diff --git a/assets/css/custom.css b/assets/css/custom.css
new file mode 100644
index 0000000..c8786d4
--- /dev/null
+++ b/assets/css/custom.css
@@ -0,0 +1,132 @@
+/* General & Typography */
+body {
+ font-family: 'Inter', sans-serif;
+ background-color: #F9FAFB;
+ color: #1F2937;
+ padding-top: 56px; /* Offset for fixed navbar */
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-family: 'Georgia', serif;
+}
+
+/* Navbar */
+.navbar {
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
+}
+
+.navbar-brand {
+ font-family: 'Georgia', serif;
+ font-weight: 700;
+ font-size: 1.5rem;
+}
+
+/* Hero Section */
+.hero {
+ position: relative;
+ padding: 8rem 0;
+ background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://picsum.photos/seed/medhero/1600/900');
+ background-size: cover;
+ background-position: center;
+ background-attachment: fixed;
+}
+
+.hero h1 {
+ font-weight: 700;
+}
+
+/* Buttons */
+.btn-primary {
+ background-color: #3B82F6;
+ border-color: #3B82F6;
+ padding: 0.75rem 1.5rem;
+ border-radius: 0.5rem;
+ transition: all 0.3s ease;
+}
+
+.btn-primary:hover {
+ background-color: #2563EB;
+ border-color: #2563EB;
+ transform: translateY(-2px);
+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);
+}
+
+/* Cards */
+.card {
+ border: none;
+ border-radius: 1rem;
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
+}
+
+.card:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 8px 20px rgba(0,0,0,0.08);
+}
+
+#checker .card {
+ border-radius: 1rem;
+}
+
+/* Forms */
+.form-control {
+ border-radius: 0.5rem;
+ padding: 0.75rem;
+}
+
+.form-control:focus {
+ box-shadow: 0 0 0 0.25rem rgba(59, 130, 246, 0.25);
+ border-color: #3B82F6;
+}
+
+/* Interaction Result */
+#interaction-result .alert {
+ border-radius: 0.5rem;
+}
+
+.alert-success {
+ background-color: #E0F2F1; /* Lighter green */
+ color: #0D6B61;
+ border-color: #B2DFDB;
+}
+
+.alert-warning {
+ background-color: #FFF3E0; /* Lighter orange */
+ color: #A65B00;
+ border-color: #FFE0B2;
+}
+
+.alert-danger {
+ background-color: #FFEBEE; /* Lighter red */
+ color: #B71C1C;
+ border-color: #FFCDD2;
+}
+
+/* Footer */
+footer a:hover {
+ text-decoration: underline;
+}
+
+/* Expiry Tracker */
+#medicine-list-container .list-group-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.expiry-date {
+ font-weight: 500;
+}
+
+.expiry-soon {
+ color: #A65B00; /* Orange from alert-warning */
+}
+
+.expired {
+ color: #B71C1C; /* Red from alert-danger */
+}
+
+#medicine-list-container .btn-sm {
+ --bs-btn-padding-y: .2rem;
+ --bs-btn-padding-x: .4rem;
+ --bs-btn-font-size: .75rem;
+}
diff --git a/assets/js/main.js b/assets/js/main.js
new file mode 100644
index 0000000..54d65c9
--- /dev/null
+++ b/assets/js/main.js
@@ -0,0 +1,250 @@
+document.addEventListener('DOMContentLoaded', function () {
+
+ // Smooth scrolling for anchor links
+ document.querySelectorAll('a[href^="#"]').forEach(anchor => {
+ anchor.addEventListener('click', function (e) {
+ e.preventDefault();
+ document.querySelector(this.getAttribute('href')).scrollIntoView({
+ behavior: 'smooth'
+ });
+ });
+ });
+
+ // Interaction Checker Logic
+ const interactionForm = document.getElementById('interaction-form');
+ const resultDiv = document.getElementById('interaction-result');
+
+ if (interactionForm) {
+ interactionForm.addEventListener('submit', function (e) {
+ e.preventDefault();
+ const drugA = document.getElementById('drugA').value.trim();
+ const drugB = document.getElementById('drugB').value.trim();
+
+ resultDiv.className = 'mt-4 d-none'; // Hide previous result
+ resultDiv.innerHTML = '
';
+ resultDiv.classList.remove('d-none');
+
+ setTimeout(() => {
+ let resultMessage = '';
+ let alertClass = 'alert-success';
+
+ if (drugA.toLowerCase() === 'warfarin' && drugB.toLowerCase() === 'aspirin' || drugA.toLowerCase() === 'aspirin' && drugB.toLowerCase() === 'warfarin') {
+ resultMessage = `High Risk Interaction: Combining ${drugA} and ${drugB} increases the risk of bleeding. Consult your doctor immediately.`;
+ alertClass = 'alert-danger';
+ } else if (drugA === '' || drugB === '') {
+ resultMessage = 'Please enter both drug names.';
+ alertClass = 'alert-warning';
+ } else {
+ resultMessage = `No Major Interaction Found: No significant interaction was found between ${drugA} and ${drugB}. This is not a substitute for professional medical advice.`;
+ }
+
+ resultDiv.innerHTML = `${resultMessage}
`;
+ }, 1500);
+ });
+ }
+
+ // Contact Form Logic
+ const contactForm = document.getElementById('contact-form');
+ const contactToastEl = document.getElementById('contact-toast');
+ const contactToast = new bootstrap.Toast(contactToastEl);
+
+ if (contactForm) {
+ contactForm.addEventListener('submit', function(e) {
+ e.preventDefault();
+ const name = document.getElementById('name').value;
+ const email = document.getElementById('email').value;
+ const message = document.getElementById('message').value;
+ const submitButton = contactForm.querySelector('button[type="submit"]');
+
+ const formData = new FormData();
+ formData.append('name', name);
+ formData.append('email', email);
+ formData.append('message', message);
+
+ submitButton.disabled = true;
+ submitButton.innerHTML = ' Sending...';
+
+ fetch('contact.php', {
+ method: 'POST',
+ body: formData
+ })
+ .then(response => response.json())
+ .then(data => {
+ const toastBody = contactToastEl.querySelector('.toast-body');
+ if (data.success) {
+ toastBody.textContent = data.message;
+ contactToastEl.classList.remove('bg-danger');
+ contactToastEl.classList.add('bg-success', 'text-white');
+ contactForm.reset();
+ } else {
+ toastBody.textContent = data.message || 'An error occurred.';
+ contactToastEl.classList.remove('bg-success');
+ contactToastEl.classList.add('bg-danger', 'text-white');
+ }
+ contactToast.show();
+ })
+ .catch(error => {
+ const toastBody = contactToastEl.querySelector('.toast-body');
+ toastBody.textContent = 'A network error occurred. Please try again.';
+ contactToastEl.classList.remove('bg-success');
+ contactToastEl.classList.add('bg-danger', 'text-white');
+ contactToast.show();
+ })
+ .finally(() => {
+ submitButton.disabled = false;
+ submitButton.innerHTML = 'Send Message';
+ });
+ });
+ }
+
+ // Expiry Alert Tracker Logic
+ const medicineForm = document.getElementById('medicine-form');
+ const medicineListContainer = document.getElementById('medicine-list-container');
+
+ // Function to calculate date difference and apply styling
+ const getExpiryStatus = (expiryDate) => {
+ const now = new Date();
+ const expiry = new Date(expiryDate);
+ // Reset time part to compare dates only
+ now.setHours(0, 0, 0, 0);
+ expiry.setHours(0, 0, 0, 0);
+
+ const diffTime = expiry - now;
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
+
+ if (diffDays < 0) {
+ return { text: `Expired on ${expiry.toLocaleDateString()}`, className: 'expired' };
+ }
+ if (diffDays <= 7) {
+ return { text: `Expires in ${diffDays} day(s)`, className: 'expiry-soon' };
+ }
+ return { text: `Expires on ${expiry.toLocaleDateString()}`, className: '' };
+ };
+
+ // Function to render medicines
+ const renderMedicines = (medicines) => {
+ if (!medicines || medicines.length === 0) {
+ medicineListContainer.innerHTML = 'No medicines being tracked yet.
';
+ return;
+ }
+
+ const list = document.createElement('ul');
+ list.className = 'list-group list-group-flush';
+
+ medicines.forEach(medicine => {
+ const status = getExpiryStatus(medicine.expiry_date);
+ const item = document.createElement('li');
+ item.className = 'list-group-item';
+ item.innerHTML = `
+
+ ${medicine.medicine_name}
+
+ ${status.text}
+
+ Remove
+ `;
+ list.appendChild(item);
+ });
+
+ medicineListContainer.innerHTML = '';
+ medicineListContainer.appendChild(list);
+ };
+
+ // Function to fetch medicines from the server
+ const fetchMedicines = () => {
+ fetch('medicines.php?action=get')
+ .then(response => response.json())
+ .then(data => {
+ if (data.success) {
+ renderMedicines(data.medicines);
+ } else {
+ console.error('Failed to fetch medicines:', data.message);
+ medicineListContainer.innerHTML = 'Could not load medicines.
';
+ }
+ })
+ .catch(error => {
+ console.error('Error fetching medicines:', error);
+ medicineListContainer.innerHTML = 'Error loading medicines.
';
+ });
+ };
+
+ // Event listener for adding a new medicine
+ if (medicineForm) {
+ medicineForm.addEventListener('submit', function (e) {
+ e.preventDefault();
+ const medicineName = document.getElementById('medicine_name').value.trim();
+ const expiryDate = document.getElementById('expiry_date').value;
+ const submitButton = medicineForm.querySelector('button[type="submit"]');
+
+ const formData = new FormData();
+ formData.append('action', 'add');
+ formData.append('medicine_name', medicineName);
+ formData.append('expiry_date', expiryDate);
+
+ submitButton.disabled = true;
+ submitButton.innerHTML = ' Adding...';
+
+ fetch('medicines.php', {
+ method: 'POST',
+ body: formData
+ })
+ .then(response => response.json())
+ .then(data => {
+ if (data.success) {
+ medicineForm.reset();
+ fetchMedicines(); // Refresh the list
+ } else {
+ alert(`Error: ${data.message}`);
+ }
+ })
+ .catch(error => {
+ alert('A network error occurred.');
+ })
+ .finally(() => {
+ submitButton.disabled = false;
+ submitButton.innerHTML = 'Add to Tracker';
+ });
+ });
+ }
+
+ // Event listener for deleting a medicine (using event delegation)
+ if (medicineListContainer) {
+ medicineListContainer.addEventListener('click', function(e) {
+ if (e.target && e.target.classList.contains('delete-medicine')) {
+ const medicineId = e.target.getAttribute('data-id');
+ if (!confirm('Are you sure you want to remove this medicine?')) {
+ return;
+ }
+
+ const formData = new FormData();
+ formData.append('action', 'delete');
+ formData.append('id', medicineId);
+
+ e.target.disabled = true;
+
+ fetch('medicines.php', {
+ method: 'POST',
+ body: formData
+ })
+ .then(response => response.json())
+ .then(data => {
+ if (data.success) {
+ fetchMedicines(); // Refresh the list
+ } else {
+ alert(`Error: ${data.message}`);
+ e.target.disabled = false;
+ }
+ })
+ .catch(error => {
+ alert('A network error occurred.');
+ e.target.disabled = false;
+ });
+ }
+ });
+ }
+
+ // Initial fetch of medicines when the page loads
+ if (medicineListContainer) {
+ fetchMedicines();
+ }
+});
diff --git a/contact.php b/contact.php
new file mode 100644
index 0000000..579300f
--- /dev/null
+++ b/contact.php
@@ -0,0 +1,60 @@
+ false, 'message' => 'Invalid request method.']);
+ exit;
+}
+
+$name = trim($_POST['name'] ?? '');
+$email = trim($_POST['email'] ?? '');
+$message = trim($_POST['message'] ?? '');
+
+if (empty($name) || empty($email) || empty($message)) {
+ echo json_encode(['success' => false, 'message' => 'Please fill out all fields.']);
+ exit;
+}
+
+if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ echo json_encode(['success' => false, 'message' => 'Please provide a valid email address.']);
+ exit;
+}
+
+try {
+ $pdo = db();
+
+ // Create table if it doesn't exist (idempotent)
+ $pdo->exec("CREATE TABLE IF NOT EXISTS contact_submissions (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ email VARCHAR(255) NOT NULL,
+ message TEXT NOT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )");
+
+ // Insert submission
+ $stmt = $pdo->prepare("INSERT INTO contact_submissions (name, email, message) VALUES (?, ?, ?)");
+ $stmt->execute([$name, $email, $message]);
+
+ // Send email notification
+ // The recipient is determined by the MAIL_TO env var by default.
+ $mailResult = MailService::sendContactMessage($name, $email, $message);
+
+ if ($mailResult['success']) {
+ echo json_encode(['success' => true, 'message' => 'Thank you! Your message has been sent.']);
+ } else {
+ // Still a success for the user, but log the mail error.
+ error_log("Contact form saved to DB, but mail sending failed: " . ($mailResult['error'] ?? 'Unknown error'));
+ echo json_encode(['success' => true, 'message' => 'Thank you! Your message has been received.']);
+ }
+
+} catch (PDOException $e) {
+ error_log("Database error: " . $e->getMessage());
+ echo json_encode(['success' => false, 'message' => 'A server error occurred while saving your message.']);
+} catch (Exception $e) {
+ error_log("General error: " . $e->getMessage());
+ echo json_encode(['success' => false, 'message' => 'A server error occurred.']);
+}
diff --git a/db/migrate.php b/db/migrate.php
new file mode 100644
index 0000000..9cff012
--- /dev/null
+++ b/db/migrate.php
@@ -0,0 +1,33 @@
+setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+ $migrationsDir = __DIR__ . '/migrations';
+ if (!is_dir($migrationsDir)) {
+ mkdir($migrationsDir, 0775, true);
+ }
+
+ $files = glob($migrationsDir . '/*.sql');
+ sort($files);
+
+ foreach ($files as $file) {
+ $sql = file_get_contents($file);
+ if (!empty(trim($sql))) {
+ $pdo->exec($sql);
+ echo "Executed migration: " . basename($file) . "
+";
+ }
+ }
+
+ echo "Migrations completed successfully.
+";
+
+} catch (PDOException $e) {
+ http_response_code(500);
+ die("Migration failed: " . $e->getMessage() . "
+");
+}
+?>
\ No newline at end of file
diff --git a/db/migrations/001_create_medicines_table.sql b/db/migrations/001_create_medicines_table.sql
new file mode 100644
index 0000000..017343a
--- /dev/null
+++ b/db/migrations/001_create_medicines_table.sql
@@ -0,0 +1,6 @@
+CREATE TABLE IF NOT EXISTS `medicines` (
+ `id` INT AUTO_INCREMENT PRIMARY KEY,
+ `medicine_name` VARCHAR(255) NOT NULL,
+ `expiry_date` DATE NOT NULL,
+ `added_on` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
\ No newline at end of file
diff --git a/index.php b/index.php
index 7205f3d..e788ab0 100644
--- a/index.php
+++ b/index.php
@@ -1,150 +1,217 @@
-
-
+
-
-
- New Style
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ MediScan - Smart Medicine Management
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
Analyzing your requirements and generating your website…
-
-
Loading…
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Drug Interaction Checker
+
+
+
+
+
+
+
+
+
+
+
+
Core Features
+
+
+
+
+
Instant Scanning
+
Use your camera to scan medicine barcodes or packaging to instantly pull up details.
+
+
+
+
+
+
+
Interaction Alerts
+
Cross-reference multiple medications to receive clear warnings about potential drug interactions.
+
+
+
+
+
+
+
Expiry Tracking
+
Never wonder about an expiry date again. Get automatic reminders for your medicines.
+
+
+
+
+
+
+
+
+
+
+
+
About MediScan
+
MediScan was born from a need for a simpler, more accessible way to manage medication safety. Our mission is to empower patients, pharmacists, and doctors with a tool that provides clear, instant, and reliable information. By bridging the gap between medical data and the user, we aim to reduce adverse drug reactions and improve overall health outcomes.
+
+
+
+
+
+
+
+
+
+
+
Expiry Alert Tracker
+
+
+
+
+
+
+
+
+
+
+
-
= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.
-
This page will update automatically as the plan is implemented.
-
Runtime: PHP = htmlspecialchars($phpVersion) ?> — UTC = htmlspecialchars($now) ?>
-
-
- Page updated: = htmlspecialchars($now) ?> (UTC)
-
+
+
+
-
+