diff --git a/assets/css/main.css b/assets/css/main.css new file mode 100644 index 00000000..53101402 --- /dev/null +++ b/assets/css/main.css @@ -0,0 +1,765 @@ +/* Global Styles & Variables */ +:root { + --turquoise: #40E0D0; + --green: #228B22; + --coral: #FF6B6B; + --white: #FFFFFF; + --off-white: #f8f9fa; + --text-color: #333; + --light-gray: #f2f2f2; + --medium-gray: #ccc; + --dark-gray: #555; + + --font-heading: 'Inter', sans-serif; + --font-body: 'Open Sans', sans-serif; + + --shadow-soft: 0 4px 12px rgba(0, 0, 0, 0.08); + --border-radius: 16px; +} + +body { + font-family: var(--font-body); + color: var(--text-color); + background-color: var(--white); /* Changed to white for a cleaner base */ + margin: 0; + padding: 0; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +h1, h2, h3, h4, h5, h6 { + font-family: var(--font-heading); + font-weight: 600; + letter-spacing: 0.5px; /* Reduced for better readability */ +} + +a { + text-decoration: none; + color: var(--coral); + transition: color 0.3s ease; +} + +a:hover { + color: var(--turquoise); +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; +} + +/* Header styles */ +header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 15px 30px; + background-color: var(--white); + border-bottom: 1px solid var(--light-gray); + position: sticky; + top: 0; + z-index: 100; +} + +.logo { + font-family: var(--font-heading); + font-size: 28px; + font-weight: 700; + color: var(--text-color); +} + +.address-container { + cursor: pointer; + padding: 8px 12px; + border-radius: 20px; + background-color: var(--off-white); + transition: background-color 0.3s ease; +} + +.address-container:hover { + background-color: var(--light-gray); +} + +.address-display { + font-size: 14px; + font-weight: 500; +} + +.user-actions { + display: flex; + align-items: center; +} + +.user-actions a { + margin-left: 20px; + font-weight: 600; + font-size: 15px; +} + +/* Modal styles */ +.modal { + display: none; + position: fixed; + z-index: 1000; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(0,0,0,0.5); + backdrop-filter: blur(5px); +} +.modal-content { + background-color: var(--white); + margin: 15% auto; + padding: 30px; + border: none; + width: 90%; + max-width: 500px; + border-radius: var(--border-radius); + box-shadow: 0 10px 30px rgba(0,0,0,0.1); + text-align: center; + position: relative; +} +.close-button { + color: var(--medium-gray); + position: absolute; + top: 15px; + right: 20px; + font-size: 32px; + font-weight: bold; + transition: color 0.3s ease; +} +.close-button:hover, +.close-button:focus { + color: var(--dark-gray); + text-decoration: none; + cursor: pointer; +} +#modal-address-input { + width: calc(100% - 40px); + padding: 12px; + margin-top: 10px; + margin-bottom: 20px; + border: 1px solid var(--light-gray); + border-radius: 8px; + font-size: 16px; +} +#save-address-button { + background-color: var(--coral); + color: white; + padding: 12px 25px; + border: none; + border-radius: 8px; + cursor: pointer; + font-size: 16px; + font-weight: 600; + transition: background-color 0.3s ease; +} +#save-address-button:hover { + background-color: #ff4f4f; +} + + +/* Animations */ +@keyframes fadeIn { + from { opacity: 0; transform: translateY(-10px); } + to { opacity: 1; transform: translateY(0); } +} + +.fade-in { + animation: fadeIn 0.5s ease-in-out forwards; +} + +/* Hero Section */ +.hero { + position: relative; + height: 400px; + background-image: url('../pasted-20251014-230507-170c4564.jpg'); + background-size: cover; + background-position: center; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + color: var(--white); + margin-bottom: 40px; +} + +.hero::after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.4); +} + +.hero-content { + position: relative; + z-index: 1; + max-width: 600px; +} + +.hero h1 { + font-size: 3rem; + font-weight: 700; + margin-bottom: 1rem; + text-shadow: 0 2px 4px rgba(0,0,0,0.5); +} + +.search-bar { + width: 100%; + padding: 1rem; + font-size: 1rem; + border-radius: 50px; + border: none; + box-shadow: var(--shadow-soft); + padding-left: 3rem; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23767676' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-search'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: 1rem center; +} + +/* Restaurant Grid */ +.page-title { + font-size: 2rem; + font-weight: 700; + margin-bottom: 1.5rem; +} + +.restaurant-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + gap: 2rem; +} + +.restaurant-card { + background-color: var(--white); + border-radius: var(--border-radius); + box-shadow: var(--shadow-soft); + overflow: hidden; + transition: all 0.3s ease-in-out; + display: flex; + flex-direction: column; + text-decoration: none; + color: inherit; +} + +.restaurant-card:hover { + transform: translateY(-5px); + box-shadow: 0 8px 20px rgba(0,0,0,0.12); +} + +.restaurant-card img { + width: 100%; + height: 200px; + object-fit: cover; +} + +.restaurant-card-content { + padding: 1.5rem; + display: flex; + flex-direction: column; + flex-grow: 1; +} + +.restaurant-card-content h3 { + font-size: 1.25rem; + font-weight: 700; + margin-bottom: 0.5rem; +} + +.restaurant-card-content p { + color: var(--dark-gray); + font-size: 0.95rem; + margin-bottom: 0.5rem; +} + +.rating-display { + display: flex; + align-items: center; + font-size: 1rem; + font-weight: 600; + color: var(--text-color); +} + +.rating-display .star { + color: #FFC107; + margin-right: 0.25rem; +} + +.rating-display .rating-count { + font-size: 0.9rem; + color: var(--dark-gray); + margin-left: 0.5rem; + font-weight: 400; +} + +footer { + text-align: center; + padding: 3rem 0; + margin-top: 3rem; + background-color: var(--off-white); + border-top: 1px solid var(--light-gray); +} + +/* Restaurant Menu Page */ +.restaurant-hero-menu { + position: relative; + height: 300px; + background-size: cover; + background-position: center; + display: flex; + flex-direction: column; + justify-content: flex-end; + padding: 2rem; + color: var(--white); + border-radius: var(--border-radius); + overflow: hidden; + margin-bottom: 2rem; +} + +.restaurant-hero-menu::after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(to top, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0) 100%); +} + +.restaurant-hero-menu-content { + position: relative; + z-index: 1; +} + +.restaurant-hero-menu h1 { + font-size: 2.5rem; + font-weight: 700; + margin: 0 0 0.5rem; + text-shadow: 0 2px 4px rgba(0,0,0,0.6); +} + +.restaurant-hero-menu p { + font-size: 1rem; + margin: 0.25rem 0; + text-shadow: 0 1px 3px rgba(0,0,0,0.5); +} + +/* Menu Grid */ +.menu-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 2rem; +} + +.menu-item-card { + background-color: var(--white); + border-radius: var(--border-radius); + box-shadow: var(--shadow-soft); + overflow: hidden; + transition: all 0.3s ease-in-out; + display: flex; + flex-direction: column; +} + +.menu-item-card:hover { + transform: translateY(-5px); + box-shadow: 0 8px 20px rgba(0,0,0,0.12); +} + +.menu-item-card img { + width: 100%; + height: 180px; + object-fit: cover; +} + +.menu-item-card-content { + padding: 1.5rem; + display: flex; + flex-direction: column; + flex-grow: 1; +} + +.menu-item-card-content h3 { + font-size: 1.15rem; + font-weight: 700; + margin: 0 0 0.5rem; +} + +.menu-item-card-content .description { + font-size: 0.9rem; + color: var(--dark-gray); + margin-bottom: 1rem; + flex-grow: 1; +} + +.menu-item-card-content .price { + font-size: 1.1rem; + font-weight: 700; + color: var(--text-color); + align-self: flex-end; +} + +/* Rating Section on Menu Page */ +.rating-form-container { + background-color: var(--white); + padding: 2rem; + border-radius: var(--border-radius); + box-shadow: var(--shadow-soft); + margin-top: 2rem; +} + +.rating-form-container h2 { + margin-top: 0; +} + +.rate-form .stars { + font-size: 2rem; + color: var(--medium-gray); + cursor: pointer; + direction: rtl; + display: inline-block; +} + +.rate-form .stars > label { + color: var(--medium-gray); + transition: color 0.2s; +} + +.rate-form .stars > input { + display: none; +} + +.rate-form .stars > input:checked ~ label, +.rate-form .stars:not(:hover) > input:checked ~ label { + color: #FFC107 !important; +} + +.rate-form .stars > label:hover, +.rate-form .stars > label:hover ~ label { + color: #FFC107 !important; +} + +.rate-form button { + background-color: var(--coral); + color: white; + border: none; + padding: 10px 20px; + border-radius: 8px; + cursor: pointer; + font-size: 1rem; + font-weight: 600; + margin-top: 1rem; + transition: background-color 0.3s ease; +} + +.rate-form button:hover { + background-color: #ff4f4f; +} + +/* Auth Forms */ +.auth-container { + max-width: 450px; + margin: 4rem auto; + padding: 3rem; + background-color: var(--white); + border-radius: var(--border-radius); + box-shadow: var(--shadow-soft); +} + +.auth-container h1 { + text-align: center; + margin-bottom: 2rem; + font-size: 2rem; +} + +.form-group { + margin-bottom: 1.5rem; +} + +.form-group label { + display: block; + margin-bottom: 0.5rem; + font-weight: 600; + color: var(--dark-gray); +} + +.form-group input { + width: 100%; + padding: 0.8rem 1rem; + border: 1px solid var(--medium-gray); + border-radius: 8px; + box-sizing: border-box; + font-size: 1rem; + transition: border-color 0.3s; +} + +.form-group input:focus { + outline: none; + border-color: var(--coral); +} + +.btn-submit { + width: 100%; + padding: 0.9rem; + border: none; + border-radius: 8px; + background-color: var(--coral); + color: white; + font-size: 1.1rem; + font-weight: 600; + cursor: pointer; + transition: background-color 0.3s; +} + +.btn-submit:hover { + background-color: #ff4f4f; +} + +.form-footer { + text-align: center; + margin-top: 1.5rem; +} + +.form-footer a { + color: var(--coral); + font-weight: 600; + text-decoration: none; +} + +.form-footer a:hover { + text-decoration: underline; +} + +/* Add to Cart Form */ +.add-to-cart-form { + margin-top: 1rem; +} + +.add-to-cart-form .form-row { + display: flex; + align-items: center; +} + +.quantity-input { + width: 60px; + padding: 0.5rem; + text-align: center; + border: 1px solid var(--medium-gray); + border-radius: 8px; + font-size: 1rem; + margin-right: 0.5rem; +} + +.add-to-cart-btn { + flex-grow: 1; + background-color: var(--coral); + color: white; + border: none; + padding: 0.6rem 1rem; + border-radius: 8px; + cursor: pointer; + font-size: 0.9rem; + font-weight: 600; + text-transform: uppercase; + transition: background-color 0.3s; +} + +.add-to-cart-btn:hover { + background-color: #ff4f4f; +} + +/* Cart Icon */ +.cart-icon { + position: relative; + display: inline-block; + margin-right: 20px; + color: var(--text-color); +} + +.cart-item-count { + position: absolute; + top: -8px; + right: -8px; + background-color: var(--coral); + color: white; + border-radius: 50%; + padding: 2px 6px; + font-size: 12px; + font-weight: bold; +} + +/* Cart Page */ +.cart-table { + width: 100%; + border-collapse: collapse; + margin: 2rem 0; + box-shadow: var(--shadow-soft); + border-radius: var(--border-radius); + overflow: hidden; +} + +.cart-table thead { + background-color: var(--off-white); +} + +.cart-table th, .cart-table td { + padding: 1rem 1.5rem; + text-align: left; +} + +.cart-table th { + font-weight: 600; + font-size: 0.9rem; + text-transform: uppercase; + color: var(--dark-gray); +} + +.cart-table tbody tr { + border-bottom: 1px solid var(--light-gray); +} + +.cart-table tbody tr:last-child { + border-bottom: none; +} + +.cart-table .update-form { + display: flex; + align-items: center; +} + +.cart-table .quantity-input { + width: 50px; + margin-right: 0.5rem; +} + +.cart-table .update-btn { + background-color: var(--turquoise); + color: white; + border: none; + padding: 0.4rem 0.8rem; + border-radius: 6px; + cursor: pointer; + font-size: 0.8rem; + font-weight: 600; + transition: background-color 0.3s; +} + +.cart-table .update-btn:hover { + background-color: #38d8c9; +} + +.cart-table .remove-link { + color: var(--coral); + font-weight: 600; + font-size: 0.9rem; +} + +.cart-total { + text-align: right; + margin-top: 1.5rem; + font-size: 1.25rem; + font-weight: 700; +} + +.cart-actions { + display: flex; + justify-content: flex-end; + align-items: center; + margin-top: 2rem; + gap: 1rem; +} + +.clear-cart-btn, .checkout-btn { + padding: 0.8rem 1.5rem; + border-radius: 8px; + font-weight: 600; + text-transform: uppercase; + font-size: 0.9rem; + transition: all 0.3s; +} + +.clear-cart-btn { + background-color: transparent; + border: 2px solid var(--medium-gray); + color: var(--dark-gray); +} + +.clear-cart-btn:hover { + background-color: var(--light-gray); + border-color: var(--dark-gray); +} + +.checkout-btn { + background-color: var(--coral); + color: white; + border: 2px solid var(--coral); +} + +.checkout-btn:hover { + background-color: #ff4f4f; + border-color: #ff4f4f; +} + +/* Checkout Page */ +.checkout-summary { + max-width: 700px; + margin: 2rem auto; + padding: 2rem; + background-color: var(--white); + border-radius: var(--border-radius); + box-shadow: var(--shadow-soft); +} + +.checkout-summary h2 { + text-align: center; + margin-bottom: 2rem; +} + +.checkout-form { + text-align: center; + margin-top: 2rem; +} + +/* Order Confirmation Page */ +.order-confirmation { + max-width: 600px; + margin: 4rem auto; + padding: 3rem; + text-align: center; + background-color: var(--white); + border-radius: var(--border-radius); + box-shadow: var(--shadow-soft); +} + +.order-confirmation h1 { + color: var(--green); + font-size: 2.5rem; + margin-bottom: 1rem; +} + +.order-confirmation p { + font-size: 1.1rem; + color: var(--dark-gray); + margin-bottom: 2rem; +} + +.order-confirmation .btn { + background-color: var(--coral); + color: white; + padding: 0.8rem 2rem; + border-radius: 8px; + font-weight: 600; + text-transform: uppercase; + font-size: 1rem; + transition: background-color 0.3s; +} + +.order-confirmation .btn:hover { + background-color: #ff4f4f; +} diff --git a/assets/images/hero.jpg b/assets/images/hero.jpg new file mode 100644 index 00000000..5af26485 Binary files /dev/null and b/assets/images/hero.jpg differ diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 00000000..3a2ca222 --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,98 @@ +document.addEventListener('DOMContentLoaded', function() { + const addressDisplay = document.getElementById('address-display'); + const addressContainer = document.querySelector('.address-container'); + const modal = document.getElementById('address-modal'); + const closeButton = document.querySelector('.close-button'); + const saveAddressButton = document.getElementById('save-address-button'); + const modalAddressInput = document.getElementById('modal-address-input'); + + // Load and display saved address + const savedAddress = localStorage.getItem('deliveryAddress'); + if (savedAddress) { + addressDisplay.textContent = savedAddress; + } else { + addressDisplay.textContent = 'Enter delivery address'; + } + + // Open modal + if (addressContainer) { + addressContainer.addEventListener('click', function() { + if (modal) { + modal.style.display = 'block'; + modalAddressInput.value = localStorage.getItem('deliveryAddress') || ''; + } + }); + } + + // Close modal + if(closeButton) { + closeButton.addEventListener('click', function() { + if (modal) modal.style.display = 'none'; + }); + } + + + window.addEventListener('click', function(event) { + if (event.target == modal) { + modal.style.display = 'none'; + } + }); + + // Save address + if(saveAddressButton) { + saveAddressButton.addEventListener('click', function() { + const newAddress = modalAddressInput.value.trim(); + if (newAddress) { + localStorage.setItem('deliveryAddress', newAddress); + addressDisplay.textContent = newAddress; + modal.style.display = 'none'; + } else { + alert('Please enter an address.'); + } + }); + } + + // Search functionality for index.php + const searchInput = document.getElementById('search-input'); + if (searchInput) { + const restaurantGrid = document.getElementById('restaurant-grid'); + const restaurantCards = restaurantGrid.querySelectorAll('a.restaurant-card'); + + searchInput.addEventListener('keyup', function () { + const searchTerm = searchInput.value.toLowerCase(); + + restaurantCards.forEach(card => { + const name = card.dataset.name || ''; + const cuisine = card.dataset.cuisine || ''; + + if (name.includes(searchTerm) || cuisine.includes(searchTerm)) { + card.style.display = 'flex'; + } else { + card.style.display = 'none'; + } + }); + }); + } + + // Search functionality for menu.php + const menuSearchInput = document.getElementById('menu-search-input'); + if (menuSearchInput) { + const menuGrid = document.getElementById('menu-grid'); + const menuItems = menuGrid.querySelectorAll('.menu-item-card'); + + menuSearchInput.addEventListener('keyup', function () { + const searchTerm = menuSearchInput.value.toLowerCase(); + + menuItems.forEach(card => { + const name = card.dataset.name || ''; + const description = card.dataset.description || ''; + + if (name.includes(searchTerm) || description.includes(searchTerm)) { + card.style.display = 'flex'; + } else { + card.style.display = 'none'; + } + }); + }); + } +}); \ No newline at end of file diff --git a/assets/pasted-20251014-230144-ecd85886.webp b/assets/pasted-20251014-230144-ecd85886.webp new file mode 100644 index 00000000..4b855002 Binary files /dev/null and b/assets/pasted-20251014-230144-ecd85886.webp differ diff --git a/assets/pasted-20251014-230507-170c4564.jpg b/assets/pasted-20251014-230507-170c4564.jpg new file mode 100644 index 00000000..ec25caae Binary files /dev/null and b/assets/pasted-20251014-230507-170c4564.jpg differ diff --git a/cart.php b/cart.php new file mode 100644 index 00000000..85f951db --- /dev/null +++ b/cart.php @@ -0,0 +1,80 @@ +prepare("SELECT * FROM menu_items WHERE id IN ($placeholders)"); + $stmt->execute($menu_item_ids); + $db_items = $stmt->fetchAll(PDO::FETCH_ASSOC); + + foreach ($db_items as $item) { + $quantity = $_SESSION['cart'][$item['id']]; + $item_total = $item['price'] * $quantity; + $total_price += $item_total; + $cart_items[] = [ + 'id' => $item['id'], + 'name' => $item['name'], + 'price' => $item['price'], + 'quantity' => $quantity, + 'total' => $item_total + ]; + } +} +?> + +
+
+

Your Cart

+ +

Your cart is empty.

+ + + + + + + + + + + + + + + + + + + + + + +
ItemPriceQuantityTotalAction
$ +
+ + + + +
+
$ + Remove +
+
+

Total: $

+
+ + +
+
+ + \ No newline at end of file diff --git a/cart_actions.php b/cart_actions.php new file mode 100644 index 00000000..ddc12c1a --- /dev/null +++ b/cart_actions.php @@ -0,0 +1,56 @@ + 0) { + // If cart is not empty and new item is from a different restaurant, clear the cart + if (!empty($_SESSION['cart']) && $_SESSION['cart_restaurant'] != $restaurant_id) { + $_SESSION['cart'] = []; + } + + $_SESSION['cart_restaurant'] = $restaurant_id; + + // Add or update item in cart + if (isset($_SESSION['cart'][$menu_item_id])) { + $_SESSION['cart'][$menu_item_id] += $quantity; + } else { + $_SESSION['cart'][$menu_item_id] = $quantity; + } + } + header('Location: menu.php?id=' . $restaurant_id); + exit; + + case 'update': + if ($menu_item_id && $quantity > 0) { + $_SESSION['cart'][$menu_item_id] = $quantity; + } + header('Location: cart.php'); + exit; + + case 'remove': + if ($menu_item_id) { + unset($_SESSION['cart'][$menu_item_id]); + } + header('Location: cart.php'); + exit; + + case 'clear': + $_SESSION['cart'] = []; + $_SESSION['cart_restaurant'] = null; + header('Location: cart.php'); + exit; +} \ No newline at end of file diff --git a/checkout.php b/checkout.php new file mode 100644 index 00000000..07c3602b --- /dev/null +++ b/checkout.php @@ -0,0 +1,100 @@ +prepare("SELECT * FROM menu_items WHERE id IN ($placeholders)"); +$stmt->execute($menu_item_ids); +$db_items = $stmt->fetchAll(PDO::FETCH_ASSOC); + +foreach ($db_items as $item) { + $quantity = $_SESSION['cart'][$item['id']]; + $item_total = $item['price'] * $quantity; + $total_price += $item_total; + $cart_items[] = [ + 'id' => $item['id'], + 'name' => $item['name'], + 'price' => $item['price'], + 'quantity' => $quantity, + 'total' => $item_total + ]; +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $user_id = $_SESSION['user_id']; + + // Insert into orders table + $stmt = db()->prepare("INSERT INTO orders (user_id, restaurant_id, total_price, status) VALUES (?, ?, ?, ?)"); + $stmt->execute([$user_id, $restaurant_id, $total_price, 'pending']); + $order_id = db()->lastInsertId(); + + // Insert into order_items table + $stmt = db()->prepare("INSERT INTO order_items (order_id, menu_item_id, quantity, price) VALUES (?, ?, ?, ?)"); + foreach ($cart_items as $item) { + $stmt->execute([$order_id, $item['id'], $item['quantity'], $item['price']]); + } + + // Clear the cart + $_SESSION['cart'] = []; + $_SESSION['cart_restaurant'] = null; + + // Redirect to a confirmation page + header('Location: order_confirmation.php?id=' . $order_id); + exit; +} + +include 'header.php'; +?> + +
+
+

Checkout

+
+

Order Summary

+ + + + + + + + + + + + + + + + + +
ItemQuantityTotal
$
+
+

Total: $

+
+
+ +
+
+
+
+ + diff --git a/footer.php b/footer.php new file mode 100644 index 00000000..7fb4b2d7 --- /dev/null +++ b/footer.php @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/header.php b/header.php new file mode 100644 index 00000000..a83297d4 --- /dev/null +++ b/header.php @@ -0,0 +1,50 @@ + + + + + + + Majuro Eats + + + + + + + +
+ +
+ Enter delivery address +
+
+ + + + + + + Welcome, + Logout + + Login + Sign Up + +
+
+ + + + + diff --git a/includes/pexels.php b/includes/pexels.php new file mode 100644 index 00000000..0c04a85f --- /dev/null +++ b/includes/pexels.php @@ -0,0 +1,25 @@ + 0 ? $k : 'Vc99rnmOhHhJAbgGQoKLZtsaIVfkeownoQNbTj78VemUjKh08ZYRbf18'; +} +function pexels_get($url) { + $ch = curl_init(); + curl_setopt_array($ch, [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ 'Authorization: '. pexels_key() ], + CURLOPT_TIMEOUT => 15, + ]); + $resp = curl_exec($ch); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($code >= 200 && $code < 300 && $resp) return json_decode($resp, true); + return null; +} +function download_to($srcUrl, $destPath) { + $data = file_get_contents($srcUrl); + if ($data === false) return false; + if (!is_dir(dirname($destPath))) mkdir(dirname($destPath), 0775, true); + return file_put_contents($destPath, $data) !== false; +} diff --git a/index.php b/index.php index d1b5f0cc..70e26670 100644 --- a/index.php +++ b/index.php @@ -1,232 +1,15 @@ - - - - - - MajuroEats - Order Food Online - - - - - - - - -
-
- -
- -
-
- - -
+
+
+
+

Order from Majuro's best

+
-
+ -
-
- -
- -

Featured Restaurants

+
+

All Restaurants

@@ -234,62 +17,39 @@ require_once 'db/config.php'; try { $pdo = db(); - $stmt = $pdo->query("SELECT name, cuisine, image_url, address, phone, opening_hours FROM restaurants ORDER BY name"); + $stmt = $pdo->query("SELECT id, name, cuisine, image_url, rating, rating_count FROM restaurants ORDER BY name"); $restaurants = $stmt->fetchAll(); foreach ($restaurants as $restaurant) { - echo ''; + echo ''; } } catch (PDOException $e) { echo '

Error: Could not fetch restaurants from the database.

'; - // Optionally log the error: error_log($e->getMessage()); } ?>
-
+ + - - - + - + \ No newline at end of file diff --git a/login.php b/login.php new file mode 100644 index 00000000..45b37352 --- /dev/null +++ b/login.php @@ -0,0 +1,23 @@ + + +
+
+

Login

+
+
+ + +
+
+ + +
+ +
+ +
+
+ + diff --git a/login_process.php b/login_process.php new file mode 100644 index 00000000..c3874f8c --- /dev/null +++ b/login_process.php @@ -0,0 +1,37 @@ +prepare($sql); + $stmt->execute([$email]); + $user = $stmt->fetch(); + + if ($user && password_verify($password, $user['password'])) { + $_SESSION['user_id'] = $user['id']; + $_SESSION['user_name'] = $user['name']; + header("Location: index.php"); + exit; + } else { + die('Invalid email or password.'); + } + } catch (PDOException $e) { + die("Could not connect to the database $dbname :" . $e->getMessage()); + } +} +?> \ No newline at end of file diff --git a/logout.php b/logout.php new file mode 100644 index 00000000..3a0a0430 --- /dev/null +++ b/logout.php @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/menu.php b/menu.php new file mode 100644 index 00000000..25c67b07 --- /dev/null +++ b/menu.php @@ -0,0 +1,85 @@ +prepare("SELECT * FROM restaurants WHERE id = ?"); + $stmt->execute([$restaurant_id]); + $restaurant = $stmt->fetch(PDO::FETCH_ASSOC); +} + +if ($restaurant) { + $stmt = db()->prepare("SELECT * FROM menu_items WHERE restaurant_id = ?"); + $stmt->execute([$restaurant_id]); + $menu_items = $stmt->fetchAll(PDO::FETCH_ASSOC); +} + +include 'header.php'; +?> + +
+
+ +
+
+

+

+
+ + + ( ratings) +
+
+
+ + + + + +
+

Rate your experience

+
+ +
+ + + + + +
+ +
+
+ + +

Restaurant not found.

+ +
+
+ + \ No newline at end of file diff --git a/migrations/20251014_create_orders_tables.sql b/migrations/20251014_create_orders_tables.sql new file mode 100644 index 00000000..969b6da0 --- /dev/null +++ b/migrations/20251014_create_orders_tables.sql @@ -0,0 +1,18 @@ +CREATE TABLE IF NOT EXISTS `orders` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `user_id` INT NOT NULL, + `restaurant_id` INT NOT NULL, + `total_price` DECIMAL(10, 2) NOT NULL, + `status` VARCHAR(50) NOT NULL DEFAULT 'pending', + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) +); + +CREATE TABLE IF NOT EXISTS `order_items` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `order_id` INT NOT NULL, + `menu_item_id` INT NOT NULL, + `quantity` INT NOT NULL, + `price` DECIMAL(10, 2) NOT NULL, + FOREIGN KEY (`order_id`) REFERENCES `orders`(`id`) +); diff --git a/order_confirmation.php b/order_confirmation.php new file mode 100644 index 00000000..c1f9bd74 --- /dev/null +++ b/order_confirmation.php @@ -0,0 +1,25 @@ + + +
+
+

Thank You for Your Order!

+

Your order has been placed successfully.

+

Your Order ID is:

+ Continue Shopping +
+
+ + \ No newline at end of file diff --git a/rate.php b/rate.php new file mode 100644 index 00000000..6dccc387 --- /dev/null +++ b/rate.php @@ -0,0 +1,37 @@ +prepare("SELECT rating, rating_count FROM restaurants WHERE id = ?"); + $stmt->execute([$restaurant_id]); + $restaurant = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($restaurant) { + $current_total_rating = $restaurant['rating'] * $restaurant['rating_count']; + $new_total_rating = $current_total_rating + $new_rating; + $new_rating_count = $restaurant['rating_count'] + 1; + $new_average_rating = $new_total_rating / $new_rating_count; + + // Update restaurant with new rating + $update_stmt = $pdo->prepare("UPDATE restaurants SET rating = ?, rating_count = ? WHERE id = ?"); + $update_stmt->execute([$new_average_rating, $new_rating_count, $restaurant_id]); + } + } catch (PDOException $e) { + // Log error, but don't show to user + error_log("Rating update failed: " . $e->getMessage()); + } + } +} + +// Redirect back to the menu page +header('Location: menu.php?id=' . $restaurant_id); +exit; +?> \ No newline at end of file diff --git a/signup.php b/signup.php new file mode 100644 index 00000000..dfb71ba8 --- /dev/null +++ b/signup.php @@ -0,0 +1,27 @@ + + +
+
+

Create Account

+
+
+ + +
+
+ + +
+
+ + +
+ +
+ +
+
+ + diff --git a/signup_process.php b/signup_process.php new file mode 100644 index 00000000..2795be59 --- /dev/null +++ b/signup_process.php @@ -0,0 +1,46 @@ +prepare($sql); + $stmt->execute([$email]); + if ($stmt->fetch()) { + die('Email already exists.'); + } + + $password_hash = password_hash($password, PASSWORD_BCRYPT); + + $sql = "INSERT INTO users (name, email, password) VALUES (?, ?, ?)"; + $stmt = $pdo->prepare($sql); + + if ($stmt->execute([$name, $email, $password_hash])) { + $user_id = $pdo->lastInsertId(); + $_SESSION['user_id'] = $user_id; + $_SESSION['user_name'] = $name; + header("Location: index.php"); + exit; + } else { + die("Error: Could not execute the query."); + } + } catch (PDOException $e) { + die("Could not connect to the database $dbname :" . $e->getMessage()); + } +} +?> \ No newline at end of file