Your Order History
+| Order ID | +Date | +Restaurant | +Total | +Status | +
|---|---|---|---|---|
| # | ++ | + | $ | ++ |
You have not placed any orders yet. Start your first order!
+ +diff --git a/add_contact.php b/add_contact.php new file mode 100644 index 0000000..5ef578a --- /dev/null +++ b/add_contact.php @@ -0,0 +1,57 @@ + false, 'message' => 'An unexpected error occurred.']; + +if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + $response['message'] = 'Invalid request method.'; + echo json_encode($response); + exit; +} + +$name = trim($_POST['name'] ?? ''); +$email = trim($_POST['email'] ?? ''); +$message = trim($_POST['message'] ?? ''); + +if (empty($name) || empty($email) || empty($message)) { + $response['message'] = 'Please fill out all fields.'; + echo json_encode($response); + exit; +} + +if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + $response['message'] = 'Invalid email format.'; + echo json_encode($response); + exit; +} + +try { + $pdo = db(); + $stmt = $pdo->prepare("INSERT INTO contact_submissions (name, email, message) VALUES (?, ?, ?)"); + $stmt->execute([$name, $email, $message]); + + // Send email notification + $mailResult = MailService::sendContactMessage($name, $email, $message); + + if ($mailResult['success']) { + $response['success'] = true; + $response['message'] = 'Message sent successfully!'; + } else { + // Still a success for the user, but log the email error + error_log("MailService Error: " . ($mailResult['error'] ?? 'Unknown error')); + $response['success'] = true; + $response['message'] = 'Message saved, but could not send notification email.'; + } + +} catch (PDOException $e) { + error_log("Database Error: " . $e->getMessage()); + $response['message'] = 'Error saving your message to the database.'; +} catch (Exception $e) { + error_log("General Error: " . $e->getMessage()); + $response['message'] = 'An unexpected error occurred.'; +} + +echo json_encode($response); \ No newline at end of file diff --git a/add_menu_item.php b/add_menu_item.php new file mode 100644 index 0000000..ce5634f --- /dev/null +++ b/add_menu_item.php @@ -0,0 +1,48 @@ +prepare("SELECT id FROM restaurants WHERE id = ? AND user_id = ?"); +$stmt->execute([$restaurant_id, $_SESSION['user_id']]); +if (!$stmt->fetch()) { + die('You do not have permission to add items to this restaurant.'); +} + +try { + $stmt_insert = $pdo->prepare( + "INSERT INTO menu_items (restaurant_id, name, description, price) VALUES (?, ?, ?, ?)" + ); + $stmt_insert->execute([$restaurant_id, $item_name, $item_description, $item_price]); + + // Redirect back to the dashboard + header("Location: dashboard.php?item_added=success"); + exit(); + +} catch (PDOException $e) { + // In a real app, you would log this error + die("Error adding menu item: " . $e->getMessage()); +} diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..e7164a5 --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,477 @@ +:root { + --primary-color: #40E0D0; /* Turquoise */ + --primary-hover-color: #36c4b5; + --secondary-color: #2E8B57; /* SeaGreen */ + --background-color: #F8F9FA; + --surface-color: #FFFFFF; + --text-color: #212529; + --text-muted-color: #6c757d; + --base-spacing: 1rem; + --border-radius: 0.5rem; + --box-shadow: 0 4px 6px rgba(0,0,0,0.1); +} + +body { + font-family: 'Poppins', sans-serif; + margin: 0; + background-color: var(--background-color); + color: var(--text-color); + line-height: 1.6; +} + +.container { + max-width: 1140px; + margin: 0 auto; + padding: 0 var(--base-spacing); +} + +.btn { + display: inline-block; + padding: 0.75rem 1.5rem; + border-radius: var(--border-radius); + text-decoration: none; + font-weight: 600; + transition: transform 0.2s, background-color 0.2s; + border: none; + cursor: pointer; +} + +.btn:hover { + transform: translateY(-2px); +} + +.btn-primary { + background-color: var(--primary-color); + color: var(--text-color); +} + +.btn-primary:hover { + background-color: var(--primary-hover-color); +} + +.navbar { + padding: var(--base-spacing) 0; + background-color: var(--surface-color); + box-shadow: var(--box-shadow); + position: sticky; + top: 0; + z-index: 1000; +} + +.navbar-inner { + display: flex; + justify-content: space-between; + align-items: center; +} + +.logo { + font-size: 1.5rem; + font-weight: 700; + color: var(--secondary-color); + text-decoration: none; +} + +.nav-links a { + margin-left: 1.5rem; + text-decoration: none; + color: var(--text-color); + font-weight: 600; +} + +.hero { + padding: 6rem 0; + text-align: center; + background: linear-gradient(45deg, var(--primary-color), var(--secondary-color)); + color: white; +} + +.hero-content h1 { + font-size: 3rem; + margin-bottom: var(--base-spacing); + font-weight: 700; +} + +.hero-content p { + font-size: 1.2rem; + margin-bottom: 2rem; +} + +.section { + padding: 4rem 0; +} + +.section-alt { + background-color: var(--surface-color); + padding: 4rem 0; +} + +h2 { + text-align: center; + font-size: 2.5rem; + margin-bottom: 3rem; + color: var(--secondary-color); + font-weight: 700; +} + +.steps { + display: flex; + justify-content: space-around; + text-align: center; + gap: 2rem; +} + +.step { + max-width: 300px; +} + +.step i { + width: 48px; + height: 48px; + color: var(--primary-color); + margin-bottom: 1rem; +} + +.step h3 { + font-size: 1.5rem; + margin-bottom: 0.5rem; +} + +.contact-content { + max-width: 600px; + margin: 0 auto; + text-align: center; +} + +.contact-form { + margin-top: 2rem; + display: flex; + flex-direction: column; + gap: 1rem; +} + +.form-group input, .form-group textarea { + width: 100%; + padding: 0.75rem; + border: 1px solid #ccc; + border-radius: var(--border-radius); + font-family: 'Poppins', sans-serif; + box-sizing: border-box; +} + +footer { + padding: 2rem 0; + text-align: center; + background-color: var(--surface-color); + margin-top: 4rem; +} + +.form-message { + margin-top: 1rem; + padding: 1rem; + border-radius: var(--border-radius); + display: none; +} + +.form-message.success { + background-color: #d4edda; + color: #155724; + display: block; +} + +.form-message.error { + background-color: #f8d7da; + color: #721c24; + display: block; +} + +.page-title { + font-size: 2.5rem; + font-weight: 700; + color: var(--secondary-color); + text-align: center; + margin-bottom: 3rem; +} + +.restaurants-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 2rem; +} + +.restaurant-card { + background-color: var(--surface-color); + border-radius: var(--border-radius); + box-shadow: var(--box-shadow); + overflow: hidden; + transition: transform 0.3s ease, box-shadow 0.3s ease; + text-decoration: none; + color: inherit; + display: flex; + flex-direction: column; +} + +.restaurant-card:hover { + transform: translateY(-5px); + box-shadow: 0 8px 12px rgba(0,0,0,0.15); +} + +.restaurant-card-image { + width: 100%; + height: 200px; + background-size: cover; + background-position: center; +} + +.restaurant-card-content { + padding: 1.5rem; + flex-grow: 1; +} + +.restaurant-card-content h3 { + margin-top: 0; + font-size: 1.5rem; + font-weight: 600; + color: var(--secondary-color); +} + +.restaurant-card-content p { + color: var(--text-muted-color); + line-height: 1.6; +} + +.menu-header { + padding: 4rem 0; + background-size: cover; + background-position: center; + color: white; + text-align: center; +} + +.menu-header h1 { + font-size: 3rem; + font-weight: 700; + margin: 0; +} + +.menu-header p { + font-size: 1.2rem; + max-width: 600px; + margin: 0.5rem auto 0; +} + +.section-title { + font-size: 2rem; + font-weight: 700; + color: var(--secondary-color); + text-align: center; + margin-bottom: 2rem; +} + +.menu-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 2rem; +} + +.menu-item-card { + background-color: var(--surface-color); + border-radius: var(--border-radius); + box-shadow: var(--box-shadow); + overflow: hidden; + display: flex; + flex-direction: column; +} + +.menu-item-image { + width: 100%; + height: 180px; + background-size: cover; + background-position: center; +} + +.menu-item-content { + padding: 1.5rem; + flex-grow: 1; + display: flex; + flex-direction: column; +} + +.menu-item-content h3 { + margin-top: 0; + font-size: 1.3rem; + font-weight: 600; + color: var(--secondary-color); +} + +.menu-item-content p { + color: var(--text-muted-color); + line-height: 1.6; + flex-grow: 1; + margin-bottom: 1rem; +} + +.menu-item-footer { + display: flex; + justify-content: space-between; + align-items: center; +} + +.menu-item-price { + font-size: 1.2rem; + font-weight: 700; + color: var(--primary-color); +} + +.cart-icon { + position: relative; +} + +#cart-count { + position: absolute; + top: -8px; + right: -8px; + background-color: #E04050; + color: white; + border-radius: 50%; + padding: 2px 6px; + font-size: 0.75rem; + font-weight: 700; + display: none; /* Hidden by default */ +} + +.dashboard-content { + background-color: var(--surface-color); + padding: 2rem; + border-radius: var(--border-radius); + box-shadow: var(--box-shadow); +} + +.table { + width: 100%; + border-collapse: collapse; +} + +.table th, .table td { + padding: 1rem; + text-align: left; + border-bottom: 1px solid #eee; +} + +.table th { + background-color: #f7f7f7; + font-weight: 600; +} + +.status { + padding: 0.25rem 0.5rem; + border-radius: 0.25rem; + font-weight: 600; + font-size: 0.9rem; +} + +.status-pending { + background-color: #fff3cd; + color: #856404; +} + +.status-confirmed { + background-color: #d4edda; + color: #155724; +} + +.status-delivered { + background-color: #d1ecf1; + color: #0c5460; +} + +.status-cancelled { + background-color: #f8d7da; + color: #721c24; +} + +.dashboard-header { + text-align: center; + margin-bottom: 2rem; +} + +.tabs { + display: flex; + justify-content: center; + margin-bottom: 2rem; +} + +.tab-link { + padding: 0.75rem 1.5rem; + border: none; + background-color: transparent; + cursor: pointer; + font-size: 1.1rem; + font-weight: 600; + color: var(--text-muted-color); + border-bottom: 2px solid transparent; + transition: color 0.2s, border-bottom-color 0.2s; +} + +.tab-link.active, .tab-link:hover { + color: var(--secondary-color); + border-bottom-color: var(--secondary-color); +} + +.tab-content { + display: none; +} + +.tab-content.active { + display: block; +} + +.order-list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); + gap: 1.5rem; +} + +.order-card { + background-color: var(--surface-color); + border-radius: var(--border-radius); + box-shadow: var(--box-shadow); + display: flex; + flex-direction: column; +} + +.order-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 1.5rem; + border-bottom: 1px solid #eee; +} + +.order-id { + font-weight: 700; + font-size: 1.1rem; +} + +.order-body { + padding: 1rem 1.5rem; + flex-grow: 1; +} + +.order-footer { + padding: 1rem 1.5rem; + background-color: #f7f7f7; + border-top: 1px solid #eee; +} + +.order-footer form { + display: flex; + justify-content: space-between; + align-items: center; +} + +.form-card { + background-color: var(--surface-color); + padding: 2rem; + border-radius: var(--border-radius); + box-shadow: var(--box-shadow); +} \ No newline at end of file diff --git a/assets/images/placeholder.jpg b/assets/images/placeholder.jpg new file mode 100644 index 0000000..e69de29 diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..585c7fd --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,100 @@ +document.addEventListener('DOMContentLoaded', function() { + const contactForm = document.getElementById('contactForm'); + const formMessage = document.getElementById('form-message'); + + if (contactForm) { + contactForm.addEventListener('submit', function(event) { + event.preventDefault(); + + const name = document.getElementById('name').value.trim(); + const email = document.getElementById('email').value.trim(); + const message = document.getElementById('message').value.trim(); + + if (!name || !email || !message) { + showMessage('Please fill out all fields.', 'error'); + return; + } + + if (!validateEmail(email)) { + showMessage('Please enter a valid email address.', 'error'); + return; + } + + const formData = new FormData(contactForm); + + fetch('add_contact.php', { + method: 'POST', + body: formData + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + showMessage('Thank you for your message! We will get back to you soon.', 'success'); + contactForm.reset(); + } else { + showMessage(data.message || 'An error occurred. Please try again.', 'error'); + } + }) + .catch(error => { + console.error('Error:', error); + showMessage('An error occurred. Please try again.', 'error'); + }); + }); + } + + function showMessage(message, type) { + formMessage.textContent = message; + formMessage.className = type; + } + + function validateEmail(email) { + const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(String(email).toLowerCase()); + } +}); + +// --- Shopping Cart --- +const shoppingCart = { + getCart: () => { + const cart = localStorage.getItem('shoppingCart'); + return cart ? JSON.parse(cart) : { items: [], restaurantId: null }; + }, + saveCart: (cart) => { + localStorage.setItem('shoppingCart', JSON.stringify(cart)); + }, + addItem: (item, restaurantId) => { + const cart = shoppingCart.getCart(); + if (cart.restaurantId && cart.restaurantId !== restaurantId) { + // If the item is from a different restaurant, ask for confirmation to clear the cart + if (!confirm('You have items from another restaurant in your cart. Do you want to clear your cart and add this item?')) { + return; + } + // Clear the cart + cart.items = []; + } + + cart.restaurantId = restaurantId; + const existingItem = cart.items.find(i => i.id === item.id); + + if (existingItem) { + existingItem.quantity++; + } else { + cart.items.push({ ...item, quantity: 1 }); + } + shoppingCart.saveCart(cart); + shoppingCart.updateCartCount(); + alert(`${item.name} has been added to your cart.`); + }, + updateCartCount: () => { + const cart = shoppingCart.getCart(); + const cartCount = cart.items.reduce((total, item) => total + item.quantity, 0); + const cartCountElement = document.getElementById('cart-count'); + if (cartCountElement) { + cartCountElement.textContent = cartCount; + } + } +}; + +document.addEventListener('DOMContentLoaded', () => { + shoppingCart.updateCartCount(); +}); diff --git a/cart.php b/cart.php new file mode 100644 index 0000000..1eb1000 --- /dev/null +++ b/cart.php @@ -0,0 +1,218 @@ + + +
+ + +| Order ID | +Date | +Restaurant | +Total | +Status | +
|---|---|---|---|---|
| # | ++ | + | $ | ++ |
You have not placed any orders yet. Start your first order!
+ +Already have an account? Log In
+Customer:
+Items:
You have no recent orders.
+ +You do not have a restaurant associated with your account.
+ += ($_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) ?>
Fresh, fast, and reliable. The best local restaurants at your fingertips.
+ Browse Restaurants +Browse menus from the best local restaurants.
+Select your favorite dishes and place your order in seconds.
+Get your food delivered hot and fresh to your doorstep.
+Have a question or feedback? Get in touch with us!
+ + +