V20
This commit is contained in:
parent
42cfa7481c
commit
2be0d2d4c4
@ -40,6 +40,9 @@ if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== tru
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="settings.php">Settings</a>
|
<a class="nav-link" href="settings.php">Settings</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="notification_emails.php">Notification Emails</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="navbar-nav ms-auto">
|
<ul class="navbar-nav ms-auto">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
|
|||||||
118
admin/notification_emails.php
Normal file
118
admin/notification_emails.php
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<?php
|
||||||
|
require_once '../db/config.php';
|
||||||
|
require_once 'header.php';
|
||||||
|
|
||||||
|
$db = db();
|
||||||
|
|
||||||
|
// Handle form submissions
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
if (isset($_POST['add_email'])) {
|
||||||
|
$email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
|
||||||
|
$form_type = $_POST['form_type'];
|
||||||
|
if (filter_var($email, FILTER_VALIDATE_EMAIL) && in_array($form_type, ['help', 'driver_signup'])) {
|
||||||
|
try {
|
||||||
|
$stmt = $db->prepare("INSERT INTO email_recipients (email, form_type) VALUES (?, ?)");
|
||||||
|
$stmt->execute([$email, $form_type]);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// Ignore unique constraint violations
|
||||||
|
if ($e->getCode() !== '23505') {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif (isset($_POST['delete_email'])) {
|
||||||
|
$id = $_POST['id'];
|
||||||
|
$stmt = $db->prepare("DELETE FROM email_recipients WHERE id = ?");
|
||||||
|
$stmt->execute([$id]);
|
||||||
|
}
|
||||||
|
// Redirect to the same page to prevent form resubmission
|
||||||
|
header("Location: notification_emails.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch existing emails
|
||||||
|
$stmt = $db->query("SELECT * FROM email_recipients ORDER BY form_type, email");
|
||||||
|
$recipients = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$help_recipients = array_filter($recipients, function($r) { return $r['form_type'] === 'help'; });
|
||||||
|
$driver_recipients = array_filter($recipients, function($r) { return $r['form_type'] === 'driver_signup'; });
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="container mt-4">
|
||||||
|
<h2>Notification Email Recipients</h2>
|
||||||
|
<p>Configure the email addresses that receive notifications when users submit the help or driver signup forms.</p>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
Help Form Recipients
|
||||||
|
</div>
|
||||||
|
<ul class="list-group list-group-flush">
|
||||||
|
<?php if (empty($help_recipients)): ?>
|
||||||
|
<li class="list-group-item text-muted">No recipients configured. Emails will be sent to the default address.</li>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($help_recipients as $recipient): ?>
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<?php echo htmlspecialchars($recipient['email']); ?>
|
||||||
|
<form method="POST" action="notification_emails.php" class="m-0">
|
||||||
|
<input type="hidden" name="id" value="<?php echo $recipient['id']; ?>">
|
||||||
|
<button type="submit" name="delete_email" class="btn btn-danger btn-sm">×</button>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
Driver Signup Form Recipients
|
||||||
|
</div>
|
||||||
|
<ul class="list-group list-group-flush">
|
||||||
|
<?php if (empty($driver_recipients)): ?>
|
||||||
|
<li class="list-group-item text-muted">No recipients configured. Emails will be sent to the default address.</li>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($driver_recipients as $recipient): ?>
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<?php echo htmlspecialchars($recipient['email']); ?>
|
||||||
|
<form method="POST" action="notification_emails.php" class="m-0">
|
||||||
|
<input type="hidden" name="id" value="<?php echo $recipient['id']; ?>">
|
||||||
|
<button type="submit" name="delete_email" class="btn btn-danger btn-sm">×</button>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card mt-4">
|
||||||
|
<div class="card-header">
|
||||||
|
Add New Recipient
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="POST" action="notification_emails.php" class="row g-3 align-items-end">
|
||||||
|
<div class="col-md-5">
|
||||||
|
<label for="email" class="form-label">Email address</label>
|
||||||
|
<input type="email" class="form-control" id="email" name="email" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-5">
|
||||||
|
<label for="form_type" class="form-label">Form Type</label>
|
||||||
|
<select class="form-select" id="form_type" name="form_type">
|
||||||
|
<option value="help">Help Form</option>
|
||||||
|
<option value="driver_signup">Driver Signup Form</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<button type="submit" name="add_email" class="btn btn-primary w-100">Add</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
@ -23,7 +23,10 @@ MajuroEats Theme
|
|||||||
/* --- Global Styles --- */
|
/* --- Global Styles --- */
|
||||||
body {
|
body {
|
||||||
font-family: var(--font-family);
|
font-family: var(--font-family);
|
||||||
background-color: var(--sand);
|
background-image: url('../assets/pasted-20251016-135055-b29d8da1.png');
|
||||||
|
background-size: cover;
|
||||||
|
background-attachment: fixed;
|
||||||
|
background-position: center;
|
||||||
color: var(--text-dark);
|
color: var(--text-dark);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-top: 80px; /* Space for fixed header */
|
padding-top: 80px; /* Space for fixed header */
|
||||||
@ -60,11 +63,25 @@ main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
font-size: 2.5rem;
|
font-size: 2.8rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 40px;
|
margin-bottom: 50px;
|
||||||
color: var(--text-dark);
|
color: var(--text-dark);
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 80px;
|
||||||
|
height: 4px;
|
||||||
|
background-color: var(--coral);
|
||||||
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Navigation Bar --- */
|
/* --- Navigation Bar --- */
|
||||||
@ -172,7 +189,7 @@ main {
|
|||||||
/* --- Hero Section --- */
|
/* --- Hero Section --- */
|
||||||
.hero-section {
|
.hero-section {
|
||||||
position: relative;
|
position: relative;
|
||||||
background-image: url('../assets/pasted-20251016-062926-8620c9e4.jpg');
|
background-image: url('../assets/pasted-20251016-083643-5429546d.jpg');
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
color: var(--coconut-white);
|
color: var(--coconut-white);
|
||||||
@ -186,8 +203,7 @@ main {
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: linear-gradient(45deg, var(--orange), var(--coral));
|
background: rgba(0, 0, 0, 0.5);
|
||||||
opacity: 0.85;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-content-container {
|
.hero-content-container {
|
||||||
@ -196,65 +212,59 @@ main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hero-content h1 {
|
.hero-content h1 {
|
||||||
font-size: 3.5rem;
|
font-size: 3.8rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
margin: 0 0 15px;
|
margin: 0 0 15px;
|
||||||
text-shadow: 0 3px 10px rgba(0,0,0,0.2);
|
text-shadow: 0 3px 10px rgba(0,0,0,0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-content p {
|
.hero-content p {
|
||||||
font-size: 1.25rem;
|
font-size: 1.3rem;
|
||||||
margin: 0 0 30px;
|
margin: 0 auto 40px;
|
||||||
opacity: 0.9;
|
opacity: 0.95;
|
||||||
|
max-width: 600px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.location-actions {
|
.hero-search-form {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 20px;
|
margin: 30px auto;
|
||||||
margin-bottom: 20px;
|
box-shadow: var(--shadow-medium);
|
||||||
|
border-radius: 50px;
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: 600px;
|
||||||
|
background-color: var(--coconut-white);
|
||||||
|
border: 3px solid var(--coconut-white);
|
||||||
}
|
}
|
||||||
|
|
||||||
.location-button {
|
#address-input {
|
||||||
padding: 15px 30px;
|
flex-grow: 1;
|
||||||
border-radius: 50px;
|
border: none;
|
||||||
font-weight: 700;
|
padding: 20px;
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
border: 2px solid var(--coconut-white);
|
font-family: var(--font-family);
|
||||||
|
color: var(--text-dark);
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#address-input:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#find-food-btn {
|
||||||
|
background-color: var(--coral);
|
||||||
|
color: var(--coconut-white);
|
||||||
|
border: none;
|
||||||
|
padding: 0 40px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 700;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: var(--transition);
|
transition: var(--transition);
|
||||||
}
|
|
||||||
|
|
||||||
.location-button.primary {
|
|
||||||
background-color: var(--coconut-white);
|
|
||||||
color: var(--coral);
|
|
||||||
}
|
|
||||||
|
|
||||||
.location-button.primary:hover {
|
|
||||||
background-color: transparent;
|
|
||||||
color: var(--coconut-white);
|
|
||||||
}
|
|
||||||
|
|
||||||
.location-button.secondary {
|
|
||||||
background-color: transparent;
|
|
||||||
color: var(--coconut-white);
|
|
||||||
}
|
|
||||||
|
|
||||||
.location-button.secondary:hover {
|
|
||||||
background-color: var(--coconut-white);
|
|
||||||
color: var(--coral);
|
|
||||||
}
|
|
||||||
|
|
||||||
.find-restaurants-btn {
|
|
||||||
display: inline-block;
|
|
||||||
background-color: var(--palm-green);
|
|
||||||
color: var(--coconut-white);
|
|
||||||
padding: 18px 40px;
|
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
font-size: 1.2rem;
|
}
|
||||||
font-weight: 800;
|
|
||||||
margin-bottom: 20px;
|
#find-food-btn:hover {
|
||||||
box-shadow: var(--shadow-medium);
|
background-color: var(--orange);
|
||||||
}
|
}
|
||||||
|
|
||||||
.delivery-note {
|
.delivery-note {
|
||||||
@ -315,11 +325,13 @@ main {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: var(--transition);
|
transition: var(--transition);
|
||||||
color: var(--text-dark);
|
color: var(--text-dark);
|
||||||
|
border: 2px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.restaurant-card:hover {
|
.restaurant-card:hover {
|
||||||
transform: translateY(-10px);
|
transform: translateY(-10px);
|
||||||
box-shadow: var(--shadow-medium);
|
box-shadow: var(--shadow-medium);
|
||||||
|
border-color: var(--coral);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-image {
|
.card-image {
|
||||||
@ -576,12 +588,11 @@ main {
|
|||||||
height: 180px;
|
height: 180px;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
filter: brightness(0.7);
|
|
||||||
transition: var(--transition);
|
transition: var(--transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cuisine-card:hover .card-image {
|
.cuisine-card:hover .card-image {
|
||||||
filter: brightness(0.9);
|
transform: scale(1.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cuisine-card-content {
|
.cuisine-card-content {
|
||||||
@ -591,7 +602,7 @@ main {
|
|||||||
padding: 20px;
|
padding: 20px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background: linear-gradient(to top, rgba(0,0,0,0.7), transparent);
|
background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cuisine-card-content h3 {
|
.cuisine-card-content h3 {
|
||||||
@ -600,3 +611,59 @@ main {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
text-shadow: 0 2px 5px rgba(0,0,0,0.4);
|
text-shadow: 0 2px 5px rgba(0,0,0,0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- Restaurants Page --- */
|
||||||
|
.filter-bar {
|
||||||
|
background-color: var(--sand);
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
margin-bottom: 40px;
|
||||||
|
box-shadow: var(--shadow-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .form-control, .filter-bar .form-select {
|
||||||
|
border-radius: 50px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar .btn-primary {
|
||||||
|
background-color: var(--coral);
|
||||||
|
border-color: var(--coral);
|
||||||
|
border-radius: 50px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.restaurant-card .card-img-top {
|
||||||
|
height: 200px;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.restaurant-card .card-body {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.restaurant-card .card-title {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
font-weight: 800;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.restaurant-card .card-text {
|
||||||
|
color: var(--text-light);
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.restaurant-card .btn-outline-primary {
|
||||||
|
border-color: var(--coral);
|
||||||
|
color: var(--coral);
|
||||||
|
border-radius: 50px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.restaurant-card .btn-outline-primary:hover {
|
||||||
|
background-color: var(--coral);
|
||||||
|
color: var(--coconut-white);
|
||||||
|
}
|
||||||
|
|||||||
BIN
assets/pasted-20251016-083643-5429546d.jpg
Normal file
BIN
assets/pasted-20251016-083643-5429546d.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 779 KiB |
BIN
assets/pasted-20251016-133832-d50b8707.png
Normal file
BIN
assets/pasted-20251016-133832-d50b8707.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.0 KiB |
BIN
assets/pasted-20251016-135055-b29d8da1.png
Normal file
BIN
assets/pasted-20251016-135055-b29d8da1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 119 KiB |
@ -34,6 +34,31 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
|||||||
$stmt = $pdo->prepare($sql);
|
$stmt = $pdo->prepare($sql);
|
||||||
|
|
||||||
if ($stmt->execute([$full_name, $email, $password_hash, $phone_number, $vehicle_details])) {
|
if ($stmt->execute([$full_name, $email, $password_hash, $phone_number, $vehicle_details])) {
|
||||||
|
// Send email notification to admins
|
||||||
|
require_once __DIR__ . '/mail/MailService.php';
|
||||||
|
|
||||||
|
$stmt_emails = $pdo->prepare("SELECT email FROM email_recipients WHERE form_type = ?");
|
||||||
|
$stmt_emails->execute(['driver_signup']);
|
||||||
|
$recipients = $stmt_emails->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
|
if (!empty($recipients)) {
|
||||||
|
$subject = 'New Driver Signup: ' . $full_name;
|
||||||
|
$html_content = "<p>A new driver has signed up and is awaiting approval.</p>" .
|
||||||
|
"<p><strong>Name:</strong> {$full_name}</p>" .
|
||||||
|
"<p><strong>Email:</strong> {$email}</p>" .
|
||||||
|
"<p><strong>Phone:</strong> {$phone_number}</p>" .
|
||||||
|
"<p><strong>Vehicle:</strong> {$vehicle_details}</p>" .
|
||||||
|
"<p>Please visit the admin panel to review and approve the application.</p>";
|
||||||
|
$text_content = "A new driver has signed up and is awaiting approval.\n\n" .
|
||||||
|
"Name: {$full_name}\n" .
|
||||||
|
"Email: {$email}\n" .
|
||||||
|
"Phone: {$phone_number}\n" .
|
||||||
|
"Vehicle: {$vehicle_details}\n\n" .
|
||||||
|
"Please visit the admin panel to review and approve the application.";
|
||||||
|
|
||||||
|
MailService::sendMail($recipients, $subject, $html_content, $text_content);
|
||||||
|
}
|
||||||
|
|
||||||
// Redirect to a pending approval page
|
// Redirect to a pending approval page
|
||||||
header("Location: driver_pending_approval.php");
|
header("Location: driver_pending_approval.php");
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@ -25,8 +25,8 @@ session_start();
|
|||||||
<span class="logo-text">MajuroEats</span>
|
<span class="logo-text">MajuroEats</span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="nav-links">
|
<ul class="nav-links">
|
||||||
<li><a href="/">Home</a></li>
|
<li><a href="index.php">Home</a></li>
|
||||||
<li><a href="index.php">Restaurants</a></li>
|
<li><a href="restaurants.php">Restaurants</a></li>
|
||||||
<li><a href="rewards.php">Rewards</a></li>
|
<li><a href="rewards.php">Rewards</a></li>
|
||||||
<li><a href="driver_signup.php">Driver</a></li>
|
<li><a href="driver_signup.php">Driver</a></li>
|
||||||
<li><a href="help.php">Help</a></li>
|
<li><a href="help.php">Help</a></li>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
session_start();
|
session_start();
|
||||||
require_once __DIR__ . '/mail/MailService.php';
|
require_once __DIR__ . '/mail/MailService.php';
|
||||||
|
require_once __DIR__ . '/db/config.php';
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$name = trim($_POST['name'] ?? '');
|
$name = trim($_POST['name'] ?? '');
|
||||||
@ -24,8 +25,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$html_content = "<p><strong>Name:</strong> {$name}</p>\n <p><strong>Email:</strong> {$email}</p>\n <p><strong>Phone:</strong> {$phone}</p>\n <p><strong>Message:</strong></p>\n <p>{$message}</p>";
|
$html_content = "<p><strong>Name:</strong> {$name}</p>\n <p><strong>Email:</strong> {$email}</p>\n <p><strong>Phone:</strong> {$phone}</p>\n <p><strong>Message:</strong></p>\n <p>{$message}</p>";
|
||||||
$text_content = "Name: {$name}\nEmail: {$email}\nPhone: {$phone}\nMessage:\n{$message}";
|
$text_content = "Name: {$name}\nEmail: {$email}\nPhone: {$phone}\nMessage:\n{$message}";
|
||||||
|
|
||||||
// The recipient's email address. Using environment variable or a default.
|
$db = db();
|
||||||
|
$stmt = $db->prepare("SELECT email FROM email_recipients WHERE form_type = ?");
|
||||||
|
$stmt->execute(['help']);
|
||||||
|
$recipients = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
|
if (!empty($recipients)) {
|
||||||
|
$to = $recipients;
|
||||||
|
} else {
|
||||||
$to = getenv('MAIL_TO') ?: 'support@majuroeats.com';
|
$to = getenv('MAIL_TO') ?: 'support@majuroeats.com';
|
||||||
|
}
|
||||||
|
|
||||||
$result = MailService::sendMail($to, $subject, $html_content, $text_content, ['reply_to' => $email]);
|
$result = MailService::sendMail($to, $subject, $html_content, $text_content, ['reply_to' => $email]);
|
||||||
|
|
||||||
|
|||||||
11
hero.php
11
hero.php
@ -2,13 +2,12 @@
|
|||||||
<div class="hero-overlay"></div>
|
<div class="hero-overlay"></div>
|
||||||
<div class="container hero-content-container">
|
<div class="container hero-content-container">
|
||||||
<div class="hero-content">
|
<div class="hero-content">
|
||||||
<h1>Fast Island Delivery — From Rita to Laura!</h1>
|
<h1>Your favorite local food, delivered.</h1>
|
||||||
<p>Get your favorite meals delivered anywhere on Majuro Island.</p>
|
<p>Enter your address to find restaurants near you.</p>
|
||||||
<div class="location-actions">
|
<div class="hero-search-form">
|
||||||
<button class="location-button primary" id="pin-location-btn">📍 Pin Your Location</button>
|
<input type="text" id="address-input" placeholder="Enter your delivery address">
|
||||||
<button class="location-button secondary" id="use-location-btn">Use Current Location</button>
|
<button id="find-food-btn">Find Food</button>
|
||||||
</div>
|
</div>
|
||||||
<a href="index.php" class="find-restaurants-btn">Find Restaurants</a>
|
|
||||||
<p class="delivery-note">MajuroEats delivers only within the main island zone (Rita–Laura).</p>
|
<p class="delivery-note">MajuroEats delivers only within the main island zone (Rita–Laura).</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
7
migrations/20251016_create_email_recipients_table.sql
Normal file
7
migrations/20251016_create_email_recipients_table.sql
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS email_recipients (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
email VARCHAR(255) NOT NULL,
|
||||||
|
form_type VARCHAR(50) NOT NULL,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE (email, form_type)
|
||||||
|
);
|
||||||
115
restaurants.php
Normal file
115
restaurants.php
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'header.php';
|
||||||
|
|
||||||
|
// Fetch all cuisines for the filter dropdown
|
||||||
|
$cuisines_stmt = db()->query("SELECT * FROM cuisines ORDER BY name");
|
||||||
|
$cuisines = $cuisines_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Base query
|
||||||
|
$sql = "SELECT r.id, r.name, r.image_url, GROUP_CONCAT(c.name SEPARATOR ', ') as cuisines, AVG(ra.rating) as average_rating
|
||||||
|
FROM restaurants r
|
||||||
|
LEFT JOIN restaurant_cuisines rc ON r.id = rc.restaurant_id
|
||||||
|
LEFT JOIN cuisines c ON rc.cuisine_id = c.id
|
||||||
|
LEFT JOIN ratings ra ON r.id = ra.restaurant_id";
|
||||||
|
|
||||||
|
$where_clauses = [];
|
||||||
|
$params = [];
|
||||||
|
|
||||||
|
// Search functionality
|
||||||
|
if (!empty($_GET['search'])) {
|
||||||
|
$where_clauses[] = "r.name LIKE :search";
|
||||||
|
$params[':search'] = '%' . $_GET['search'] . '%';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cuisine filter
|
||||||
|
if (!empty($_GET['cuisine'])) {
|
||||||
|
$where_clauses[] = "r.id IN (SELECT restaurant_id FROM restaurant_cuisines WHERE cuisine_id = :cuisine_id)";
|
||||||
|
$params[':cuisine_id'] = $_GET['cuisine'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($where_clauses)) {
|
||||||
|
$sql .= " WHERE " . implode(' AND ', $where_clauses);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= " GROUP BY r.id";
|
||||||
|
|
||||||
|
// Sorting functionality
|
||||||
|
$sort_order = $_GET['sort'] ?? 'name_asc';
|
||||||
|
switch ($sort_order) {
|
||||||
|
case 'rating_desc':
|
||||||
|
$sql .= " ORDER BY average_rating DESC";
|
||||||
|
break;
|
||||||
|
case 'name_desc':
|
||||||
|
$sql .= " ORDER BY r.name DESC";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$sql .= " ORDER BY r.name ASC";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = db()->prepare($sql);
|
||||||
|
$stmt->execute($params);
|
||||||
|
$restaurants = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h1 class="text-center mb-5">Our Restaurants</h1>
|
||||||
|
|
||||||
|
<!-- Filters and Sorting -->
|
||||||
|
<form action="restaurants.php" method="get" class="row g-3 mb-5 align-items-center">
|
||||||
|
<div class="col-md-5">
|
||||||
|
<input type="text" name="search" class="form-control" placeholder="Search for a restaurant..." value="<?php echo htmlspecialchars($_GET['search'] ?? ''); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<select name="cuisine" class="form-select">
|
||||||
|
<option value="">All Cuisines</option>
|
||||||
|
<?php foreach ($cuisines as $cuisine): ?>
|
||||||
|
<option value="<?php echo $cuisine['id']; ?>" <?php echo (($_GET['cuisine'] ?? '') == $cuisine['id']) ? 'selected' : ''; ?>>
|
||||||
|
<?php echo htmlspecialchars($cuisine['name']); ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<select name="sort" class="form-select">
|
||||||
|
<option value="name_asc" <?php echo ($sort_order == 'name_asc') ? 'selected' : ''; ?>>Sort by Name (A-Z)</option>
|
||||||
|
<option value="name_desc" <?php echo ($sort_order == 'name_desc') ? 'selected' : ''; ?>>Sort by Name (Z-A)</option>
|
||||||
|
<option value="rating_desc" <?php echo ($sort_order == 'rating_desc') ? 'selected' : ''; ?>>Sort by Rating</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<button type="submit" class="btn btn-primary w-100">Apply</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<!-- Restaurant Grid -->
|
||||||
|
<div class="row">
|
||||||
|
<?php if ($restaurants): ?>
|
||||||
|
<?php foreach ($restaurants as $restaurant): ?>
|
||||||
|
<div class="col-md-4 mb-4">
|
||||||
|
<div class="card restaurant-card h-100">
|
||||||
|
<a href="menu.php?restaurant_id=<?php echo $restaurant['id']; ?>">
|
||||||
|
<img src="<?php echo htmlspecialchars($restaurant['image_url'] ?: 'assets/images/hero.jpg'); ?>" class="card-img-top" alt="<?php echo htmlspecialchars($restaurant['name']); ?>">
|
||||||
|
</a>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title"><?php echo htmlspecialchars($restaurant['name']); ?></h5>
|
||||||
|
<p class="card-text text-muted"><?php echo htmlspecialchars($restaurant['cuisines']); ?></p>
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<span class="text-warning"><?php echo $restaurant['average_rating'] ? round($restaurant['average_rating'], 1) . ' ★' : 'No ratings'; ?></span>
|
||||||
|
<a href="menu.php?restaurant_id=<?php echo $restaurant['id']; ?>" class="btn btn-outline-primary">View Menu</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="col">
|
||||||
|
<p class="alert alert-info">No restaurants found matching your criteria.</p>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
Loading…
x
Reference in New Issue
Block a user