V12
This commit is contained in:
parent
e98192b894
commit
7a0a2165fc
41
admin/assign_driver.php
Normal file
41
admin/assign_driver.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
require_once '../db/config.php';
|
||||
|
||||
session_start();
|
||||
// Check if the user is logged in as an admin
|
||||
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['order_id']) && isset($_POST['driver_id'])) {
|
||||
$order_id = $_POST['order_id'];
|
||||
$driver_id = $_POST['driver_id'];
|
||||
|
||||
if (!empty($order_id) && !empty($driver_id)) {
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// Check if an assignment already exists
|
||||
$check_stmt = $pdo->prepare("SELECT id FROM driver_assignments WHERE order_id = ?");
|
||||
$check_stmt->execute([$order_id]);
|
||||
|
||||
if (!$check_stmt->fetch()) {
|
||||
// Create new assignment
|
||||
$insert_stmt = $pdo->prepare("INSERT INTO driver_assignments (order_id, driver_id) VALUES (?, ?)");
|
||||
$insert_stmt->execute([$order_id, $driver_id]);
|
||||
|
||||
// Update order status
|
||||
$update_stmt = $pdo->prepare("UPDATE orders SET status = 'Confirmed' WHERE id = ?");
|
||||
$update_stmt->execute([$order_id]);
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
// Log error or handle it appropriately
|
||||
die("Database error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header('Location: orders.php');
|
||||
exit;
|
||||
?>
|
||||
63
admin/drivers.php
Normal file
63
admin/drivers.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
include 'header.php';
|
||||
require_once '../db/config.php';
|
||||
|
||||
// Check if the user is logged in as an admin
|
||||
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
|
||||
// Fetch all drivers with user information
|
||||
$stmt = $pdo->query("
|
||||
SELECT d.id, d.full_name, d.phone_number, d.vehicle_details, d.approval_status, u.email
|
||||
FROM drivers d
|
||||
JOIN users u ON d.user_id = u.id
|
||||
ORDER BY d.created_at DESC
|
||||
");
|
||||
$drivers = $stmt->fetchAll();
|
||||
|
||||
$possible_statuses = ['pending', 'approved', 'rejected'];
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<h2>Driver Management</h2>
|
||||
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Driver ID</th>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th>Phone</th>
|
||||
<th>Vehicle</th>
|
||||
<th>Status</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($drivers as $driver): ?>
|
||||
<tr>
|
||||
<td><?php echo $driver['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($driver['full_name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($driver['email']); ?></td>
|
||||
<td><?php echo htmlspecialchars($driver['phone_number']); ?></td>
|
||||
<td><?php echo htmlspecialchars($driver['vehicle_details']); ?></td>
|
||||
<td><?php echo htmlspecialchars($driver['approval_status']); ?></td>
|
||||
<td>
|
||||
<?php if ($driver['approval_status'] == 'pending'): ?>
|
||||
<a href="update_driver_status.php?id=<?php echo $driver['id']; ?>&status=approved" class="btn btn-success btn-sm">Approve</a>
|
||||
<a href="update_driver_status.php?id=<?php echo $driver['id']; ?>&status=rejected" class="btn btn-danger btn-sm">Reject</a>
|
||||
<?php else: ?>
|
||||
N/A
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
@ -34,6 +34,12 @@ if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== tru
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="cuisines.php">Cuisines</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="drivers.php">Drivers</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="settings.php">Settings</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
|
||||
@ -32,6 +32,10 @@ $stmt = $pdo->query("
|
||||
");
|
||||
$orders = $stmt->fetchAll();
|
||||
|
||||
// Fetch all approved drivers
|
||||
$driver_stmt = $pdo->query("SELECT id, full_name FROM drivers WHERE approval_status = 'approved'");
|
||||
$approved_drivers = $driver_stmt->fetchAll();
|
||||
|
||||
$possible_statuses = ['Pending', 'Confirmed', 'Preparing', 'Out for Delivery', 'Delivered', 'Cancelled'];
|
||||
?>
|
||||
|
||||
@ -47,6 +51,7 @@ $possible_statuses = ['Pending', 'Confirmed', 'Preparing', 'Out for Delivery', '
|
||||
<th>Order Date</th>
|
||||
<th>Status</th>
|
||||
<th>Update Status</th>
|
||||
<th>Assign Driver</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -72,6 +77,32 @@ $possible_statuses = ['Pending', 'Confirmed', 'Preparing', 'Out for Delivery', '
|
||||
<button type="submit" class="btn btn-primary btn-sm ml-2">Update</button>
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
// Check if a driver is already assigned
|
||||
$assignment_stmt = $pdo->prepare("SELECT d.full_name FROM driver_assignments da JOIN drivers d ON da.driver_id = d.id WHERE da.order_id = ?");
|
||||
$assignment_stmt->execute([$order['id']]);
|
||||
$assigned_driver = $assignment_stmt->fetch();
|
||||
?>
|
||||
<?php if ($assigned_driver): ?>
|
||||
<?php echo htmlspecialchars($assigned_driver['full_name']); ?>
|
||||
<?php else: ?>
|
||||
<form action="assign_driver.php" method="POST" class="form-inline">
|
||||
<input type="hidden" name="order_id" value="<?php echo $order['id']; ?>">
|
||||
<div class="form-group">
|
||||
<select name="driver_id" class="form-control form-control-sm">
|
||||
<option value="">Select Driver</option>
|
||||
<?php foreach ($approved_drivers as $driver): ?>
|
||||
<option value="<?php echo $driver['id']; ?>">
|
||||
<?php echo htmlspecialchars($driver['full_name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success btn-sm ml-2">Assign</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
|
||||
119
admin/settings.php
Normal file
119
admin/settings.php
Normal file
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
require_once '../db/config.php';
|
||||
|
||||
$settings = [];
|
||||
$stmt = db()->query('SELECT * FROM settings');
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$settings[$row['name']] = $row['value'];
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$stmt = db()->prepare('UPDATE settings SET value = :value WHERE name = :name');
|
||||
foreach ($_POST as $name => $value) {
|
||||
$stmt->execute(['value' => $value, 'name' => $name]);
|
||||
}
|
||||
header('Location: settings.php?success=1');
|
||||
exit;
|
||||
}
|
||||
|
||||
include 'header.php';
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<h2>Settings</h2>
|
||||
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
<div class="alert alert-success">Settings saved successfully!</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Fees</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<label for="service_fee_percentage">Service Fee Percentage (%)</label>
|
||||
<input type="number" class="form-control" id="service_fee_percentage" name="service_fee_percentage" value="<?php echo htmlspecialchars($settings['service_fee_percentage'] ?? ''); ?>" step="0.01">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="delivery_fee">Delivery Fee ($)</label>
|
||||
<input type="number" class="form-control" id="delivery_fee" name="delivery_fee" value="<?php echo htmlspecialchars($settings['delivery_fee'] ?? ''); ?>" step="0.01">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Driver Pay</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6>Base Pay</h6>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="driver_base_pay_tier1_miles">Base Pay Tier 1 (miles)</label>
|
||||
<input type="number" class="form-control" id="driver_base_pay_tier1_miles" name="driver_base_pay_tier1_miles" value="<?php echo htmlspecialchars($settings['driver_base_pay_tier1_miles'] ?? ''); ?>" step="1">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="driver_base_pay_tier1_amount">Base Pay Tier 1 Amount ($)</label>
|
||||
<input type="number" class="form-control" id="driver_base_pay_tier1_amount" name="driver_base_pay_tier1_amount" value="<?php echo htmlspecialchars($settings['driver_base_pay_tier1_amount'] ?? ''); ?>" step="0.01">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="driver_base_pay_tier2_miles">Base Pay Tier 2 (miles)</label>
|
||||
<input type="number" class="form-control" id="driver_base_pay_tier2_miles" name="driver_base_pay_tier2_miles" value="<?php echo htmlspecialchars($settings['driver_base_pay_tier2_miles'] ?? ''); ?>" step="1">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="driver_base_pay_tier2_amount">Base Pay Tier 2 Amount ($)</label>
|
||||
<input type="number" class="form-control" id="driver_base_pay_tier2_amount" name="driver_base_pay_tier2_amount" value="<?php echo htmlspecialchars($settings['driver_base_pay_tier2_amount'] ?? ''); ?>" step="0.01">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="driver_base_pay_tier3_amount">Base Pay Tier 3 Amount (> Tier 2 miles) ($)</label>
|
||||
<input type="number" class="form-control" id="driver_base_pay_tier3_amount" name="driver_base_pay_tier3_amount" value="<?php echo htmlspecialchars($settings['driver_base_pay_tier3_amount'] ?? ''); ?>" step="0.01">
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h6>Mileage Pay</h6>
|
||||
<div class="form-group">
|
||||
<label for="driver_mileage_pay_rate">Mileage Pay Rate ($ per mile)</label>
|
||||
<input type="number" class="form-control" id="driver_mileage_pay_rate" name="driver_mileage_pay_rate" value="<?php echo htmlspecialchars($settings['driver_mileage_pay_rate'] ?? ''); ?>" step="0.01">
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h6>Bonuses</h6>
|
||||
<div class="form-group">
|
||||
<label for="driver_busy_hour_bonus">Busy Hour Bonus ($ per delivery)</label>
|
||||
<input type="number" class="form-control" id="driver_busy_hour_bonus" name="driver_busy_hour_bonus" value="<?php echo htmlspecialchars($settings['driver_busy_hour_bonus'] ?? ''); ?>" step="0.01">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-4">
|
||||
<label for="driver_quest_bonus_amount">Quest Bonus Amount ($)</label>
|
||||
<input type="number" class="form-control" id="driver_quest_bonus_amount" name="driver_quest_bonus_amount" value="<?php echo htmlspecialchars($settings['driver_quest_bonus_amount'] ?? ''); ?>" step="0.01">
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<label for="driver_quest_bonus_deliveries">Quest Bonus Deliveries</label>
|
||||
<input type="number" class="form-control" id="driver_quest_bonus_deliveries" name="driver_quest_bonus_deliveries" value="<?php echo htmlspecialchars($settings['driver_quest_bonus_deliveries'] ?? ''); ?>" step="1">
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<label for="driver_quest_bonus_hours">Quest Bonus Hours</label>
|
||||
<input type="number" class="form-control" id="driver_quest_bonus_hours" name="driver_quest_bonus_hours" value="<?php echo htmlspecialchars($settings['driver_quest_bonus_hours'] ?? ''); ?>" step="1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save Settings</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
26
admin/update_driver_status.php
Normal file
26
admin/update_driver_status.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
require_once '../db/config.php';
|
||||
|
||||
session_start();
|
||||
// Check if the user is logged in as an admin
|
||||
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
if (isset($_GET['id']) && isset($_GET['status'])) {
|
||||
$driver_id = $_GET['id'];
|
||||
$status = $_GET['status'];
|
||||
|
||||
$possible_statuses = ['approved', 'rejected'];
|
||||
|
||||
if (in_array($status, $possible_statuses)) {
|
||||
$pdo = db();
|
||||
$update_stmt = $pdo->prepare("UPDATE drivers SET approval_status = :status WHERE id = :driver_id");
|
||||
$update_stmt->execute(['status' => $status, 'driver_id' => $driver_id]);
|
||||
}
|
||||
}
|
||||
|
||||
header('Location: drivers.php');
|
||||
exit;
|
||||
?>
|
||||
@ -1,29 +1,37 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
session_start();
|
||||
require_once '../db/config.php';
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
// Check if user is logged in
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
echo json_encode(['error' => 'Unauthorized']);
|
||||
exit();
|
||||
echo json_encode(['error' => 'User not authenticated']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Check if order_id is provided
|
||||
if (!isset($_GET['order_id'])) {
|
||||
echo json_encode(['error' => 'No order ID specified']);
|
||||
exit();
|
||||
echo json_encode(['error' => 'Order ID not specified']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$order_id = $_GET['order_id'];
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
// Fetch order status, ensuring the user owns the order
|
||||
$stmt = $db->prepare("SELECT status FROM orders WHERE id = ? AND user_id = ?");
|
||||
$stmt->execute([$order_id, $user_id]);
|
||||
$order = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
if ($order) {
|
||||
echo json_encode(['status' => $order['status']]);
|
||||
} else {
|
||||
echo json_encode(['error' => 'Order not found or permission denied']);
|
||||
// Fetch the order status, ensuring the order belongs to the logged-in user
|
||||
$stmt = $pdo->prepare("SELECT status FROM orders WHERE id = ? AND user_id = ?");
|
||||
$stmt->execute([$order_id, $user_id]);
|
||||
$order = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($order) {
|
||||
echo json_encode(['status' => ucwords($order['status'])]);
|
||||
} else {
|
||||
echo json_encode(['error' => 'Order not found or permission denied']);
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
echo json_encode(['error' => 'Database error']);
|
||||
}
|
||||
?>
|
||||
?>
|
||||
44
api/save_location.php
Normal file
44
api/save_location.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Define the service area bounds for Majuro
|
||||
const MAJURO_BOUNDS = [
|
||||
'minLat' => 7.05,
|
||||
'maxLat' => 7.15,
|
||||
'minLng' => 171.17,
|
||||
'maxLng' => 171.39
|
||||
];
|
||||
|
||||
function isWithinMajuro($lat, $lng) {
|
||||
return $lat >= MAJURO_BOUNDS['minLat'] && $lat <= MAJURO_BOUNDS['maxLat'] &&
|
||||
$lng >= MAJURO_BOUNDS['minLng'] && $lng <= MAJURO_BOUNDS['maxLng'];
|
||||
}
|
||||
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (isset($data['lat']) && isset($data['lng'])) {
|
||||
$lat = filter_var($data['lat'], FILTER_VALIDATE_FLOAT);
|
||||
$lng = filter_var($data['lng'], FILTER_VALIDATE_FLOAT);
|
||||
|
||||
if ($lat === false || $lng === false) {
|
||||
echo json_encode(['success' => false, 'message' => 'Invalid coordinates provided.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!isWithinMajuro($lat, $lng)) {
|
||||
echo json_encode(['success' => false, 'message' => 'The selected location is outside our service area.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$_SESSION['delivery_location'] = [
|
||||
'lat' => $lat,
|
||||
'lng' => $lng
|
||||
];
|
||||
|
||||
echo json_encode(['success' => true, 'message' => 'Location saved.']);
|
||||
} else {
|
||||
echo json_encode(['success' => false, 'message' => 'No coordinates provided.']);
|
||||
}
|
||||
?>
|
||||
@ -879,3 +879,95 @@ footer {
|
||||
.filter-dropdown:hover .filter-button-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.location-actions {
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.location-button {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||
color: white;
|
||||
border-radius: 50px;
|
||||
padding: 10px 20px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.location-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
border-color: var(--white);
|
||||
}
|
||||
|
||||
/* Star Rating Styles */
|
||||
.rating {
|
||||
display: inline-block;
|
||||
font-size: 2rem;
|
||||
direction: rtl; /* Right-to-left to fill stars from right */
|
||||
}
|
||||
|
||||
.rating input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.rating label {
|
||||
color: #ddd; /* Default empty star color */
|
||||
cursor: pointer;
|
||||
padding: 0 0.1em;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.rating label:hover,
|
||||
.rating label:hover ~ label,
|
||||
.rating input:checked ~ label {
|
||||
color: #FFC107; /* Filled star color */
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -15px;
|
||||
}
|
||||
.col-md-3 {
|
||||
width: 25%;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.col-md-9 {
|
||||
width: 75%;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.form-check {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.btn {
|
||||
padding: 8px 15px;
|
||||
border-radius: 5px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
.btn-primary {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: 1px solid #007bff;
|
||||
}
|
||||
.btn-secondary {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
border: 1px solid #6c757d;
|
||||
}
|
||||
.mt-3 {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.search-form {
|
||||
display: flex;
|
||||
}
|
||||
.search-bar {
|
||||
flex-grow: 1;
|
||||
}
|
||||
25
cart.php
25
cart.php
@ -70,23 +70,32 @@ include 'header.php';
|
||||
<div class="col-md-6 text-end">
|
||||
<h4>Subtotal: $<?php echo number_format($totalPrice, 2); ?></h4>
|
||||
<?php
|
||||
$discount_amount = 0;
|
||||
$final_total = $totalPrice;
|
||||
// Fetch settings from the database
|
||||
$settingsStmt = $pdoconnection->query("SELECT name, value FROM settings WHERE name IN ('delivery_fee', 'service_fee_percentage')");
|
||||
$settings = $settingsStmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
|
||||
$delivery_fee = $settings['delivery_fee'] ?? 0;
|
||||
$service_fee_percentage = $settings['service_fee_percentage'] ?? 0;
|
||||
|
||||
$service_fee = ($totalPrice * $service_fee_percentage) / 100;
|
||||
|
||||
$discount_amount = 0;
|
||||
if (isset($_SESSION['coupon_code']) && isset($_SESSION['discount_percentage'])) {
|
||||
$discount_percentage = $_SESSION['discount_percentage'];
|
||||
$discount_amount = ($totalPrice * $discount_percentage) / 100;
|
||||
$final_total = $totalPrice - $discount_amount;
|
||||
?>
|
||||
<h5 class="text-success">Discount (<?php echo htmlspecialchars($_SESSION['coupon_code']); ?> @ <?php echo $discount_percentage; ?>%): -$<?php echo number_format($discount_amount, 2); ?></h5>
|
||||
<h3>Total: $<?php echo number_format($final_total, 2); ?></h3>
|
||||
<a href="remove_coupon.php" class="btn btn-danger btn-sm mt-2">Remove Coupon</a>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<h3>Total: $<?php echo number_format($final_total, 2); ?></h3>
|
||||
<?php
|
||||
}
|
||||
|
||||
$final_total = $totalPrice - $discount_amount + $delivery_fee + $service_fee;
|
||||
|
||||
?>
|
||||
<h5>Delivery Fee: $<?php echo number_format($delivery_fee, 2); ?></h5>
|
||||
<h5>Service Fee (<?php echo htmlspecialchars($service_fee_percentage); ?>%): $<?php echo number_format($service_fee, 2); ?></h5>
|
||||
<h3>Total: $<?php echo number_format($final_total, 2); ?></h3>
|
||||
<?php
|
||||
|
||||
$_SESSION['total_price'] = $final_total;
|
||||
$_SESSION['discount_amount'] = $discount_amount;
|
||||
|
||||
21
checkout.php
21
checkout.php
@ -25,8 +25,17 @@ $totalPrice = 0;
|
||||
foreach ($cartItems as $item) {
|
||||
$totalPrice += $item['price'] * $item['quantity'];
|
||||
}
|
||||
$delivery_fee = 5.00;
|
||||
$totalPriceWithDelivery = $totalPrice + $delivery_fee;
|
||||
|
||||
// Fetch settings from the database
|
||||
$settingsStmt = $pdo->query("SELECT name, value FROM settings WHERE name IN ('delivery_fee', 'service_fee_percentage')");
|
||||
$settings = $settingsStmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
|
||||
$delivery_fee = $settings['delivery_fee'] ?? 0;
|
||||
$service_fee_percentage = $settings['service_fee_percentage'] ?? 0;
|
||||
|
||||
$service_fee = ($totalPrice * $service_fee_percentage) / 100;
|
||||
$totalPriceWithFees = $totalPrice + $delivery_fee + $service_fee;
|
||||
|
||||
|
||||
|
||||
include 'header.php';
|
||||
@ -86,9 +95,13 @@ include 'header.php';
|
||||
Delivery Fee
|
||||
<span>$<?php echo number_format($delivery_fee, 2); ?></span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Service Fee (<?php echo htmlspecialchars($service_fee_percentage); ?>%)
|
||||
<span>$<?php echo number_format($service_fee, 2); ?></span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center fw-bold">
|
||||
Total
|
||||
<span>$<?php echo number_format($totalPriceWithDelivery, 2); ?></span>
|
||||
<span>$<?php echo number_format($totalPriceWithFees, 2); ?></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -130,7 +143,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
return actions.order.create({
|
||||
purchase_units: [{
|
||||
amount: {
|
||||
value: '<?php echo number_format($totalPriceWithDelivery, 2, '.', ''); ?>'
|
||||
value: '<?php echo number_format($totalPriceWithFees, 2, '.', ''); ?>'
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
||||
2
driver/footer.php
Normal file
2
driver/footer.php
Normal file
@ -0,0 +1,2 @@
|
||||
</body>
|
||||
</html>
|
||||
27
driver/header.php
Normal file
27
driver/header.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
session_start();
|
||||
// If driver is not logged in, redirect to login page
|
||||
if (!isset($_SESSION['driver_id'])) {
|
||||
header('Location: /driver/login.php');
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Driver Dashboard - Majuro Eats</title>
|
||||
<link rel="stylesheet" href="../assets/css/main.css?v=<?php echo time(); ?>">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<a href="/driver/" class="logo">Majuro Eats - Driver Portal</a>
|
||||
<div class="user-actions">
|
||||
<?php if (isset($_SESSION['driver_id'])): ?>
|
||||
<span>Welcome, <?php echo htmlspecialchars($_SESSION['driver_name']); ?></span>
|
||||
<a href="logout.php">Logout</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</header>
|
||||
75
driver/index.php
Normal file
75
driver/index.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
include 'header.php';
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
$driver_id = $_SESSION['driver_id'];
|
||||
$pdo = db();
|
||||
|
||||
$stmt = $pdo->prepare(
|
||||
'SELECT ' .
|
||||
'o.id as order_id, ' .
|
||||
'o.status as order_status, ' .
|
||||
'o.delivery_address, ' .
|
||||
'u.name as customer_name, ' .
|
||||
'r.name as restaurant_name, ' .
|
||||
'r.address as restaurant_address ' .
|
||||
'FROM orders o ' .
|
||||
'JOIN driver_assignments da ON o.id = da.order_id ' .
|
||||
'JOIN users u ON o.user_id = u.id ' .
|
||||
'JOIN restaurants r ON o.restaurant_id = r.id ' .
|
||||
'WHERE da.driver_id = ? ' .
|
||||
'ORDER BY o.created_at DESC'
|
||||
);
|
||||
$stmt->execute([$driver_id]);
|
||||
$assigned_orders = $stmt->fetchAll();
|
||||
|
||||
$order_statuses = ['preparing', 'out for delivery', 'delivered', 'cancelled'];
|
||||
|
||||
?>
|
||||
|
||||
<main class="container">
|
||||
<h1>My Assigned Deliveries</h1>
|
||||
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
<p class="success-message"><?php echo htmlspecialchars($_GET['success']); ?></p>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($_GET['error'])): ?>
|
||||
<p class="error-message"><?php echo htmlspecialchars($_GET['error']); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="order-list">
|
||||
<?php if (empty($assigned_orders)): ?>
|
||||
<p>You have no assigned orders at the moment.</p>
|
||||
<?php else: ?>
|
||||
<?php foreach ($assigned_orders as $order): ?>
|
||||
<div class="order-card">
|
||||
<h3>Order #<?php echo htmlspecialchars($order['order_id']); ?></h3>
|
||||
<p><strong>Status:</strong> <?php echo htmlspecialchars(ucwords($order['order_status'])); ?></p>
|
||||
<hr>
|
||||
<p><strong>Customer:</strong> <?php echo htmlspecialchars($order['customer_name']); ?></p>
|
||||
<p><strong>Delivery Address:</strong> <?php echo htmlspecialchars($order['delivery_address']); ?></p>
|
||||
<hr>
|
||||
<p><strong>Restaurant:</strong> <?php echo htmlspecialchars($order['restaurant_name']); ?></p>
|
||||
<p><strong>Restaurant Address:</strong> <?php echo htmlspecialchars($order['restaurant_address']); ?></p>
|
||||
|
||||
<form action="update_order_status.php" method="POST" class="status-update-form">
|
||||
<input type="hidden" name="order_id" value="<?php echo $order['order_id']; ?>">
|
||||
<div class="form-group">
|
||||
<label for="status-<?php echo $order['order_id']; ?>">Update Status:</label>
|
||||
<select name="status" id="status-<?php echo $order['order_id']; ?>">
|
||||
<?php foreach ($order_statuses as $status): ?>
|
||||
<option value="<?php echo $status; ?>" <?php echo ($order['order_status'] === $status) ? 'selected' : ''; ?>>
|
||||
<?php echo ucwords($status); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn-submit">Update</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
30
driver/login.php
Normal file
30
driver/login.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (isset($_SESSION['driver_id'])) {
|
||||
header('Location: /driver/index.php');
|
||||
exit;
|
||||
}
|
||||
include 'header.php';
|
||||
?>
|
||||
|
||||
<main>
|
||||
<div class="auth-container">
|
||||
<h1>Driver Login</h1>
|
||||
<?php if (isset($_GET['error'])): ?>
|
||||
<p class="error-message"><?php echo htmlspecialchars($_GET['error']); ?></p>
|
||||
<?php endif; ?>
|
||||
<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>
|
||||
</main>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
49
driver/login_process.php
Normal file
49
driver/login_process.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$email = $_POST['email'];
|
||||
$password = $_POST['password'];
|
||||
|
||||
if (empty($email) || empty($password)) {
|
||||
header("Location: login.php?error=Please fill all fields");
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
$sql = "SELECT id, full_name, email, password_hash, approval_status FROM drivers WHERE email = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$email]);
|
||||
$driver = $stmt->fetch();
|
||||
|
||||
if ($driver) {
|
||||
if ($driver['approval_status'] === 'pending') {
|
||||
header("Location: ../driver_pending_approval.php");
|
||||
exit;
|
||||
} elseif ($driver['approval_status'] === 'rejected') {
|
||||
header("Location: ../driver_rejected.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($driver['approval_status'] === 'approved' && password_verify($password, $driver['password_hash'])) {
|
||||
$_SESSION['driver_id'] = $driver['id'];
|
||||
$_SESSION['driver_name'] = $driver['full_name'];
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
} else {
|
||||
header("Location: login.php?error=Invalid credentials");
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
header("Location: login.php?error=Invalid credentials");
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
header("Location: login.php?error=A database error occurred");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
?>
|
||||
7
driver/logout.php
Normal file
7
driver/logout.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
session_start();
|
||||
session_unset();
|
||||
session_destroy();
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
?>
|
||||
58
driver/update_order_status.php
Normal file
58
driver/update_order_status.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
// Ensure driver is logged in
|
||||
if (!isset($_SESSION['driver_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$order_id = $_POST['order_id'];
|
||||
$status = $_POST['status'];
|
||||
$driver_id = $_SESSION['driver_id'];
|
||||
|
||||
$allowed_statuses = ['preparing', 'out for delivery', 'delivered', 'cancelled'];
|
||||
|
||||
if (empty($order_id) || empty($status) || !in_array($status, $allowed_statuses)) {
|
||||
header('Location: index.php?error=Invalid input.');
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// Security Check: Verify the order is assigned to this driver
|
||||
$check_stmt = $pdo->prepare(
|
||||
'SELECT o.id FROM orders o ' .
|
||||
'JOIN driver_assignments da ON o.id = da.order_id ' .
|
||||
'WHERE o.id = ? AND da.driver_id = ?'
|
||||
);
|
||||
$check_stmt->execute([$order_id, $driver_id]);
|
||||
$assignment = $check_stmt->fetch();
|
||||
|
||||
if (!$assignment) {
|
||||
header('Location: index.php?error=You are not authorized to update this order.');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Update the order status
|
||||
$update_stmt = $pdo->prepare('UPDATE orders SET status = ? WHERE id = ?');
|
||||
|
||||
if ($update_stmt->execute([$status, $order_id])) {
|
||||
header('Location: index.php?success=Order status updated successfully.');
|
||||
exit;
|
||||
} else {
|
||||
header('Location: index.php?error=Failed to update order status.');
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
header('Location: index.php?error=A database error occurred.');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
12
driver_pending_approval.php
Normal file
12
driver_pending_approval.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php include 'header.php'; ?>
|
||||
|
||||
<main>
|
||||
<div class="container mt-4">
|
||||
<h1>Application Pending Approval</h1>
|
||||
<p>Thank you for signing up to be a driver. Your application is currently under review.</p>
|
||||
<p>We will notify you by email once your application has been approved.</p>
|
||||
<p><a href="logout.php">Logout</a></p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
12
driver_rejected.php
Normal file
12
driver_rejected.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php include 'header.php'; ?>
|
||||
|
||||
<main>
|
||||
<div class="container mt-4">
|
||||
<h1>Application Rejected</h1>
|
||||
<p>We regret to inform you that your application to become a driver has been rejected.</p>
|
||||
<p>If you believe this is a mistake, please contact our support team.</p>
|
||||
<p><a href="logout.php">Logout</a></p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
35
driver_signup.php
Normal file
35
driver_signup.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php include 'header.php'; ?>
|
||||
|
||||
<main>
|
||||
<div class="auth-container">
|
||||
<h1>Become a Driver</h1>
|
||||
<form action="driver_signup_process.php" method="POST">
|
||||
<div class="form-group">
|
||||
<label for="full_name">Full Name</label>
|
||||
<input type="text" id="full_name" name="full_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>
|
||||
<div class="form-group">
|
||||
<label for="phone_number">Phone Number</label>
|
||||
<input type="text" id="phone_number" name="phone_number" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="vehicle_details">Vehicle Details (e.g., 2023 Toyota Camry, Blue)</label>
|
||||
<input type="text" id="vehicle_details" name="vehicle_details" 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'; ?>
|
||||
47
driver_signup_process.php
Normal file
47
driver_signup_process.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$full_name = $_POST['full_name'];
|
||||
$email = $_POST['email'];
|
||||
$password = $_POST['password'];
|
||||
$phone_number = $_POST['phone_number'];
|
||||
$vehicle_details = $_POST['vehicle_details'];
|
||||
|
||||
if (empty($full_name) || empty($email) || empty($password) || empty($phone_number) || empty($vehicle_details)) {
|
||||
die('Please fill all required fields.');
|
||||
}
|
||||
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
die('Invalid email format.');
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// Check if driver already exists
|
||||
$sql = "SELECT id FROM drivers WHERE email = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$email]);
|
||||
if ($stmt->fetch()) {
|
||||
die('Email already exists.');
|
||||
}
|
||||
|
||||
// Insert into drivers table
|
||||
$password_hash = password_hash($password, PASSWORD_BCRYPT);
|
||||
$sql = "INSERT INTO drivers (full_name, email, password_hash, phone_number, vehicle_details, approval_status) VALUES (?, ?, ?, ?, ?, 'pending')";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
|
||||
if ($stmt->execute([$full_name, $email, $password_hash, $phone_number, $vehicle_details])) {
|
||||
// Redirect to a pending approval page
|
||||
header("Location: driver_pending_approval.php");
|
||||
exit;
|
||||
} else {
|
||||
die("Error: Could not execute the query.");
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
die("Could not connect to the database: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
?>
|
||||
@ -11,6 +11,7 @@ session_start();
|
||||
<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(); ?>">
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@ -67,4 +68,6 @@ session_start();
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>" defer></script>
|
||||
|
||||
|
||||
252
index.php
252
index.php
@ -8,6 +8,10 @@
|
||||
<input type="text" name="search" class="search-bar" placeholder="Search for restaurants..." value="<?= isset($_GET['search']) ? htmlspecialchars($_GET['search']) : '' ?>">
|
||||
<button type="submit" class="search-button">Search</button>
|
||||
</form>
|
||||
<div class="location-actions">
|
||||
<button class="location-button" id="pin-location">Pin a Location</button>
|
||||
<button class="location-button" id="my-location">My Location</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -15,15 +19,16 @@
|
||||
<div class="row">
|
||||
<!-- Filter Sidebar -->
|
||||
<div class="col-md-3">
|
||||
<h4>Filter by Cuisine</h4>
|
||||
<h4>Filter Results</h4>
|
||||
<form action="index.php" method="get" id="filter-form">
|
||||
<!-- Hidden search field to persist search query -->
|
||||
<?php if (isset($_GET['search'])): ?>
|
||||
<?php if (isset($_GET['search'])):
|
||||
<input type="hidden" name="search" value="<?= htmlspecialchars($_GET['search']) ?>">
|
||||
<?php endif; ?>
|
||||
|
||||
<h5>By Cuisine</h5>
|
||||
<?php
|
||||
$cuisine_stmt = $pdo->query("SELECT * FROM cuisines ORDER BY name");
|
||||
$cuisine_stmt = db()->query("SELECT * FROM cuisines ORDER BY name");
|
||||
$all_cuisines = $cuisine_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$selected_cuisines = isset($_GET['cuisines']) && is_array($_GET['cuisines']) ? $_GET['cuisines'] : [];
|
||||
|
||||
@ -35,8 +40,20 @@
|
||||
</label>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<button type="submit" class="btn btn-primary mt-3">Apply Filter</button>
|
||||
<a href="index.php" class="btn btn-secondary mt-3">Clear Filter</a>
|
||||
|
||||
<h5 class="mt-4">By Rating</h5>
|
||||
<div class="form-group">
|
||||
<select name="min_rating" class="form-control">
|
||||
<option value="">Any Rating</option>
|
||||
<option value="4" <?= isset($_GET['min_rating']) && $_GET['min_rating'] == 4 ? 'selected' : '' ?>>4 stars & up</option>
|
||||
<option value="3" <?= isset($_GET['min_rating']) && $_GET['min_rating'] == 3 ? 'selected' : '' ?>>3 stars & up</option>
|
||||
<option value="2" <?= isset($_GET['min_rating']) && $_GET['min_rating'] == 2 ? 'selected' : '' ?>>2 stars & up</option>
|
||||
<option value="1" <?= isset($_GET['min_rating']) && $_GET['min_rating'] == 1 ? 'selected' : '' ?>>1 star & up</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary mt-3">Apply Filters</button>
|
||||
<a href="index.php" class="btn btn-secondary mt-3">Clear Filters</a>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@ -76,9 +93,18 @@
|
||||
$sql .= " WHERE " . implode(' AND ', $where_clauses);
|
||||
}
|
||||
|
||||
$sql .= " GROUP BY r.id, r.name, r.image_url ORDER BY r.name";
|
||||
$sql .= " GROUP BY r.id, r.name, r.image_url";
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
// Add rating filter (HAVING clause)
|
||||
$selected_min_rating = isset($_GET['min_rating']) && is_numeric($_GET['min_rating']) ? (int)$_GET['min_rating'] : 0;
|
||||
if ($selected_min_rating > 0) {
|
||||
$sql .= " HAVING AVG(rt.rating) >= ?";
|
||||
$params[] = $selected_min_rating;
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY r.name";
|
||||
|
||||
$stmt = db()->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$restaurants = $stmt->fetchAll();
|
||||
|
||||
@ -88,11 +114,11 @@
|
||||
foreach ($restaurants as $restaurant) {
|
||||
// Get cuisines for this restaurant
|
||||
$cuisine_sql = "SELECT c.name FROM cuisines c JOIN restaurant_cuisines rc ON c.id = rc.cuisine_id WHERE rc.restaurant_id = ?";
|
||||
$cuisine_stmt = $pdo->prepare($cuisine_sql);
|
||||
$cuisine_stmt = db()->prepare($cuisine_sql);
|
||||
$cuisine_stmt->execute([$restaurant['id']]);
|
||||
$restaurant_cuisines_list = $cuisine_stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
echo '<a href="menu.php?id=' . htmlspecialchars($restaurant['id']) . '" class="restaurant-card">';
|
||||
echo '<a href="menu.php?restaurant_id=' . htmlspecialchars($restaurant['id']) . '" class="restaurant-card">';
|
||||
echo '<img src="' . htmlspecialchars($restaurant['image_url'] ? $restaurant['image_url'] : 'assets/images/hero.jpg') . '" alt="' . htmlspecialchars($restaurant['name']) . '">';
|
||||
echo '<div class="restaurant-card-content">';
|
||||
echo '<h3>' . htmlspecialchars($restaurant['name']) . '</h3>';
|
||||
@ -118,55 +144,161 @@
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -15px;
|
||||
}
|
||||
.col-md-3 {
|
||||
width: 25%;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.col-md-9 {
|
||||
width: 75%;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.form-check {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.btn {
|
||||
padding: 8px 15px;
|
||||
border-radius: 5px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
.btn-primary {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: 1px solid #007bff;
|
||||
}
|
||||
.btn-secondary {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
border: 1px solid #6c757d;
|
||||
}
|
||||
.mt-3 {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.search-form {
|
||||
display: flex;
|
||||
}
|
||||
.search-bar {
|
||||
flex-grow: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
<div id="map-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close-button">×</span>
|
||||
<h2>Pin Your Location</h2>
|
||||
<div id="map" style="height: 400px;"></div>
|
||||
<p id="map-message"></p>
|
||||
<button id="confirm-location-button">Confirm Location</button>
|
||||
<button id="cancel-location-button">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const pinLocationButton = document.getElementById('pin-location');
|
||||
const myLocationButton = document.getElementById('my-location');
|
||||
const locationActions = document.querySelector('.location-actions');
|
||||
const addressDisplay = document.getElementById('address-display');
|
||||
|
||||
const mapModal = document.getElementById('map-modal');
|
||||
const closeModalButton = mapModal.querySelector('.close-button');
|
||||
const confirmLocationButton = document.getElementById('confirm-location-button');
|
||||
const cancelLocationButton = document.getElementById('cancel-location-button');
|
||||
const mapMessage = document.getElementById('map-message');
|
||||
|
||||
let map;
|
||||
let marker;
|
||||
|
||||
const majuroBounds = {
|
||||
minLat: 7.05,
|
||||
maxLat: 7.15,
|
||||
minLng: 171.17,
|
||||
maxLng: 171.39
|
||||
};
|
||||
|
||||
function isWithinMajuro(lat, lng) {
|
||||
return lat >= majuroBounds.minLat && lat <= majuroBounds.maxLat &&
|
||||
lng >= majuroBounds.minLng && lng <= majuroBounds.maxLng;
|
||||
}
|
||||
|
||||
function openMapModal(lat, lng) {
|
||||
mapModal.style.display = 'block';
|
||||
if (!map) {
|
||||
map = L.map('map').setView([7.09, 171.28], 12);
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
}).addTo(map);
|
||||
}
|
||||
map.setView([lat, lng], 14);
|
||||
if (marker) {
|
||||
marker.setLatLng([lat, lng]);
|
||||
} else {
|
||||
marker = L.marker([lat, lng], { draggable: true }).addTo(map);
|
||||
}
|
||||
mapMessage.textContent = '';
|
||||
}
|
||||
|
||||
function closeMapModal() {
|
||||
mapModal.style.display = 'none';
|
||||
}
|
||||
|
||||
pinLocationButton.addEventListener('click', function() {
|
||||
openMapModal(7.09, 171.28);
|
||||
});
|
||||
|
||||
myLocationButton.addEventListener('click', function() {
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(function(position) {
|
||||
const lat = position.coords.latitude;
|
||||
const lng = position.coords.longitude;
|
||||
if (isWithinMajuro(lat, lng)) {
|
||||
saveLocation(lat, lng);
|
||||
} else {
|
||||
alert('Sorry, we do not offer services for your current location.');
|
||||
}
|
||||
}, function() {
|
||||
alert('Could not get your location.');
|
||||
});
|
||||
} else {
|
||||
alert('Geolocation is not supported by your browser.');
|
||||
}
|
||||
});
|
||||
|
||||
closeModalButton.addEventListener('click', closeMapModal);
|
||||
cancelLocationButton.addEventListener('click', closeMapModal);
|
||||
|
||||
confirmLocationButton.addEventListener('click', function() {
|
||||
const latlng = marker.getLatLng();
|
||||
if (isWithinMajuro(latlng.lat, latlng.lng)) {
|
||||
saveLocation(latlng.lat, latlng.lng);
|
||||
} else {
|
||||
mapMessage.textContent = 'Sorry, we do not offer services for the location you pinned. Please select a location within Majuro (Rita-Laura).';
|
||||
mapMessage.style.color = 'red';
|
||||
}
|
||||
});
|
||||
|
||||
function saveLocation(lat, lng) {
|
||||
fetch('api/save_location.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ lat: lat, lng: lng })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
updateLocationUI(lat, lng);
|
||||
closeMapModal();
|
||||
} else {
|
||||
alert(data.message || 'Could not save location.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateLocationUI(lat, lng) {
|
||||
locationActions.innerHTML = `
|
||||
<div class="pinned-location">
|
||||
<span>Pinned: ${lat.toFixed(4)}, ${lng.toFixed(4)}</span>
|
||||
<button id="change-location">Change</button>
|
||||
</div>
|
||||
`;
|
||||
addressDisplay.textContent = `Delivery to: ${lat.toFixed(4)}, ${lng.toFixed(4)}`;
|
||||
document.getElementById('change-location').addEventListener('click', function() {
|
||||
locationActions.innerHTML = `
|
||||
<button class="location-button" id="pin-location">Pin a Location</button>
|
||||
<button class="location-button" id="my-location">My Location</button>
|
||||
`;
|
||||
// Re-add event listeners
|
||||
document.getElementById('pin-location').addEventListener('click', function() { openMapModal(7.09, 171.28); });
|
||||
document.getElementById('my-location').addEventListener('click', function() {
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(function(position) {
|
||||
const lat = position.coords.latitude;
|
||||
const lng = position.coords.longitude;
|
||||
if (isWithinMajuro(lat, lng)) {
|
||||
saveLocation(lat, lng);
|
||||
} else {
|
||||
alert('Sorry, we do not offer services for your current location.');
|
||||
}
|
||||
}, function() {
|
||||
alert('Could not get your location.');
|
||||
});
|
||||
} else {
|
||||
alert('Geolocation is not supported by your browser.');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// On page load, check if location is in session
|
||||
<?php if (isset($_SESSION['delivery_location'])):
|
||||
updateLocationUI(<?php echo $_SESSION['delivery_location']['lat']; ?>, <?php echo $_SESSION['delivery_location']['lng']; ?>);
|
||||
<?php endif; ?>
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
87
leave_review.php
Normal file
87
leave_review.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
// Ensure user is logged in
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header("Location: login.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
include 'header.php';
|
||||
$db = db();
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$order_id = isset($_GET['order_id']) ? (int)$_GET['order_id'] : 0;
|
||||
|
||||
$error_message = '';
|
||||
$order = null;
|
||||
|
||||
if ($order_id > 0) {
|
||||
// 1. Verify the order exists, belongs to the user, and is delivered
|
||||
$stmt = $db->prepare("SELECT * FROM orders WHERE id = ? AND user_id = ?");
|
||||
$stmt->execute([$order_id, $user_id]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
if (!$order) {
|
||||
$error_message = "This order could not be found or does not belong to you.";
|
||||
} elseif ($order['status'] !== 'Delivered') {
|
||||
$error_message = "You can only review orders that have been delivered.";
|
||||
} else {
|
||||
// 2. Check if a review already exists for this order
|
||||
$stmt_rating = $db->prepare("SELECT id FROM ratings WHERE order_id = ?");
|
||||
$stmt_rating->execute([$order_id]);
|
||||
if ($stmt_rating->fetch()) {
|
||||
$error_message = "You have already submitted a review for this order.";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$error_message = "No order was specified.";
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="container mt-5">
|
||||
<h2>Leave a Review</h2>
|
||||
<hr>
|
||||
|
||||
<?php
|
||||
if (isset($_SESSION['success_message'])) {
|
||||
echo '<div class="alert alert-success">' . $_SESSION['success_message'] . '</div>';
|
||||
unset($_SESSION['success_message']);
|
||||
}
|
||||
if (isset($_SESSION['error_message'])) {
|
||||
echo '<div class="alert alert-danger">' . $_SESSION['error_message'] . '</div>';
|
||||
unset($_SESSION['error_message']);
|
||||
}
|
||||
?>
|
||||
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo $error_message; ?></div>
|
||||
<?php else: ?>
|
||||
<p>You are reviewing Order #<?php echo htmlspecialchars($order_id); ?></p>
|
||||
|
||||
<form action="process_review.php" method="POST">
|
||||
<input type="hidden" name="order_id" value="<?php echo htmlspecialchars($order_id); ?>">
|
||||
<input type="hidden" name="restaurant_id" value="<?php echo htmlspecialchars($order['restaurant_id']); ?>">
|
||||
|
||||
<div class="form-group">
|
||||
<label><strong>Rating</strong></label>
|
||||
<div class="rating">
|
||||
<input type="radio" name="rating" id="star5" value="5" required><label for="star5">★</label>
|
||||
<input type="radio" name="rating" id="star4" value="4"><label for="star4">★</label>
|
||||
<input type="radio" name="rating" id="star3" value="3"><label for="star3">★</label>
|
||||
<input type="radio" name="rating" id="star2" value="2"><label for="star2">★</label>
|
||||
<input type="radio" name="rating" id="star1" value="1"><label for="star1">★</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="review"><strong>Review (optional)</strong></label>
|
||||
<textarea name="review" id="review" class="form-control" rows="4" placeholder="Tell us about your experience..."></textarea>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Submit Review</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
@ -23,17 +23,40 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user && password_verify($password, $user['password'])) {
|
||||
$user_id = $user['id'];
|
||||
$session_id = session_id();
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['user_name'] = $user['name'];
|
||||
$_SESSION['user_role'] = $user['role'];
|
||||
|
||||
// Merge guest cart with user cart
|
||||
$session_id = session_id();
|
||||
$merge_sql = "UPDATE cart SET user_id = ?, session_id = NULL WHERE session_id = ?";
|
||||
$merge_stmt = $pdo->prepare($merge_sql);
|
||||
$merge_stmt->execute([$user_id, $session_id]);
|
||||
$merge_stmt->execute([$user['id'], $session_id]);
|
||||
|
||||
$_SESSION['user_id'] = $user_id;
|
||||
$_SESSION['user_name'] = $user['name'];
|
||||
header("Location: index.php");
|
||||
if ($user['role'] == 'admin') {
|
||||
$_SESSION['admin_logged_in'] = true;
|
||||
header("Location: admin/index.php");
|
||||
} elseif ($user['role'] == 'driver') {
|
||||
$driver_sql = "SELECT approval_status FROM drivers WHERE user_id = ?";
|
||||
$driver_stmt = $pdo->prepare($driver_sql);
|
||||
$driver_stmt->execute([$user['id']]);
|
||||
$driver = $driver_stmt->fetch();
|
||||
|
||||
if ($driver) {
|
||||
if ($driver['approval_status'] == 'approved') {
|
||||
header("Location: driver/index.php");
|
||||
} elseif ($driver['approval_status'] == 'pending') {
|
||||
header("Location: driver_pending_approval.php");
|
||||
} else { // rejected
|
||||
header("Location: driver_rejected.php");
|
||||
}
|
||||
} else {
|
||||
// This case should ideally not happen if data is consistent
|
||||
die('Driver profile not found.');
|
||||
}
|
||||
} else { // customer
|
||||
header("Location: index.php");
|
||||
}
|
||||
exit;
|
||||
} else {
|
||||
die('Invalid email or password.');
|
||||
|
||||
130
menu.php
130
menu.php
@ -2,53 +2,36 @@
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
$restaurant_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||
$restaurant_id = isset($_GET['restaurant_id']) ? (int)$_GET['restaurant_id'] : 0;
|
||||
|
||||
if ($restaurant_id === 0) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Handle review submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit_review'])) {
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
// Redirect to login if not logged in
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$rating = isset($_POST['rating']) ? (int)$_POST['rating'] : 0;
|
||||
$review = isset($_POST['review']) ? trim($_POST['review']) : '';
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
if ($rating >= 1 && $rating <= 5) {
|
||||
try {
|
||||
$insert_stmt = db()->prepare("INSERT INTO ratings (restaurant_id, user_id, rating, review) VALUES (:restaurant_id, :user_id, :rating, :review)");
|
||||
$insert_stmt->bindParam(':restaurant_id', $restaurant_id, PDO::PARAM_INT);
|
||||
$insert_stmt->bindParam(':user_id', $user_id, PDO::PARAM_INT);
|
||||
$insert_stmt->bindParam(':rating', $rating, PDO::PARAM_INT);
|
||||
$insert_stmt->bindParam(':review', $review, PDO::PARAM_STR);
|
||||
$insert_stmt->execute();
|
||||
// Redirect to the same page to prevent form resubmission
|
||||
header("Location: menu.php?id=$restaurant_id&rated=true");
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
$submit_error = "Error submitting your review. Please try again.";
|
||||
// In a real app, you'd log this error.
|
||||
}
|
||||
} else {
|
||||
$submit_error = "Please select a rating between 1 and 5.";
|
||||
}
|
||||
}
|
||||
|
||||
require_once 'header.php';
|
||||
|
||||
try {
|
||||
// Fetch restaurant details
|
||||
$stmt = db()->prepare("SELECT name, image_url, cuisine FROM restaurants WHERE id = :id");
|
||||
$stmt = db()->prepare("SELECT r.id, r.name, r.image_url, c.name as cuisine_name
|
||||
FROM restaurants r
|
||||
LEFT JOIN restaurant_cuisines rc ON r.id = rc.restaurant_id
|
||||
LEFT JOIN cuisines c ON rc.cuisine_id = c.id
|
||||
WHERE r.id = :id");
|
||||
$stmt->bindParam(':id', $restaurant_id, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$restaurant = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$restaurant_data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$restaurant_data) {
|
||||
throw new Exception("Restaurant not found.");
|
||||
}
|
||||
|
||||
$restaurant = [
|
||||
'id' => $restaurant_data[0]['id'],
|
||||
'name' => $restaurant_data[0]['name'],
|
||||
'image_url' => $restaurant_data[0]['image_url'],
|
||||
'cuisines' => array_column($restaurant_data, 'cuisine_name')
|
||||
];
|
||||
|
||||
// Fetch menu items
|
||||
$menu_stmt = db()->prepare("SELECT id, name, description, price, image_url FROM menu_items WHERE restaurant_id = :restaurant_id");
|
||||
@ -63,28 +46,45 @@ try {
|
||||
$ratings = $ratings_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$average_rating = 0;
|
||||
if (count($ratings) > 0) {
|
||||
$total_rating = 0;
|
||||
foreach ($ratings as $r) {
|
||||
$total_rating += $r['rating'];
|
||||
}
|
||||
$average_rating = round($total_rating / count($ratings), 1);
|
||||
$rating_count = count($ratings);
|
||||
if ($rating_count > 0) {
|
||||
$total_rating = array_sum(array_column($ratings, 'rating'));
|
||||
$average_rating = round($total_rating / $rating_count, 1);
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
echo "<div class='container'><p class='alert alert-danger'>Error fetching restaurant data.</p></div>";
|
||||
// Check if this restaurant is a favorite for the current user
|
||||
$is_favorite = false;
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
$fav_stmt = db()->prepare("SELECT COUNT(*) FROM favorite_restaurants WHERE user_id = :user_id AND restaurant_id = :restaurant_id");
|
||||
$fav_stmt->bindParam(':user_id', $_SESSION['user_id'], PDO::PARAM_INT);
|
||||
$fav_stmt->bindParam(':restaurant_id', $restaurant_id, PDO::PARAM_INT);
|
||||
$fav_stmt->execute();
|
||||
$is_favorite = $fav_stmt->fetchColumn() > 0;
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "<div class='container'><p class='alert alert-danger'>" . $e->getMessage() . "</p></div>";
|
||||
require_once 'footer.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<div class="container mt-5">
|
||||
<?php if ($restaurant): ?>
|
||||
<div class="row mb-4 align-items-center">
|
||||
<div class="col-md-8">
|
||||
<h1 class="display-4"><?php echo htmlspecialchars($restaurant['name']); ?></h1>
|
||||
<p class="lead text-muted"><?php echo htmlspecialchars($restaurant['cuisine']); ?></p>
|
||||
<div class="d-flex align-items-center">
|
||||
<h1 class="display-4 mb-0"><?php echo htmlspecialchars($restaurant['name']); ?></h1>
|
||||
<?php if (isset($_SESSION['user_id'])) : ?>
|
||||
<form action="toggle_favorite.php" method="post" class="ms-4">
|
||||
<input type="hidden" name="restaurant_id" value="<?php echo $restaurant_id; ?>">
|
||||
<button type="submit" class="btn <?php echo $is_favorite ? 'btn-danger' : 'btn-outline-danger'; ?>">
|
||||
<?php echo $is_favorite ? '♥ Remove from Favorites' : '♡ Add to Favorites'; ?>
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<p class="lead text-muted"><?php echo htmlspecialchars(implode(', ', $restaurant['cuisines'])); ?></p>
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="h4 text-warning me-2"><?php echo $average_rating; ?> ★</span>
|
||||
<span class="text-muted">(<?php echo count($ratings); ?> reviews)</span>
|
||||
@ -138,39 +138,17 @@ try {
|
||||
<div class="col-lg-8 mx-auto">
|
||||
<h2 class="mb-4">Reviews & Ratings</h2>
|
||||
|
||||
<?php if (isset($_SESSION['user_id'])): ?>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Leave a Review</div>
|
||||
<div class="card-body">
|
||||
<?php if (isset($submit_error)): ?>
|
||||
<div class="alert alert-danger"><?php echo $submit_error; ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($_GET['rated']) && $_GET['rated'] == 'true'): ?>
|
||||
<div class="alert alert-success">Thank you for your review!</div>
|
||||
<?php endif; ?>
|
||||
<form action="menu.php?id=<?php echo $restaurant_id; ?>" method="post">
|
||||
<div class="mb-3">
|
||||
<label for="rating" class="form-label">Your Rating</label>
|
||||
<select class="form-select" id="rating" name="rating" required>
|
||||
<option value="" disabled selected>Choose a rating...</option>
|
||||
<option value="5">5 - Excellent</option>
|
||||
<option value="4">4 - Very Good</option>
|
||||
<option value="3">3 - Good</option>
|
||||
<option value="2">2 - Fair</option>
|
||||
<option value="1">1 - Poor</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="review" class="form-label">Your Review</label>
|
||||
<textarea class="form-control" id="review" name="review" rows="3" placeholder="What did you think?"></textarea>
|
||||
</div>
|
||||
<button type="submit" name="submit_review" class="btn btn-success">Submit Review</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php if (isset($_SESSION['user_id']) && $rating_count > 0): ?>
|
||||
<div class="alert alert-light">
|
||||
You have already reviewed this restaurant.
|
||||
</div>
|
||||
<?php elseif (isset($_SESSION['user_id'])): ?>
|
||||
<div class="alert alert-info">
|
||||
<a href="leave_review.php?order_id=ORDER_ID_PLACEHOLDER">Leave a review</a> for a completed order.
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="alert alert-info">
|
||||
<a href="login.php?redirect_url=<?php echo urlencode($_SERVER['REQUEST_URI']); ?>">Log in</a> to leave a review.
|
||||
<a href="login.php?redirect_url=<?php echo urlencode($_SERVER['REQUEST_URI']); ?>">Log in</a> to see reviews or leave your own.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
6
migrations/20251015_add_promotion_id_to_menu_items.sql
Normal file
6
migrations/20251015_add_promotion_id_to_menu_items.sql
Normal file
@ -0,0 +1,6 @@
|
||||
ALTER TABLE menu_items
|
||||
ADD COLUMN promotion_id INT,
|
||||
ADD CONSTRAINT fk_promotion
|
||||
FOREIGN KEY(promotion_id)
|
||||
REFERENCES special_promotions(id)
|
||||
ON DELETE SET NULL;
|
||||
10
migrations/20251015_create_driver_assignments_table.sql
Normal file
10
migrations/20251015_create_driver_assignments_table.sql
Normal file
@ -0,0 +1,10 @@
|
||||
CREATE TABLE IF NOT EXISTS driver_assignments (
|
||||
id SERIAL PRIMARY KEY,
|
||||
order_id INT NOT NULL,
|
||||
driver_id INT NOT NULL,
|
||||
assignment_status VARCHAR(50) NOT NULL DEFAULT 'pending', -- pending, accepted, completed
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (driver_id) REFERENCES drivers(id) ON DELETE CASCADE
|
||||
);
|
||||
11
migrations/20251015_create_drivers_table.sql
Normal file
11
migrations/20251015_create_drivers_table.sql
Normal file
@ -0,0 +1,11 @@
|
||||
CREATE TABLE IF NOT EXISTS drivers (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
full_name VARCHAR(255) NOT NULL,
|
||||
phone_number VARCHAR(255) NOT NULL,
|
||||
vehicle_details TEXT,
|
||||
approval_status VARCHAR(50) NOT NULL DEFAULT 'pending', -- pending, approved, rejected
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
@ -0,0 +1,8 @@
|
||||
CREATE TABLE IF NOT EXISTS favorite_restaurants (
|
||||
user_id INT NOT NULL,
|
||||
restaurant_id INT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (user_id, restaurant_id),
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (restaurant_id) REFERENCES restaurants(id) ON DELETE CASCADE
|
||||
);
|
||||
12
migrations/20251015_create_ratings_table_final.sql
Normal file
12
migrations/20251015_create_ratings_table_final.sql
Normal file
@ -0,0 +1,12 @@
|
||||
CREATE TABLE IF NOT EXISTS ratings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
order_id INT NOT NULL UNIQUE,
|
||||
restaurant_id INT NOT NULL,
|
||||
user_id INT NOT NULL,
|
||||
rating INT NOT NULL CHECK (rating >= 1 AND rating <= 5),
|
||||
review TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (restaurant_id) REFERENCES restaurants(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
19
migrations/20251015_create_settings_table.sql
Normal file
19
migrations/20251015_create_settings_table.sql
Normal file
@ -0,0 +1,19 @@
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
name VARCHAR(255) PRIMARY KEY,
|
||||
value VARCHAR(255)
|
||||
);
|
||||
|
||||
INSERT INTO settings (name, value) VALUES
|
||||
('service_fee_percentage', '7'),
|
||||
('delivery_fee', '1.50'),
|
||||
('driver_base_pay_tier1_miles', '3'),
|
||||
('driver_base_pay_tier1_amount', '3'),
|
||||
('driver_base_pay_tier2_miles', '5'),
|
||||
('driver_base_pay_tier2_amount', '4'),
|
||||
('driver_base_pay_tier3_amount', '5'),
|
||||
('driver_mileage_pay_rate', '0.65'),
|
||||
('driver_busy_hour_bonus', '2'),
|
||||
('driver_quest_bonus_amount', '10'),
|
||||
('driver_quest_bonus_deliveries', '10'),
|
||||
('driver_quest_bonus_hours', '2')
|
||||
ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value;
|
||||
12
migrations/20251015_create_special_promotions_table.sql
Normal file
12
migrations/20251015_create_special_promotions_table.sql
Normal file
@ -0,0 +1,12 @@
|
||||
CREATE TABLE IF NOT EXISTS special_promotions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
discount_type VARCHAR(10) NOT NULL,
|
||||
discount_value DECIMAL(10, 2) NOT NULL,
|
||||
start_date TIMESTAMP NOT NULL,
|
||||
end_date TIMESTAMP NOT NULL,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
4
migrations/20251015_update_drivers_table.sql
Normal file
4
migrations/20251015_update_drivers_table.sql
Normal file
@ -0,0 +1,4 @@
|
||||
ALTER TABLE drivers DROP CONSTRAINT IF EXISTS drivers_user_id_fkey;
|
||||
ALTER TABLE drivers DROP COLUMN IF EXISTS user_id;
|
||||
ALTER TABLE drivers ADD COLUMN IF NOT EXISTS email VARCHAR(255) NOT NULL UNIQUE;
|
||||
ALTER TABLE drivers ADD COLUMN IF NOT EXISTS password_hash VARCHAR(255) NOT NULL;
|
||||
@ -3,6 +3,8 @@ session_start();
|
||||
require_once 'db/config.php';
|
||||
include 'header.php';
|
||||
|
||||
echo '<meta http-equiv="refresh" content="30">';
|
||||
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header("Location: login.php");
|
||||
exit();
|
||||
@ -31,6 +33,11 @@ if (!$order) {
|
||||
$p_items = $db->prepare("SELECT oi.*, mi.name as item_name FROM order_items oi JOIN menu_items mi ON oi.menu_item_id = mi.id WHERE oi.order_id = ?");
|
||||
$p_items->execute([$order_id]);
|
||||
$items = $p_items->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Fetch assigned driver
|
||||
$p_driver = $db->prepare("SELECT d.full_name FROM drivers d JOIN driver_assignments da ON d.id = da.driver_id WHERE da.order_id = ?");
|
||||
$p_driver->execute([$order_id]);
|
||||
$driver = $p_driver->fetch(PDO::FETCH_ASSOC);
|
||||
?>
|
||||
|
||||
<div class="container mt-5">
|
||||
@ -43,6 +50,9 @@ $items = $p_items->fetchAll(PDO::FETCH_ASSOC);
|
||||
<p><strong>Order Date:</strong> <?php echo date("F j, Y, g:i a", strtotime($order['created_at'])); ?></p>
|
||||
<p><strong>Total:</strong> $<?php echo number_format($order['total_price'], 2); ?></p>
|
||||
<p><strong>Status:</strong> <?php echo htmlspecialchars($order['status']); ?></p>
|
||||
<?php if ($driver): ?>
|
||||
<p><strong>Driver:</strong> <?php echo htmlspecialchars($driver['full_name']); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -12,7 +12,8 @@ include 'header.php';
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$db = db();
|
||||
|
||||
$stmt = $db->prepare("SELECT * FROM orders WHERE user_id = ? ORDER BY order_date DESC");
|
||||
// Fetch user's orders
|
||||
$stmt = $db->prepare("SELECT * FROM orders WHERE user_id = ? ORDER BY created_at DESC");
|
||||
$stmt->execute([$user_id]);
|
||||
$orders = $stmt->fetchAll();
|
||||
|
||||
@ -22,6 +23,17 @@ $orders = $stmt->fetchAll();
|
||||
<h2>My Order History</h2>
|
||||
<hr>
|
||||
|
||||
<?php
|
||||
if (isset($_SESSION['success_message'])) {
|
||||
echo '<div class="alert alert-success">' . $_SESSION['success_message'] . '</div>';
|
||||
unset($_SESSION['success_message']);
|
||||
}
|
||||
if (isset($_SESSION['error_message'])) {
|
||||
echo '<div class="alert alert-danger">' . $_SESSION['error_message'] . '</div>';
|
||||
unset($_SESSION['error_message']);
|
||||
}
|
||||
?>
|
||||
|
||||
<?php if (empty($orders)): ?>
|
||||
<div class="alert alert-info">You have not placed any orders yet.</div>
|
||||
<?php else: ?>
|
||||
@ -39,12 +51,22 @@ $orders = $stmt->fetchAll();
|
||||
<?php foreach ($orders as $order): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($order['id']); ?></td>
|
||||
<td><?php echo htmlspecialchars(date('F j, Y, g:i a', strtotime($order['order_date']))); ?></td>
|
||||
<td><?php echo htmlspecialchars(date('F j, Y, g:i a', strtotime($order['created_at']))); ?></td>
|
||||
<td>$<?php echo htmlspecialchars(number_format($order['total_price'], 2)); ?></td>
|
||||
<td><?php echo htmlspecialchars(ucfirst($order['status'])); ?></td>
|
||||
<td>
|
||||
<a href="order_details.php?id=<?php echo $order['id']; ?>" class="btn btn-primary btn-sm">View Details</a>
|
||||
<a href="order_status.php?order_id=<?php echo $order['id']; ?>" class="btn btn-info btn-sm">Track Order</a>
|
||||
<a href="order_status.php?order_id=<?php echo $order['id']; ?>" class="btn btn-info btn-sm">View Details / Track</a>
|
||||
<?php
|
||||
// Check if a review has already been submitted for this order
|
||||
$stmt_rating = $db->prepare("SELECT id FROM ratings WHERE order_id = ?");
|
||||
$stmt_rating->execute([$order['id']]);
|
||||
$existing_rating = $stmt_rating->fetch();
|
||||
|
||||
// If order is delivered and no review exists, show the 'Leave a Review' link
|
||||
if ($order['status'] === 'Delivered' && !$existing_rating):
|
||||
?>
|
||||
<a href="leave_review.php?order_id=<?php echo $order['id']; ?>" class="btn btn-success btn-sm mt-1">Leave a Review</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
@ -53,4 +75,4 @@ $orders = $stmt->fetchAll();
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
<?php include 'footer.php'; ?>
|
||||
|
||||
@ -16,9 +16,10 @@ if (!isset($_GET['order_id'])) {
|
||||
|
||||
$order_id = $_GET['order_id'];
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$pdo = db();
|
||||
|
||||
// Fetch order details to ensure the user owns this order
|
||||
$p_order = $db->prepare("SELECT o.*, r.name as restaurant_name FROM orders o JOIN restaurants r ON o.restaurant_id = r.id WHERE o.id = ? AND o.user_id = ?");
|
||||
$p_order = $pdo->prepare("SELECT o.*, r.name as restaurant_name FROM orders o JOIN restaurants r ON o.restaurant_id = r.id WHERE o.id = ? AND o.user_id = ?");
|
||||
$p_order->execute([$order_id, $user_id]);
|
||||
$order = $p_order->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
@ -29,7 +30,7 @@ if (!$order) {
|
||||
}
|
||||
|
||||
// Fetch order items
|
||||
$p_items = $db->prepare("SELECT oi.*, mi.name as item_name FROM order_items oi JOIN menu_items mi ON oi.menu_item_id = mi.id WHERE oi.order_id = ?");
|
||||
$p_items = $pdo->prepare("SELECT oi.*, mi.name as item_name FROM order_items oi JOIN menu_items mi ON oi.menu_item_id = mi.id WHERE oi.order_id = ?");
|
||||
$p_items->execute([$order_id]);
|
||||
$items = $p_items->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
@ -44,7 +45,7 @@ $items = $p_items->fetchAll(PDO::FETCH_ASSOC);
|
||||
<p><strong>Restaurant:</strong> <?php echo htmlspecialchars($order['restaurant_name']); ?></p>
|
||||
<p><strong>Order Date:</strong> <?php echo date("F j, Y, g:i a", strtotime($order['created_at'])); ?></p>
|
||||
<div id="order-status-container">
|
||||
<p><strong>Status:</strong> <span class="badge bg-primary fs-6" id="order-status"><?php echo htmlspecialchars($order['status']); ?></span></p>
|
||||
<p><strong>Status:</strong> <span class="badge bg-primary fs-6" id="order-status"><?php echo htmlspecialchars(ucwords($order['status'])); ?></span></p>
|
||||
</div>
|
||||
<div class="progress" style="height: 25px;">
|
||||
<div id="progress-bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
@ -80,8 +81,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
const statusToProgress = {
|
||||
'Pending': 10,
|
||||
'In Progress': 40,
|
||||
'Out for Delivery': 75,
|
||||
'Preparing': 40,
|
||||
'Out For Delivery': 75,
|
||||
'Delivered': 100,
|
||||
'Cancelled': 0
|
||||
};
|
||||
|
||||
77
process_review.php
Normal file
77
process_review.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
// Ensure user is logged in
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
// Not logged in
|
||||
http_response_code(403);
|
||||
exit("You must be logged in to submit a review.");
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
// Not a POST request
|
||||
http_response_code(405);
|
||||
exit("Invalid request method.");
|
||||
}
|
||||
|
||||
$db = db();
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
// Get POST data
|
||||
$order_id = isset($_POST['order_id']) ? (int)$_POST['order_id'] : 0;
|
||||
$restaurant_id = isset($_POST['restaurant_id']) ? (int)$_POST['restaurant_id'] : 0;
|
||||
$rating = isset($_POST['rating']) ? (int)$_POST['rating'] : 0;
|
||||
$review = isset($_POST['review']) ? trim($_POST['review']) : '';
|
||||
|
||||
// --- Server-side validation ---
|
||||
|
||||
// 1. Basic validation
|
||||
if ($order_id <= 0 || $restaurant_id <= 0 || $rating < 1 || $rating > 5) {
|
||||
$_SESSION['error_message'] = "Invalid data provided. Please try again.";
|
||||
header("Location: leave_review.php?order_id=" . $order_id);
|
||||
exit();
|
||||
}
|
||||
|
||||
// 2. Security and integrity validation
|
||||
$stmt = $db->prepare("SELECT id, status FROM orders WHERE id = ? AND user_id = ? AND restaurant_id = ?");
|
||||
$stmt->execute([$order_id, $user_id, $restaurant_id]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
if (!$order) {
|
||||
$_SESSION['error_message'] = "You cannot review this order.";
|
||||
header("Location: order_history.php");
|
||||
exit();
|
||||
} elseif ($order['status'] !== 'Delivered') {
|
||||
$_SESSION['error_message'] = "You can only review delivered orders.";
|
||||
header("Location: leave_review.php?order_id=" . $order_id);
|
||||
exit();
|
||||
}
|
||||
|
||||
// 3. Check if a review already exists
|
||||
$stmt_rating = $db->prepare("SELECT id FROM ratings WHERE order_id = ?");
|
||||
$stmt_rating->execute([$order_id]);
|
||||
if ($stmt_rating->fetch()) {
|
||||
$_SESSION['error_message'] = "You have already reviewed this order.";
|
||||
header("Location: order_history.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// --- All checks passed, insert into database ---
|
||||
try {
|
||||
$stmt_insert = $db->prepare(
|
||||
"INSERT INTO ratings (order_id, restaurant_id, user_id, rating, review) VALUES (?, ?, ?, ?, ?)"
|
||||
);
|
||||
$stmt_insert->execute([$order_id, $restaurant_id, $user_id, $rating, $review]);
|
||||
|
||||
$_SESSION['success_message'] = "Thank you for your review!";
|
||||
header("Location: order_history.php");
|
||||
exit();
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// Log error properly in a real application
|
||||
// error_log($e->getMessage());
|
||||
$_SESSION['error_message'] = "A database error occurred. Please try again later.";
|
||||
header("Location: leave_review.php?order_id=" . $order_id);
|
||||
exit();
|
||||
}
|
||||
39
profile.php
39
profile.php
@ -56,6 +56,18 @@ $p_user = $db->prepare("SELECT * FROM users WHERE id = ?");
|
||||
$p_user->execute([$user_id]);
|
||||
$user = $p_user->fetch();
|
||||
|
||||
// Fetch favorite restaurants
|
||||
$fav_stmt = $db->prepare("
|
||||
SELECT r.id, r.name, r.image_url, c.name as cuisine_name
|
||||
FROM favorite_restaurants fr
|
||||
JOIN restaurants r ON fr.restaurant_id = r.id
|
||||
LEFT JOIN restaurant_cuisines rc ON r.id = rc.restaurant_id
|
||||
LEFT JOIN cuisines c ON rc.cuisine_id = c.id
|
||||
WHERE fr.user_id = ?
|
||||
GROUP BY r.id
|
||||
");
|
||||
$fav_stmt->execute([$user_id]);
|
||||
$favorite_restaurants = $fav_stmt->fetchAll();
|
||||
|
||||
?>
|
||||
|
||||
@ -121,6 +133,33 @@ $user = $p_user->fetch();
|
||||
<div class="mt-5">
|
||||
<a href="order_history.php" class="btn btn-secondary">View Order History</a>
|
||||
</div>
|
||||
|
||||
<div class="row mt-5">
|
||||
<div class="col-12">
|
||||
<h2>My Favorite Restaurants</h2>
|
||||
<hr>
|
||||
<?php if ($favorite_restaurants): ?>
|
||||
<div class="row">
|
||||
<?php foreach ($favorite_restaurants as $fav_restaurant): ?>
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card h-100">
|
||||
<a href="menu.php?restaurant_id=<?php echo $fav_restaurant['id']; ?>">
|
||||
<img src="<?php echo htmlspecialchars($fav_restaurant['image_url'] ? $fav_restaurant['image_url'] : 'https://via.placeholder.com/300x200'); ?>" class="card-img-top" alt="<?php echo htmlspecialchars($fav_restaurant['name']); ?>" style="height: 200px; object-fit: cover;">
|
||||
</a>
|
||||
<div class="card-body d-flex flex-column">
|
||||
<h5 class="card-title"><?php echo htmlspecialchars($fav_restaurant['name']); ?></h5>
|
||||
<p class="card-text text-muted"><?php echo htmlspecialchars($fav_restaurant['cuisine_name']); ?></p>
|
||||
<a href="menu.php?restaurant_id=<?php echo $fav_restaurant['id']; ?>" class="btn btn-primary mt-auto">View Menu</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<p>You haven't added any favorite restaurants yet. <a href="index.php">Explore restaurants</a> to find some!</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
@ -26,16 +26,22 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = $_POST['name'] ?? '';
|
||||
$description = $_POST['description'] ?? '';
|
||||
$price = $_POST['price'] ?? '';
|
||||
$promotion_id = $_POST['promotion_id'] ?? null;
|
||||
|
||||
if ($name && $price) {
|
||||
$stmt = $pdo->prepare("INSERT INTO menu_items (restaurant_id, name, description, price) VALUES (?, ?, ?, ?)");
|
||||
$stmt->execute([$restaurant_id, $name, $description, $price]);
|
||||
$stmt = $pdo->prepare("INSERT INTO menu_items (restaurant_id, name, description, price, promotion_id) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$restaurant_id, $name, $description, $price, $promotion_id]);
|
||||
header('Location: menu.php');
|
||||
exit;
|
||||
} else {
|
||||
$error = "Name and price are required.";
|
||||
}
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM special_promotions");
|
||||
$stmt->execute();
|
||||
$promotions = $stmt->fetchAll();
|
||||
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
@ -58,6 +64,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
<label for="price" class="form-label">Price</label>
|
||||
<input type="number" step="0.01" class="form-control" id="price" name="price" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="promotion_id" class="form-label">Promotion</label>
|
||||
<select class="form-control" id="promotion_id" name="promotion_id">
|
||||
<option value="">None</option>
|
||||
<?php foreach ($promotions as $promotion): ?>
|
||||
<option value="<?= $promotion['id'] ?>"><?= htmlspecialchars($promotion['name']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Add Item</button>
|
||||
<a href="menu.php" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
|
||||
61
restaurant/add_promotion.php
Normal file
61
restaurant/add_promotion.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
require_once 'header.php';
|
||||
require_once '../db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = $_POST['name'];
|
||||
$description = $_POST['description'];
|
||||
$discount_type = $_POST['discount_type'];
|
||||
$discount_value = $_POST['discount_value'];
|
||||
$start_date = $_POST['start_date'];
|
||||
$end_date = $_POST['end_date'];
|
||||
$is_active = isset($_POST['is_active']) ? 1 : 0;
|
||||
|
||||
$stmt = db()->prepare("INSERT INTO special_promotions (name, description, discount_type, discount_value, start_date, end_date, is_active) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$name, $description, $discount_type, $discount_value, $start_date, $end_date, $is_active]);
|
||||
|
||||
header('Location: promotions.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<h2>Add Promotion</h2>
|
||||
<form method="post">
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description">Description</label>
|
||||
<textarea class="form-control" id="description" name="description"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="discount_type">Discount Type</label>
|
||||
<select class="form-control" id="discount_type" name="discount_type">
|
||||
<option value="percentage">Percentage</option>
|
||||
<option value="fixed">Fixed</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="discount_value">Discount Value</label>
|
||||
<input type="number" class="form-control" id="discount_value" name="discount_value" step="0.01" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="start_date">Start Date</label>
|
||||
<input type="datetime-local" class="form-control" id="start_date" name="start_date" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="end_date">End Date</label>
|
||||
<input type="datetime-local" class="form-control" id="end_date" name="end_date" required>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="is_active" name="is_active" value="1" checked>
|
||||
<label class="form-check-label" for="is_active">Active</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Add Promotion</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php require_once 'footer.php'; ?>
|
||||
16
restaurant/delete_promotion.php
Normal file
16
restaurant/delete_promotion.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
require_once '../db/config.php';
|
||||
|
||||
$promotion_id = $_GET['id'];
|
||||
|
||||
// First, update menu_items to remove the promotion_id
|
||||
$stmt = db()->prepare("UPDATE menu_items SET promotion_id = NULL WHERE promotion_id = ?");
|
||||
$stmt->execute([$promotion_id]);
|
||||
|
||||
// Then, delete the promotion
|
||||
$stmt = db()->prepare("DELETE FROM special_promotions WHERE id = ?");
|
||||
$stmt->execute([$promotion_id]);
|
||||
|
||||
header('Location: promotions.php');
|
||||
exit;
|
||||
?>
|
||||
@ -42,16 +42,22 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = $_POST['name'] ?? '';
|
||||
$description = $_POST['description'] ?? '';
|
||||
$price = $_POST['price'] ?? '';
|
||||
$promotion_id = $_POST['promotion_id'] ?? null;
|
||||
|
||||
if ($name && $price) {
|
||||
$stmt = $pdo->prepare("UPDATE menu_items SET name = ?, description = ?, price = ? WHERE id = ? AND restaurant_id = ?");
|
||||
$stmt->execute([$name, $description, $price, $menu_item_id, $restaurant_id]);
|
||||
$stmt = $pdo->prepare("UPDATE menu_items SET name = ?, description = ?, price = ?, promotion_id = ? WHERE id = ? AND restaurant_id = ?");
|
||||
$stmt->execute([$name, $description, $price, $promotion_id, $menu_item_id, $restaurant_id]);
|
||||
header('Location: menu.php');
|
||||
exit;
|
||||
} else {
|
||||
$error = "Name and price are required.";
|
||||
}
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM special_promotions");
|
||||
$stmt->execute();
|
||||
$promotions = $stmt->fetchAll();
|
||||
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
@ -74,6 +80,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
<label for="price" class="form-label">Price</label>
|
||||
<input type="number" step="0.01" class="form-control" id="price" name="price" value="<?php echo htmlspecialchars($item['price']); ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="promotion_id" class="form-label">Promotion</label>
|
||||
<select class="form-control" id="promotion_id" name="promotion_id">
|
||||
<option value="">None</option>
|
||||
<?php foreach ($promotions as $promotion): ?>
|
||||
<option value="<?= $promotion['id'] ?>" <?= $item['promotion_id'] == $promotion['id'] ? 'selected' : '' ?>><?= htmlspecialchars($promotion['name']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Update Item</button>
|
||||
<a href="menu.php" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
|
||||
67
restaurant/edit_promotion.php
Normal file
67
restaurant/edit_promotion.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
require_once 'header.php';
|
||||
require_once '../db/config.php';
|
||||
|
||||
$promotion_id = $_GET['id'];
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = $_POST['name'];
|
||||
$description = $_POST['description'];
|
||||
$discount_type = $_POST['discount_type'];
|
||||
$discount_value = $_POST['discount_value'];
|
||||
$start_date = $_POST['start_date'];
|
||||
$end_date = $_POST['end_date'];
|
||||
$is_active = isset($_POST['is_active']) ? 1 : 0;
|
||||
|
||||
$stmt = db()->prepare("UPDATE special_promotions SET name = ?, description = ?, discount_type = ?, discount_value = ?, start_date = ?, end_date = ?, is_active = ? WHERE id = ?");
|
||||
$stmt->execute([$name, $description, $discount_type, $discount_value, $start_date, $end_date, $is_active, $promotion_id]);
|
||||
|
||||
header('Location: promotions.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = db()->prepare("SELECT * FROM special_promotions WHERE id = ?");
|
||||
$stmt->execute([$promotion_id]);
|
||||
$promotion = $stmt->fetch();
|
||||
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<h2>Edit Promotion</h2>
|
||||
<form method="post">
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" class="form-control" id="name" name="name" value="<?= htmlspecialchars($promotion['name']) ?>" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description">Description</label>
|
||||
<textarea class="form-control" id="description" name="description"><?= htmlspecialchars($promotion['description']) ?></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="discount_type">Discount Type</label>
|
||||
<select class="form-control" id="discount_type" name="discount_type">
|
||||
<option value="percentage" <?= $promotion['discount_type'] == 'percentage' ? 'selected' : '' ?>>Percentage</option>
|
||||
<option value="fixed" <?= $promotion['discount_type'] == 'fixed' ? 'selected' : '' ?>>Fixed</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="discount_value">Discount Value</label>
|
||||
<input type="number" class="form-control" id="discount_value" name="discount_value" step="0.01" value="<?= htmlspecialchars($promotion['discount_value']) ?>" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="start_date">Start Date</label>
|
||||
<input type="datetime-local" class="form-control" id="start_date" name="start_date" value="<?= date('Y-m-d\TH:i', strtotime($promotion['start_date'])) ?>" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="end_date">End Date</label>
|
||||
<input type="datetime-local" class="form-control" id="end_date" name="end_date" value="<?= date('Y-m-d\TH:i', strtotime($promotion['end_date'])) ?>" required>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="is_active" name="is_active" value="1" <?= $promotion['is_active'] ? 'checked' : '' ?>>
|
||||
<label class="form-check-label" for="is_active">Active</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Update Promotion</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php require_once 'footer.php'; ?>
|
||||
@ -31,6 +31,9 @@ if (!isset($_SESSION['user_role']) || $_SESSION['user_role'] !== 'restaurant_own
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="orders.php">Orders</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="promotions.php">Promotions</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
|
||||
47
restaurant/promotions.php
Normal file
47
restaurant/promotions.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
require_once 'header.php';
|
||||
require_once '../db/config.php';
|
||||
|
||||
// Fetch promotions for the logged-in restaurant owner
|
||||
$restaurant_id = $_SESSION['restaurant_id'];
|
||||
$stmt = db()->prepare("SELECT sp.* FROM special_promotions sp JOIN menu_items mi ON sp.id = mi.promotion_id JOIN restaurants r ON mi.restaurant_id = r.id WHERE r.id = ?");
|
||||
$stmt->execute([$restaurant_id]);
|
||||
$promotions = $stmt->fetchAll();
|
||||
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<h2>Manage Promotions</h2>
|
||||
<a href="add_promotion.php" class="btn btn-primary mb-3">Add Promotion</a>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Discount</th>
|
||||
<th>Start Date</th>
|
||||
<th>End Date</th>
|
||||
<th>Active</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($promotions as $promotion): ?>
|
||||
<tr>
|
||||
<td><?= htmlspecialchars($promotion['name']) ?></td>
|
||||
<td><?= htmlspecialchars($promotion['description']) ?></td>
|
||||
<td><?= htmlspecialchars($promotion['discount_value']) ?> <?= $promotion['discount_type'] == 'percentage' ? '%' : '' ?></td>
|
||||
<td><?= htmlspecialchars($promotion['start_date']) ?></td>
|
||||
<td><?= htmlspecialchars($promotion['end_date']) ?></td>
|
||||
<td><?= $promotion['is_active'] ? 'Yes' : 'No' ?></td>
|
||||
<td>
|
||||
<a href="edit_promotion.php?id=<?= $promotion['id'] ?>" class="btn btn-sm btn-info">Edit</a>
|
||||
<a href="delete_promotion.php?id=<?= $promotion['id'] ?>" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure?')">Delete</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<?php require_once 'footer.php'; ?>
|
||||
57
toggle_favorite.php
Normal file
57
toggle_favorite.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
// Check if the user is logged in
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
// Redirect to login page if not logged in
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Check if the request method is POST
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Get the restaurant ID from the POST data
|
||||
$restaurant_id = isset($_POST['restaurant_id']) ? (int)$_POST['restaurant_id'] : 0;
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
if ($restaurant_id > 0) {
|
||||
try {
|
||||
$db = db();
|
||||
|
||||
// Check if the restaurant is already a favorite
|
||||
$stmt = $db->prepare("SELECT COUNT(*) FROM favorite_restaurants WHERE user_id = :user_id AND restaurant_id = :restaurant_id");
|
||||
$stmt->bindParam(':user_id', $user_id, PDO::PARAM_INT);
|
||||
$stmt->bindParam(':restaurant_id', $restaurant_id, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$is_favorite = $stmt->fetchColumn() > 0;
|
||||
|
||||
if ($is_favorite) {
|
||||
// Remove from favorites
|
||||
$delete_stmt = $db->prepare("DELETE FROM favorite_restaurants WHERE user_id = :user_id AND restaurant_id = :restaurant_id");
|
||||
$delete_stmt->bindParam(':user_id', $user_id, PDO::PARAM_INT);
|
||||
$delete_stmt->bindParam(':restaurant_id', $restaurant_id, PDO::PARAM_INT);
|
||||
$delete_stmt->execute();
|
||||
$_SESSION['alert'] = ['type' => 'success', 'message' => 'Restaurant removed from your favorites.'];
|
||||
} else {
|
||||
// Add to favorites
|
||||
$insert_stmt = $db->prepare("INSERT INTO favorite_restaurants (user_id, restaurant_id) VALUES (:user_id, :restaurant_id)");
|
||||
$insert_stmt->bindParam(':user_id', $user_id, PDO::PARAM_INT);
|
||||
$insert_stmt->bindParam(':restaurant_id', $restaurant_id, PDO::PARAM_INT);
|
||||
$insert_stmt->execute();
|
||||
$_SESSION['alert'] = ['type' => 'success', 'message' => 'Restaurant added to your favorites!'];
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
// Handle database errors
|
||||
$_SESSION['alert'] = ['type' => 'danger', 'message' => 'Database error: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect back to the menu page
|
||||
header('Location: menu.php?restaurant_id=' . $restaurant_id);
|
||||
exit;
|
||||
} else {
|
||||
// If not a POST request, redirect to the homepage
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user