This commit is contained in:
Flatlogic Bot 2025-10-14 23:38:25 +00:00
parent bd0cd9042d
commit ab1ae8b39b
21 changed files with 1512 additions and 266 deletions

765
assets/css/main.css Normal file
View File

@ -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;
}

BIN
assets/images/hero.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

98
assets/js/main.js Normal file
View File

@ -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';
}
});
});
}
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 KiB

80
cart.php Normal file
View File

@ -0,0 +1,80 @@
<?php
session_start();
require_once 'db/config.php';
include 'header.php';
$cart_items = [];
$total_price = 0;
if (!empty($_SESSION['cart'])) {
$menu_item_ids = array_keys($_SESSION['cart']);
$placeholders = implode(',', array_fill(0, count($menu_item_ids), '?'));
$stmt = db()->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
];
}
}
?>
<main>
<div class="container">
<h1>Your Cart</h1>
<?php if (empty($cart_items)): ?>
<p>Your cart is empty.</p>
<?php else: ?>
<table class="cart-table">
<thead>
<tr>
<th>Item</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php foreach ($cart_items as $item): ?>
<tr>
<td><?= htmlspecialchars($item['name']) ?></td>
<td>$<?= htmlspecialchars(number_format($item['price'], 2)) ?></td>
<td>
<form action="cart_actions.php" method="POST" class="update-form">
<input type="hidden" name="action" value="update">
<input type="hidden" name="menu_item_id" value="<?= $item['id'] ?>">
<input type="number" name="quantity" value="<?= $item['quantity'] ?>" min="1" class="quantity-input">
<button type="submit" class="update-btn">Update</button>
</form>
</td>
<td>$<?= htmlspecialchars(number_format($item['total'], 2)) ?></td>
<td>
<a href="cart_actions.php?action=remove&menu_item_id=<?= $item['id'] ?>" class="remove-link">Remove</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<div class="cart-total">
<h3>Total: $<?= htmlspecialchars(number_format($total_price, 2)) ?></h3>
</div>
<div class="cart-actions">
<a href="cart_actions.php?action=clear" class="clear-cart-btn">Clear Cart</a>
<a href="checkout.php" class="checkout-btn">Proceed to Checkout</a>
</div>
<?php endif; ?>
</div>
</main>
<?php include 'footer.php'; ?>

56
cart_actions.php Normal file
View File

@ -0,0 +1,56 @@
<?php
session_start();
require_once 'db/config.php';
// Initialize cart if it doesn't exist
if (!isset($_SESSION['cart'])) {
$_SESSION['cart'] = [];
$_SESSION['cart_restaurant'] = null;
}
$action = $_POST['action'] ?? $_GET['action'] ?? null;
$menu_item_id = $_POST['menu_item_id'] ?? $_GET['menu_item_id'] ?? null;
$restaurant_id = $_POST['restaurant_id'] ?? null;
$quantity = $_POST['quantity'] ?? 1;
switch ($action) {
case 'add':
if ($menu_item_id && $restaurant_id && $quantity > 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;
}

100
checkout.php Normal file
View File

@ -0,0 +1,100 @@
<?php
session_start();
require_once 'db/config.php';
// If user is not logged in, redirect to login page
if (!isset($_SESSION['user_id'])) {
header('Location: login.php');
exit;
}
// If cart is empty, redirect to cart page
if (empty($_SESSION['cart'])) {
header('Location: cart.php');
exit;
}
$cart_items = [];
$total_price = 0;
$restaurant_id = $_SESSION['cart_restaurant'];
$menu_item_ids = array_keys($_SESSION['cart']);
$placeholders = implode(',', array_fill(0, count($menu_item_ids), '?'));
$stmt = db()->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';
?>
<main>
<div class="container">
<h1>Checkout</h1>
<div class="checkout-summary">
<h2>Order Summary</h2>
<table class="cart-table">
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<?php foreach ($cart_items as $item): ?>
<tr>
<td><?= htmlspecialchars($item['name']) ?></td>
<td><?= $item['quantity'] ?></td>
<td>$<?= htmlspecialchars(number_format($item['total'], 2)) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<div class="cart-total">
<h3>Total: $<?= htmlspecialchars(number_format($total_price, 2)) ?></h3>
</div>
<form action="checkout.php" method="POST" class="checkout-form">
<button type="submit" class="checkout-btn">Place Order</button>
</form>
</div>
</div>
</main>
<?php include 'footer.php'; ?>

7
footer.php Normal file
View File

@ -0,0 +1,7 @@
<footer>
<div class="container">
<p>&copy; <?php echo date("Y"); ?> Majuro Eats. All Rights Reserved.</p>
</div>
</footer>
</body>
</html>

50
header.php Normal file
View File

@ -0,0 +1,50 @@
<?php
session_start();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Majuro Eats</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Open+Sans:wght@400;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/main.css?v=<?php echo time(); ?>">
</head>
<body>
<header>
<a href="/" class="logo">Majuro Eats</a>
<div class="address-container">
<span id="address-display">Enter delivery address</span>
</div>
<div class="user-actions">
<?php
$cart_item_count = isset($_SESSION['cart']) ? count($_SESSION['cart']) : 0;
?>
<a href="cart.php" class="cart-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="21" r="1"></circle><circle cx="20" cy="21" r="1"></circle><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path></svg>
<span class="cart-item-count"><?= $cart_item_count ?></span>
</a>
<?php if (isset($_SESSION['user_id'])): ?>
<span>Welcome, <?php echo htmlspecialchars($_SESSION['user_name']); ?></span>
<a href="logout.php">Logout</a>
<?php else: ?>
<a href="login.php">Login</a>
<a href="signup.php">Sign Up</a>
<?php endif; ?>
</div>
</header>
<!-- The Modal -->
<div id="address-modal" class="modal">
<div class="modal-content">
<span class="close-button">&times;</span>
<h2>Enter your delivery address</h2>
<input type="text" id="modal-address-input" placeholder="e.g. Uliga, Majuro">
<button id="save-address-button">Save Address</button>
</div>
</div>
<script src="assets/js/main.js?v=<?php echo time(); ?>" defer></script>

25
includes/pexels.php Normal file
View File

@ -0,0 +1,25 @@
<?php
function pexels_key() {
$k = getenv('PEXELS_KEY');
return $k && strlen($k) > 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;
}

286
index.php
View File

@ -1,232 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MajuroEats - Order Food Online</title>
<meta name="description" content="Your one-stop destination for ordering food from the best local restaurants in Majuro.">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
:root {
--primary-color: #EB1A01; /* DoorDash Red */
--secondary-color: #333333; /* Dark Gray */
--background-color: #F7F7F7; /* Light Gray */
--surface-color: #FFFFFF; /* White */
--text-color: #333333;
--text-light: #767676;
--border-color: #EEEEEE;
--border-radius: 0.5rem;
--spacing-unit: 1rem;
}
<?php include 'header.php'; ?>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Poppins', sans-serif;
background-color: var(--background-color);
color: var(--text-color);
line-height: 1.5;
}
.container {
max-width: 1280px;
margin: 0 auto;
padding: 0 var(--spacing-unit);
}
header {
background-color: var(--surface-color);
padding: var(--spacing-unit) 0;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
position: sticky;
top: 0;
z-index: 1000;
}
.header-container {
display: flex;
justify-content: space-between;
align-items: center;
max-width: 1280px;
margin: 0 auto;
padding: 0 var(--spacing-unit);
}
.logo {
font-size: 1.75rem;
font-weight: 700;
color: var(--secondary-color);
}
.logo span {
color: var(--primary-color);
}
.address-search-container {
display: flex;
align-items: center;
background-color: var(--background-color);
border-radius: 50px;
padding: 0.5rem 1rem;
flex-grow: 1;
margin: 0 2rem;
max-width: 600px;
}
.address-search-container input {
border: none;
background: transparent;
outline: none;
font-size: 1rem;
width: 100%;
font-family: 'Poppins', sans-serif;
}
.header-actions {
display: flex;
align-items: center;
gap: 1.5rem;
}
.header-actions .icon-button {
background: none;
border: none;
cursor: pointer;
}
main {
margin-top: calc(var(--spacing-unit) * 2);
}
.page-title {
font-size: 2rem;
font-weight: 600;
margin-bottom: var(--spacing-unit);
}
.restaurant-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: calc(var(--spacing-unit) * 2);
}
.restaurant-card {
background-color: var(--surface-color);
border-radius: var(--border-radius);
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
overflow: hidden;
transition: all 0.2s ease-in-out;
cursor: pointer;
display: flex;
flex-direction: column;
}
.restaurant-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 16px rgba(0,0,0,0.1);
}
.restaurant-card img {
width: 100%;
height: 180px;
object-fit: cover;
}
.restaurant-card-content {
padding: var(--spacing-unit);
display: flex;
flex-direction: column;
flex-grow: 1;
}
.restaurant-card-content h3 {
font-size: 1.15rem;
font-weight: 600;
margin-bottom: calc(var(--spacing-unit) / 4);
}
.restaurant-card-content p {
color: var(--text-light);
font-size: 0.9rem;
}
.restaurant-card-details {
margin-top: auto;
padding-top: var(--spacing-unit);
font-size: 0.85rem;
color: var(--text-light);
}
.restaurant-card-details p {
margin-bottom: calc(var(--spacing-unit) / 4);
display: flex;
align-items: center;
}
.restaurant-card-details svg {
width: 14px;
height: 14px;
margin-right: 8px;
stroke-width: 2;
}
footer {
text-align: center;
padding: calc(var(--spacing-unit) * 3) 0;
margin-top: calc(var(--spacing-unit) * 3);
background-color: var(--surface-color);
border-top: 1px solid var(--border-color);
}
/* Search bar specific styles */
.search-section {
margin-bottom: calc(var(--spacing-unit) * 2);
}
.search-bar {
width: 100%;
padding: calc(var(--spacing-unit) * 0.9);
font-size: 1rem;
border-radius: 50px;
border: 1px solid var(--border-color);
font-family: 'Poppins', sans-serif;
background-color: var(--surface-color);
padding-left: 2.5rem;
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;
}
</style>
</head>
<body>
<header>
<div class="header-container">
<div class="logo">Majuro<span>Eats</span></div>
<div class="address-search-container">
<input type="text" placeholder="Enter delivery address">
<main>
<section class="hero">
<div class="hero-content">
<h1>Order from Majuro's best</h1>
<input type="text" id="search-input" class="search-bar" placeholder="Search restaurants or cuisines...">
</div>
<div class="header-actions">
<button class="icon-button">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-user"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>
</button>
<button class="icon-button">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-shopping-bag"><path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"></path><line x1="3" y1="6" x2="21" y2="6"></line><path d="M16 10a4 4 0 0 1-8 0"></path></svg>
</button>
</div>
</div>
</header>
<main class="container">
<section class="search-section">
<input type="text" id="search-input" class="search-bar" placeholder="Search restaurants, cuisines, dishes...">
</section>
<h2 class="page-title">Featured Restaurants</h2>
<div class="container">
<h2 class="page-title">All Restaurants</h2>
<section class="restaurant-list">
<div class="restaurant-grid" id="restaurant-grid">
@ -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 '<div class="restaurant-card" data-name="' . htmlspecialchars(strtolower($restaurant['name'])) . '" data-cuisine="' . htmlspecialchars(strtolower($restaurant['cuisine'])) . '">';
echo '<a href="menu.php?id=' . htmlspecialchars($restaurant['id']) . '" class="restaurant-card" data-name="' . htmlspecialchars(strtolower($restaurant['name'])) . '" data-cuisine="' . htmlspecialchars(strtolower($restaurant['cuisine'])) . '">';
echo '<img src="' . htmlspecialchars($restaurant['image_url']) . '" alt="' . htmlspecialchars($restaurant['name']) . '">';
echo '<div class="restaurant-card-content">';
echo '<div>';
echo '<h3>' . htmlspecialchars($restaurant['name']) . '</h3>';
echo '<p>' . htmlspecialchars($restaurant['cuisine']) . '</p>';
if (isset($restaurant['rating']) && $restaurant['rating'] > 0) {
echo '<div class="rating-display">';
echo '<span class="star">★</span>';
echo '<span>' . htmlspecialchars(number_format($restaurant['rating'], 1)) . '</span>';
echo '<span class="rating-count">(' . htmlspecialchars($restaurant['rating_count']) . ' ratings)</span>';
echo '</div>';
echo '<div class="restaurant-card-details">';
if (!empty($restaurant['address'])) {
echo '<p><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-map-pin"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path><circle cx="12" cy="10" r="3"></circle></svg>' . htmlspecialchars($restaurant['address']) . '</p>';
}
if (!empty($restaurant['opening_hours'])) {
echo '<p><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-clock"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>' . htmlspecialchars($restaurant['opening_hours']) . '</p>';
} else {
echo '<div class="rating-display"><span class="rating-count">No ratings yet</span></div>';
}
echo '</div>';
echo '</div>';
echo '</div>';
echo '</a>';
}
} catch (PDOException $e) {
echo '<p>Error: Could not fetch restaurants from the database.</p>';
// Optionally log the error: error_log($e->getMessage());
}
?>
</div>
</section>
</main>
</div>
</main>
<footer>
<p>&copy; <?php echo date("Y"); ?> MajuroEats. All Rights Reserved.</p>
</footer>
<script>
document.addEventListener('DOMContentLoaded', function () {
const searchInput = document.getElementById('search-input');
const restaurantCards = document.querySelectorAll('.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';
}
});
});
});
</script>
<footer>
<p>&copy; <?php echo date("Y"); ?> Majuro Eats. All Rights Reserved.</p>
</footer>
</body>
</html>

23
login.php Normal file
View File

@ -0,0 +1,23 @@
<?php include 'header.php'; ?>
<main>
<div class="auth-container">
<h1>Login</h1>
<form action="login_process.php" method="POST">
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" required>
</div>
<button type="submit" class="btn-submit">Login</button>
</form>
<div class="form-footer">
<p>Don't have an account? <a href="signup.php">Sign up</a></p>
</div>
</div>
</main>
<?php include 'footer.php'; ?>

37
login_process.php Normal file
View File

@ -0,0 +1,37 @@
<?php
session_start();
require_once 'db/config.php';
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$email = $_POST['email'];
$password = $_POST['password'];
if (empty($email) || empty($password)) {
die('Please fill all required fields.');
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
die('Invalid email format.');
}
try {
$pdo = db();
$sql = "SELECT * FROM users WHERE email = ?";
$stmt = $pdo->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());
}
}
?>

7
logout.php Normal file
View File

@ -0,0 +1,7 @@
<?php
session_start();
session_unset();
session_destroy();
header("Location: index.php");
exit;
?>

85
menu.php Normal file
View File

@ -0,0 +1,85 @@
<?php
require_once 'db/config.php';
$restaurant_id = $_GET['id'] ?? null;
$restaurant = null;
$menu_items = [];
if ($restaurant_id) {
$stmt = db()->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';
?>
<main>
<div class="container">
<?php if ($restaurant): ?>
<section class="restaurant-hero-menu" style="background-image: url('<?= htmlspecialchars($restaurant['image_url']) ?>');">
<div class="restaurant-hero-menu-content">
<h1><?= htmlspecialchars($restaurant['name']) ?></h1>
<p><?= htmlspecialchars($restaurant['cuisine']) ?></p>
<div class="rating-display">
<span class="star"></span>
<span><?= htmlspecialchars(number_format($restaurant['rating'], 1)) ?></span>
<span class="rating-count">(<?= htmlspecialchars($restaurant['rating_count']) ?> ratings)</span>
</div>
</div>
</section>
<div class="menu-search-container">
<input type="text" id="menu-search-input" class="search-bar" placeholder="Search menu items...">
</div>
<section class="menu-grid" id="menu-grid">
<?php foreach ($menu_items as $item): ?>
<div class="menu-item-card" data-name="<?= htmlspecialchars(strtolower($item['name'])) ?>" data-description="<?= htmlspecialchars(strtolower($item['description'])) ?>">
<img src="<?= htmlspecialchars($item['image_url']) ?>" alt="<?= htmlspecialchars($item['name']) ?>">
<div class="menu-item-card-content">
<h3><?= htmlspecialchars($item['name']) ?></h3>
<p class="description"><?= htmlspecialchars($item['description']) ?></p>
<p class="price">$<?= htmlspecialchars(number_format($item['price'], 2)) ?></p>
<form action="cart_actions.php" method="POST" class="add-to-cart-form">
<input type="hidden" name="action" value="add">
<input type="hidden" name="menu_item_id" value="<?= $item['id'] ?>">
<input type="hidden" name="restaurant_id" value="<?= $restaurant['id'] ?>">
<div class="form-row">
<input type="number" name="quantity" value="1" min="1" class="quantity-input">
<button type="submit" class="add-to-cart-btn">Add to Cart</button>
</div>
</form>
</div>
</div>
<?php endforeach; ?>
</section>
<section class="rating-form-container">
<h2>Rate your experience</h2>
<form action="rate.php" method="POST" class="rate-form">
<input type="hidden" name="restaurant_id" value="<?= $restaurant['id'] ?>">
<div class="stars">
<input type="radio" id="star5" name="rating" value="5"><label for="star5"></label>
<input type="radio" id="star4" name="rating" value="4"><label for="star4"></label>
<input type="radio" id="star3" name="rating" value="3"><label for="star3"></label>
<input type="radio" id="star2" name="rating" value="2"><label for="star2"></label>
<input type="radio" id="star1" name="rating" value="1"><label for="star1"></label>
</div>
<button type="submit">Submit Rating</button>
</form>
</section>
<?php else: ?>
<p>Restaurant not found.</p>
<?php endif; ?>
</div>
</main>
<?php include 'footer.php'; // Assuming you might create a footer file ?>

View File

@ -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`)
);

25
order_confirmation.php Normal file
View File

@ -0,0 +1,25 @@
<?php
session_start();
require_once 'db/config.php';
include 'header.php';
if (!isset($_SESSION['order_id'])) {
header('Location: index.php');
exit();
}
$order_id = $_SESSION['order_id'];
unset($_SESSION['order_id']);
?>
<main class="container">
<div class="order-confirmation">
<h1>Thank You for Your Order!</h1>
<p>Your order has been placed successfully.</p>
<p>Your Order ID is: <strong><?php echo htmlspecialchars($order_id); ?></strong></p>
<a href="index.php" class="btn btn-primary">Continue Shopping</a>
</div>
</main>
<?php include 'footer.php'; ?>

37
rate.php Normal file
View File

@ -0,0 +1,37 @@
<?php
require_once 'db/config.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$restaurant_id = $_POST['restaurant_id'] ?? null;
$new_rating = $_POST['rating'] ?? null;
if ($restaurant_id && $new_rating) {
try {
$pdo = db();
// Get current rating and count
$stmt = $pdo->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;
?>

27
signup.php Normal file
View File

@ -0,0 +1,27 @@
<?php include 'header.php'; ?>
<main>
<div class="auth-container">
<h1>Create Account</h1>
<form action="signup_process.php" method="POST">
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" required>
</div>
<button type="submit" class="btn-submit">Sign Up</button>
</form>
<div class="form-footer">
<p>Already have an account? <a href="login.php">Log in</a></p>
</div>
</div>
</main>
<?php include 'footer.php'; ?>

46
signup_process.php Normal file
View File

@ -0,0 +1,46 @@
<?php
session_start();
require_once 'db/config.php';
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$name = $_POST['name'];
$email = $_POST['email'];
$password = $_POST['password'];
if (empty($name) || empty($email) || empty($password)) {
die('Please fill all required fields.');
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
die('Invalid email format.');
}
try {
$pdo = db();
$sql = "SELECT id FROM users WHERE email = ?";
$stmt = $pdo->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());
}
}
?>