This commit is contained in:
Flatlogic Bot 2025-10-16 14:27:25 +00:00
parent 42cfa7481c
commit 2be0d2d4c4
12 changed files with 406 additions and 63 deletions

View File

@ -40,6 +40,9 @@ if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== tru
<li class="nav-item">
<a class="nav-link" href="settings.php">Settings</a>
</li>
<li class="nav-item">
<a class="nav-link" href="notification_emails.php">Notification Emails</a>
</li>
</ul>
<ul class="navbar-nav ms-auto">
<li class="nav-item">

View 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">&times;</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">&times;</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'; ?>

View File

@ -23,7 +23,10 @@ MajuroEats Theme
/* --- Global Styles --- */
body {
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);
margin: 0;
padding-top: 80px; /* Space for fixed header */
@ -60,11 +63,25 @@ main {
}
.section-title {
font-size: 2.5rem;
font-size: 2.8rem;
font-weight: 800;
text-align: center;
margin-bottom: 40px;
margin-bottom: 50px;
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 --- */
@ -172,7 +189,7 @@ main {
/* --- Hero Section --- */
.hero-section {
position: relative;
background-image: url('../assets/pasted-20251016-062926-8620c9e4.jpg');
background-image: url('../assets/pasted-20251016-083643-5429546d.jpg');
background-size: cover;
background-position: center;
color: var(--coconut-white);
@ -186,8 +203,7 @@ main {
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(45deg, var(--orange), var(--coral));
opacity: 0.85;
background: rgba(0, 0, 0, 0.5);
}
.hero-content-container {
@ -196,65 +212,59 @@ main {
}
.hero-content h1 {
font-size: 3.5rem;
font-size: 3.8rem;
font-weight: 800;
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 {
font-size: 1.25rem;
margin: 0 0 30px;
opacity: 0.9;
font-size: 1.3rem;
margin: 0 auto 40px;
opacity: 0.95;
max-width: 600px;
}
.location-actions {
.hero-search-form {
display: flex;
justify-content: center;
gap: 20px;
margin-bottom: 20px;
margin: 30px auto;
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 {
padding: 15px 30px;
border-radius: 50px;
font-weight: 700;
#address-input {
flex-grow: 1;
border: none;
padding: 20px;
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;
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;
font-size: 1.2rem;
font-weight: 800;
margin-bottom: 20px;
box-shadow: var(--shadow-medium);
}
#find-food-btn:hover {
background-color: var(--orange);
}
.delivery-note {
@ -315,11 +325,13 @@ main {
overflow: hidden;
transition: var(--transition);
color: var(--text-dark);
border: 2px solid transparent;
}
.restaurant-card:hover {
transform: translateY(-10px);
box-shadow: var(--shadow-medium);
border-color: var(--coral);
}
.card-image {
@ -576,12 +588,11 @@ main {
height: 180px;
background-size: cover;
background-position: center;
filter: brightness(0.7);
transition: var(--transition);
}
.cuisine-card:hover .card-image {
filter: brightness(0.9);
transform: scale(1.05);
}
.cuisine-card-content {
@ -591,7 +602,7 @@ main {
padding: 20px;
width: 100%;
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 {
@ -600,3 +611,59 @@ main {
margin: 0;
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);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

View File

@ -34,6 +34,31 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
$stmt = $pdo->prepare($sql);
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
header("Location: driver_pending_approval.php");
exit;

View File

@ -25,8 +25,8 @@ session_start();
<span class="logo-text">MajuroEats</span>
</a>
<ul class="nav-links">
<li><a href="/">Home</a></li>
<li><a href="index.php">Restaurants</a></li>
<li><a href="index.php">Home</a></li>
<li><a href="restaurants.php">Restaurants</a></li>
<li><a href="rewards.php">Rewards</a></li>
<li><a href="driver_signup.php">Driver</a></li>
<li><a href="help.php">Help</a></li>

View File

@ -1,6 +1,7 @@
<?php
session_start();
require_once __DIR__ . '/mail/MailService.php';
require_once __DIR__ . '/db/config.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$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>";
$text_content = "Name: {$name}\nEmail: {$email}\nPhone: {$phone}\nMessage:\n{$message}";
// The recipient's email address. Using environment variable or a default.
$to = getenv('MAIL_TO') ?: 'support@majuroeats.com';
$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';
}
$result = MailService::sendMail($to, $subject, $html_content, $text_content, ['reply_to' => $email]);

View File

@ -2,13 +2,12 @@
<div class="hero-overlay"></div>
<div class="container hero-content-container">
<div class="hero-content">
<h1>Fast Island Delivery From Rita to Laura!</h1>
<p>Get your favorite meals delivered anywhere on Majuro Island.</p>
<div class="location-actions">
<button class="location-button primary" id="pin-location-btn">📍 Pin Your Location</button>
<button class="location-button secondary" id="use-location-btn">Use Current Location</button>
<h1>Your favorite local food, delivered.</h1>
<p>Enter your address to find restaurants near you.</p>
<div class="hero-search-form">
<input type="text" id="address-input" placeholder="Enter your delivery address">
<button id="find-food-btn">Find Food</button>
</div>
<a href="index.php" class="find-restaurants-btn">Find Restaurants</a>
<p class="delivery-note">MajuroEats delivers only within the main island zone (RitaLaura).</p>
</div>
</div>

View 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
View 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'; ?>