Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
155d41aa75 |
62
accept_listing.php
Normal file
62
accept_listing.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['id'])) {
|
||||||
|
header('Location: ngo_dashboard.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$id = filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT);
|
||||||
|
|
||||||
|
if ($id === false) {
|
||||||
|
header('Location: ngo_dashboard.php?status=error');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate a logged-in NGO by fetching the first one
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$sql_ngo = "SELECT id FROM ngos ORDER BY id ASC LIMIT 1";
|
||||||
|
$stmt_ngo = $pdo->query($sql_ngo);
|
||||||
|
$ngo = $stmt_ngo->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if (!$ngo) {
|
||||||
|
throw new Exception('No NGOs found in the database. Please register an NGO first.');
|
||||||
|
}
|
||||||
|
$ngo_id = $ngo['id'];
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// error_log($e->getMessage());
|
||||||
|
header('Location: ngo_dashboard.php?status=no_ngo');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
// Check if the listing is still available before claiming
|
||||||
|
$checkSql = "SELECT status FROM food_listings WHERE id = :id";
|
||||||
|
$checkStmt = $pdo->prepare($checkSql);
|
||||||
|
$checkStmt->bindParam(':id', $id, PDO::PARAM_INT);
|
||||||
|
$checkStmt->execute();
|
||||||
|
$currentStatus = $checkStmt->fetchColumn();
|
||||||
|
|
||||||
|
if ($currentStatus === 'available') {
|
||||||
|
$updateSql = "UPDATE food_listings SET status = 'claimed', ngo_id = :ngo_id WHERE id = :id";
|
||||||
|
$updateStmt = $pdo->prepare($updateSql);
|
||||||
|
$updateStmt->bindParam(':ngo_id', $ngo_id, PDO::PARAM_INT);
|
||||||
|
$updateStmt->bindParam(':id', $id, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
if ($updateStmt->execute()) {
|
||||||
|
header('Location: ngo_dashboard.php?status=claimed');
|
||||||
|
} else {
|
||||||
|
header('Location: ngo_dashboard.php?status=error');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The listing was already claimed by someone else
|
||||||
|
header('Location: ngo_dashboard.php?status=already_claimed');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// error_log($e->getMessage());
|
||||||
|
header('Location: ngo_dashboard.php?status=error');
|
||||||
|
}
|
||||||
|
|
||||||
|
exit();
|
||||||
138
add_listing.php
Normal file
138
add_listing.php
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Add Food Listing - Real-Time Food Rescue</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
.navbar {
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,.1);
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
border: none;
|
||||||
|
box-shadow: 0 4px 8px rgba(0,0,0,.1);
|
||||||
|
}
|
||||||
|
.form-label {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.btn-primary {
|
||||||
|
background-color: #28a745;
|
||||||
|
border-color: #28a745;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
}
|
||||||
|
.btn-primary:hover {
|
||||||
|
background-color: #218838;
|
||||||
|
border-color: #1e7e34;
|
||||||
|
}
|
||||||
|
.alert {
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light bg-white">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="index.php" style="font-weight: 600;">Food Rescue</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="index.php">Home</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" href="add_listing.php">Add Listing</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="ngo_dashboard.php">NGO Dashboard</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="volunteer_signup.php">Volunteer Signup</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="volunteer_dashboard.php">Volunteer Dashboard</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="volunteer_hub_old.php">Find Pickups</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="distribution_map.php">Distribution Map</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="admin_panel.php">Admin Panel</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container my-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card p-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="card-title text-center mb-4">Create a Surplus Food Listing</h2>
|
||||||
|
|
||||||
|
<?php if (isset($_GET['status']) && $_GET['status'] == 'success'): ?>
|
||||||
|
<div class="alert alert-success" role="alert">
|
||||||
|
Thank you! Your food listing has been posted successfully.
|
||||||
|
</div>
|
||||||
|
<?php elseif (isset($_GET['status']) && $_GET['status'] == 'error'): ?>
|
||||||
|
<div class="alert alert-danger" role="alert">
|
||||||
|
Something went wrong. Please check your inputs and try again.
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="submit_listing.php" method="POST">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="name" class="form-label">Food Item Name</label>
|
||||||
|
<input type="text" class="form-control" id="name" name="name" placeholder="e.g., Fresh Bread Loaves" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="quantity" class="form-label">Quantity</label>
|
||||||
|
<input type="text" class="form-control" id="quantity" name="quantity" placeholder="e.g., 10 loaves, 5 boxes" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="pickup_by" class="form-label">Latest Pickup Time</label>
|
||||||
|
<input type="datetime-local" class="form-control" id="pickup_by" name="pickup_by" required>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="latitude" class="form-label">Latitude</label>
|
||||||
|
<input type="text" class="form-control" id="latitude" name="latitude" placeholder="e.g., 40.7128">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="longitude" class="form-label">Longitude</label>
|
||||||
|
<input type="text" class="form-control" id="longitude" name="longitude" placeholder="e.g., -74.0060">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="description" class="form-label">Description (Optional)</label>
|
||||||
|
<textarea class="form-control" id="description" name="description" rows="3" placeholder="Additional details like ingredients or special instructions."></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" class="btn btn-primary">Submit Listing</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
113
admin_panel.php
Normal file
113
admin_panel.php
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<?php
|
||||||
|
// In a real application, this page should be protected by a robust authentication and authorization system.
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Fetch all food listings with relations
|
||||||
|
$sql = "SELECT
|
||||||
|
l.id, l.name as food_item, l.quantity, l.status, l.pickup_by,
|
||||||
|
d.name as donor_name,
|
||||||
|
n.name as ngo_name,
|
||||||
|
v.name as volunteer_name
|
||||||
|
FROM food_listings as l
|
||||||
|
LEFT JOIN donors as d ON l.id = d.id // This is a simplification, should be a proper FK
|
||||||
|
LEFT JOIN ngos as n ON l.ngo_id = n.id
|
||||||
|
LEFT JOIN volunteer_assignments as va ON l.id = va.listing_id
|
||||||
|
LEFT JOIN volunteers as v ON va.volunteer_id = v.id
|
||||||
|
ORDER BY l.created_at DESC";
|
||||||
|
$stmt = $pdo->query($sql);
|
||||||
|
$listings = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$listings = [];
|
||||||
|
// error_log($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusBadge($status) {
|
||||||
|
$badges = [
|
||||||
|
'available' => '<span class="badge bg-secondary">Available</span>',
|
||||||
|
'claimed' => '<span class="badge bg-warning text-dark">Claimed</span>',
|
||||||
|
'assigned' => '<span class="badge bg-primary">Assigned</span>',
|
||||||
|
'collected' => '<span class="badge bg-info">Collected</span>',
|
||||||
|
'en-route' => '<span class="badge bg-info text-dark">En Route</span>',
|
||||||
|
'delivered' => '<span class="badge bg-success">Delivered</span>',
|
||||||
|
];
|
||||||
|
return $badges[$status] ?? '<span class="badge bg-light text-dark">Unknown</span>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Admin Panel - Food Rescue</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body { font-family: 'Poppins', sans-serif; background-color: #f8f9fa; }
|
||||||
|
.navbar { box-shadow: 0 2px 4px rgba(0,0,0,.1); }
|
||||||
|
.table { background-color: #fff; box-shadow: 0 4px 8px rgba(0,0,0,.1); }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light bg-white sticky-top">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="index.php" style="font-weight: 600;">Food Rescue</a>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="index.php">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="add_listing.php">Add Listing</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="ngo_dashboard.php">NGO Dashboard</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="volunteer_dashboard.php">Volunteer Dashboard</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="distribution_map.php">Distribution Map</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link active" href="admin_panel.php">Admin Panel</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container-fluid my-5">
|
||||||
|
<h1 class="h2 mb-4">Admin Panel: System-Wide View</h1>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
All Food Listings
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead class="table-dark">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Food Item</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>NGO</th>
|
||||||
|
<th>Volunteer</th>
|
||||||
|
<th>Pickup By</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if (empty($listings)): ?>
|
||||||
|
<tr><td colspan="6" class="text-center text-muted">No listings found.</td></tr>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($listings as $listing): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($listing['id']) ?></td>
|
||||||
|
<td><?= htmlspecialchars($listing['food_item']) ?></td>
|
||||||
|
<td><?= getStatusBadge($listing['status']) ?></td>
|
||||||
|
<td><?= htmlspecialchars($listing['ngo_name'] ?? '-') ?></td>
|
||||||
|
<td><?= htmlspecialchars($listing['volunteer_name'] ?? '-') ?></td>
|
||||||
|
<td><?= date('M d, Y h:i A', strtotime($listing['pickup_by'])) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
22
api/locations.php
Normal file
22
api/locations.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
require_once __DIR__ . '/../db/config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
// Fetch listings that are either assigned or collected, and have coordinates
|
||||||
|
$sql = "SELECT name, quantity, latitude, longitude, status, pickup_by
|
||||||
|
FROM food_listings
|
||||||
|
WHERE (status = 'assigned' OR status = 'collected')
|
||||||
|
AND latitude IS NOT NULL AND longitude IS NOT NULL";
|
||||||
|
|
||||||
|
$stmt = $pdo->query($sql);
|
||||||
|
$locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
echo json_encode($locations);
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => 'Database error']);
|
||||||
|
// error_log($e->getMessage());
|
||||||
|
}
|
||||||
59
assign_pickup.php
Normal file
59
assign_pickup.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['listing_id']) || !isset($_POST['volunteer_id'])) {
|
||||||
|
header('Location: volunteer_hub.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$listing_id = filter_input(INPUT_POST, 'listing_id', FILTER_VALIDATE_INT);
|
||||||
|
$volunteer_id = filter_input(INPUT_POST, 'volunteer_id', FILTER_VALIDATE_INT);
|
||||||
|
|
||||||
|
if ($listing_id === false || $volunteer_id === false) {
|
||||||
|
header('Location: volunteer_hub.php?status=error');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
// 1. Check if the listing is still 'claimed'
|
||||||
|
$checkSql = "SELECT status FROM food_listings WHERE id = :listing_id FOR UPDATE"; // Lock the row
|
||||||
|
$checkStmt = $pdo->prepare($checkSql);
|
||||||
|
$checkStmt->bindParam(':listing_id', $listing_id, PDO::PARAM_INT);
|
||||||
|
$checkStmt->execute();
|
||||||
|
$currentStatus = $checkStmt->fetchColumn();
|
||||||
|
|
||||||
|
if ($currentStatus === 'claimed') {
|
||||||
|
// 2. Update the listing status to 'assigned'
|
||||||
|
$updateSql = "UPDATE food_listings SET status = 'assigned' WHERE id = :listing_id";
|
||||||
|
$updateStmt = $pdo->prepare($updateSql);
|
||||||
|
$updateStmt->bindParam(':listing_id', $listing_id, PDO::PARAM_INT);
|
||||||
|
$updateStmt->execute();
|
||||||
|
|
||||||
|
// 3. Create the assignment record
|
||||||
|
$assignSql = "INSERT INTO volunteer_assignments (listing_id, volunteer_id) VALUES (:listing_id, :volunteer_id)";
|
||||||
|
$assignStmt = $pdo->prepare($assignSql);
|
||||||
|
$assignStmt->bindParam(':listing_id', $listing_id, PDO::PARAM_INT);
|
||||||
|
$assignStmt->bindParam(':volunteer_id', $volunteer_id, PDO::PARAM_INT);
|
||||||
|
$assignStmt->execute();
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
header('Location: volunteer_hub.php?status=assigned');
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// The listing was already assigned or is in another state
|
||||||
|
$pdo->rollBack();
|
||||||
|
header('Location: volunteer_hub.php?status=already_assigned');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
if ($pdo->inTransaction()) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
}
|
||||||
|
// error_log($e->getMessage());
|
||||||
|
header('Location: volunteer_hub.php?status=error');
|
||||||
|
}
|
||||||
|
|
||||||
|
exit();
|
||||||
23
db/setup.php
Normal file
23
db/setup.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$sql = "
|
||||||
|
CREATE TABLE IF NOT EXISTS food_listings (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
quantity VARCHAR(100) NOT NULL,
|
||||||
|
pickup_by DATETIME NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
status ENUM('available', 'claimed', 'collected') DEFAULT 'available',
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);";
|
||||||
|
|
||||||
|
$pdo->exec($sql);
|
||||||
|
echo "Database table 'food_listings' created successfully (if it didn't exist).
|
||||||
|
";
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("DB ERROR: " . $e->getMessage());
|
||||||
|
}
|
||||||
21
db/setup_admin.php
Normal file
21
db/setup_admin.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// donors table
|
||||||
|
$sql_donors = "
|
||||||
|
CREATE TABLE IF NOT EXISTS donors (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
email VARCHAR(255) NOT NULL UNIQUE,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);";
|
||||||
|
$pdo->exec($sql_donors);
|
||||||
|
echo "Database table 'donors' created successfully (if it didn't exist).\n";
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("DB ERROR: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
59
db/setup_auth.php
Normal file
59
db/setup_auth.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
echo "Starting authentication setup...\n";
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
// 1. Create the new unified 'users' table
|
||||||
|
$sql_users = "
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
email VARCHAR(255) NOT NULL UNIQUE,
|
||||||
|
password VARCHAR(255) NOT NULL,
|
||||||
|
role ENUM('donor', 'ngo', 'volunteer', 'admin') NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);";
|
||||||
|
$pdo->exec($sql_users);
|
||||||
|
echo "- 'users' table created successfully.\n";
|
||||||
|
|
||||||
|
// 2. Migrate data from old tables
|
||||||
|
// Note: We are setting a default password. Users would need a "reset password" flow.
|
||||||
|
$default_password = password_hash('password123', PASSWORD_DEFAULT);
|
||||||
|
|
||||||
|
// Migrate from donors (assuming it exists and has data)
|
||||||
|
if ($pdo->query("SHOW TABLES LIKE 'donors'")->rowCount() > 0) {
|
||||||
|
$pdo->exec("INSERT INTO users (name, email, password, role) SELECT name, email, '{$default_password}', 'donor' FROM donors");
|
||||||
|
echo "- Migrated data from 'donors'.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate from ngos
|
||||||
|
$pdo->exec("INSERT INTO users (name, email, password, role) SELECT name, email, '{$default_password}', 'ngo' FROM ngos");
|
||||||
|
echo "- Migrated data from 'ngos'.\n";
|
||||||
|
|
||||||
|
// Migrate from volunteers
|
||||||
|
$pdo->exec("INSERT INTO users (name, email, password, role) SELECT name, email, '{$default_password}', 'volunteer' FROM volunteers");
|
||||||
|
echo "- Migrated data from 'volunteers'.\n";
|
||||||
|
|
||||||
|
// 3. Rename old tables (optional, but good for cleanup)
|
||||||
|
$pdo->exec("RENAME TABLE donors TO donors_old");
|
||||||
|
$pdo->exec("RENAME TABLE ngos TO ngos_old");
|
||||||
|
$pdo->exec("RENAME TABLE volunteers TO volunteers_old");
|
||||||
|
echo "- Renamed old user tables.\n";
|
||||||
|
|
||||||
|
// 4. Update foreign key constraints (This is the tricky part)
|
||||||
|
// We need to update ngo_id and volunteer_id in other tables to point to the new users.id
|
||||||
|
// This is complex and requires careful data mapping. For this MVP, we will skip this step
|
||||||
|
// and acknowledge that existing relationships will be broken. New relationships will use the new users table.
|
||||||
|
echo "- SKIPPED updating foreign keys for this migration. New records will use the new schema.\n";
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
echo "Authentication setup completed successfully!\n";
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
die("DB ERROR: " . $e->getMessage());
|
||||||
|
}
|
||||||
29
db/setup_locations.php
Normal file
29
db/setup_locations.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Add latitude and longitude columns to food_listings
|
||||||
|
// Using DECIMAL(10, 8) and DECIMAL(11, 8) for sufficient precision
|
||||||
|
$sql_alter_lat = "ALTER TABLE food_listings ADD COLUMN latitude DECIMAL(10, 8) NULL AFTER description";
|
||||||
|
$sql_alter_lon = "ALTER TABLE food_listings ADD COLUMN longitude DECIMAL(11, 8) NULL AFTER latitude";
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo->exec($sql_alter_lat);
|
||||||
|
echo "Added 'latitude' column to 'food_listings' table.\n";
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo "Could not add 'latitude' column (maybe it already exists).\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo->exec($sql_alter_lon);
|
||||||
|
echo "Added 'longitude' column to 'food_listings' table.\n";
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo "Could not add 'longitude' column (maybe it already exists).\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("DB ERROR: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
34
db/setup_ngos.php
Normal file
34
db/setup_ngos.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// ngos table
|
||||||
|
$sql_ngos = "
|
||||||
|
CREATE TABLE IF NOT EXISTS ngos (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
email VARCHAR(255) NOT NULL UNIQUE,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);";
|
||||||
|
$pdo->exec($sql_ngos);
|
||||||
|
echo "Database table 'ngos' created successfully (if it didn't exist).\n";
|
||||||
|
|
||||||
|
// Add ngo_id to food_listings table
|
||||||
|
try {
|
||||||
|
$sql_alter = "ALTER TABLE food_listings ADD COLUMN ngo_id INT NULL AFTER volunteer_id, ADD FOREIGN KEY (ngo_id) REFERENCES ngos(id) ON DELETE SET NULL";
|
||||||
|
// I am getting an error with volunteer_id not existing, so I will add it first.
|
||||||
|
$sql_add_volunteer_id = "ALTER TABLE food_listings ADD COLUMN volunteer_id INT NULL AFTER status";
|
||||||
|
$pdo->exec($sql_add_volunteer_id);
|
||||||
|
$pdo->exec($sql_alter);
|
||||||
|
echo "Altered 'food_listings' table to add 'ngo_id'.\n";
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// If the column already exists, this will fail, which is okay.
|
||||||
|
echo "Could not alter 'food_listings' table (maybe 'ngo_id' already exists or other schema issue). Error: " . $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("DB ERROR: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
19
db/setup_volunteer_dashboard.php
Normal file
19
db/setup_volunteer_dashboard.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Add more statuses to the food_listings table
|
||||||
|
try {
|
||||||
|
$sql_alter = "ALTER TABLE food_listings MODIFY status ENUM('available', 'claimed', 'collected', 'assigned', 'en-route', 'delivered') DEFAULT 'available'";
|
||||||
|
$pdo->exec($sql_alter);
|
||||||
|
echo "Altered 'food_listings' table to add more delivery statuses.\n";
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo "Could not alter 'food_listings' table (maybe statuses already exist). Error: " . $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("DB ERROR: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
45
db/setup_volunteers.php
Normal file
45
db/setup_volunteers.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// volunteers table
|
||||||
|
$sql_volunteers = "
|
||||||
|
CREATE TABLE IF NOT EXISTS volunteers (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
email VARCHAR(255) NOT NULL UNIQUE,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);";
|
||||||
|
$pdo->exec($sql_volunteers);
|
||||||
|
echo "Database table 'volunteers' created successfully (if it didn't exist).\n";
|
||||||
|
|
||||||
|
// volunteer_assignments table
|
||||||
|
$sql_assignments = "
|
||||||
|
CREATE TABLE IF NOT EXISTS volunteer_assignments (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
listing_id INT NOT NULL,
|
||||||
|
volunteer_id INT NOT NULL,
|
||||||
|
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (listing_id) REFERENCES food_listings(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (volunteer_id) REFERENCES volunteers(id) ON DELETE CASCADE
|
||||||
|
);";
|
||||||
|
$pdo->exec($sql_assignments);
|
||||||
|
echo "Database table 'volunteer_assignments' created successfully (if it didn't exist).\n";
|
||||||
|
|
||||||
|
// Add 'assigned' to the status enum in food_listings
|
||||||
|
// Note: This might fail if the enum value already exists, which is fine.
|
||||||
|
try {
|
||||||
|
$sql_alter_listings = "ALTER TABLE food_listings MODIFY status ENUM('available', 'claimed', 'collected', 'assigned') DEFAULT 'available'";
|
||||||
|
$pdo->exec($sql_alter_listings);
|
||||||
|
echo "Altered 'food_listings' table to add 'assigned' status.\n";
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// This will likely throw an error if you run it more than once.
|
||||||
|
echo "Could not alter 'food_listings' table (maybe 'assigned' status already exists).\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("DB ERROR: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
124
distribution_map.php
Normal file
124
distribution_map.php
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Distribution Map - Food Rescue</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body { font-family: 'Poppins', sans-serif; background-color: #f8f9fa; }
|
||||||
|
.navbar { box-shadow: 0 2px 4px rgba(0,0,0,.1); }
|
||||||
|
#map { height: 600px; border-radius: 0.5rem; box-shadow: 0 4px 8px rgba(0,0,0,.1); }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light bg-white sticky-top">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="index.php" style="font-weight: 600;">Food Rescue</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"><span class="navbar-toggler-icon"></span></button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="index.php">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="add_listing.php">Add Listing</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="ngo_dashboard.php">NGO Dashboard</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="volunteer_signup.php">Volunteer Signup</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="volunteer_dashboard.php">Volunteer Dashboard</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="volunteer_hub_old.php">Find Pickups</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link active" href="distribution_map.php">Distribution Map</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="admin_panel.php">Admin Panel</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container my-5">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<h1 class="h2">Food Distribution Points</h1>
|
||||||
|
<p class="lead text-muted">Find locations where food is being distributed.</p>
|
||||||
|
</div>
|
||||||
|
<div id="map"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
// Initialize the map, centered on a default location (e.g., New York City)
|
||||||
|
const map = L.map('map').setView([40.7128, -74.0060], 12);
|
||||||
|
|
||||||
|
// Add the OpenStreetMap tile layer
|
||||||
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
maxZoom: 19,
|
||||||
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
// Fetch location data from the API
|
||||||
|
fetch('api/locations.php')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(locations => {
|
||||||
|
if (locations.length === 0) {
|
||||||
|
// Optional: Handle case with no locations
|
||||||
|
console.log('No distribution points found.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const markers = [];
|
||||||
|
locations.forEach(loc => {
|
||||||
|
const lat = parseFloat(loc.latitude);
|
||||||
|
const lon = parseFloat(loc.longitude);
|
||||||
|
|
||||||
|
// Define marker color based on status
|
||||||
|
const markerColor = loc.status === 'assigned' ? 'orange' : 'green';
|
||||||
|
const icon = L.divIcon({
|
||||||
|
className: 'custom-div-icon',
|
||||||
|
html: `<div style="background-color:${markerColor};" class="marker-pin"></div><i></i>`,
|
||||||
|
iconSize: [30, 42],
|
||||||
|
iconAnchor: [15, 42]
|
||||||
|
});
|
||||||
|
|
||||||
|
const marker = L.marker([lat, lon], { icon: icon });
|
||||||
|
|
||||||
|
let popupContent = `<b>${loc.name}</b><br>Quantity: ${loc.quantity}<br>Status: ${loc.status}`;
|
||||||
|
marker.bindPopup(popupContent);
|
||||||
|
|
||||||
|
markers.push(marker);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add markers to the map
|
||||||
|
const featureGroup = L.featureGroup(markers).addTo(map);
|
||||||
|
|
||||||
|
// Fit map to show all markers
|
||||||
|
if (markers.length > 0) {
|
||||||
|
map.fitBounds(featureGroup.getBounds().pad(0.1));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => console.error('Error fetching locations:', error));
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.marker-pin {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 50% 50% 50% 0;
|
||||||
|
background: #007bff;
|
||||||
|
position: absolute;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
margin: -15px 0 0 -15px;
|
||||||
|
}
|
||||||
|
.marker-pin::after {
|
||||||
|
content: '';
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
margin: 8px 0 0 8px;
|
||||||
|
background: #fff;
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
259
index.php
259
index.php
@ -1,21 +1,12 @@
|
|||||||
<?php
|
<!DOCTYPE html>
|
||||||
declare(strict_types=1);
|
|
||||||
@ini_set('display_errors', '1');
|
|
||||||
@error_reporting(E_ALL);
|
|
||||||
@date_default_timezone_set('UTC');
|
|
||||||
|
|
||||||
$phpVersion = PHP_VERSION;
|
|
||||||
$now = date('Y-m-d H:i:s');
|
|
||||||
?>
|
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>New Style</title>
|
<title>Real-Time Food Rescue</title>
|
||||||
<?php
|
<?php
|
||||||
// Read project preview data from environment
|
// Read project preview data from environment
|
||||||
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
|
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'A platform to connect food donors with those in need.';
|
||||||
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
||||||
?>
|
?>
|
||||||
<?php if ($projectDescription): ?>
|
<?php if ($projectDescription): ?>
|
||||||
@ -32,119 +23,135 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
|||||||
<!-- Twitter image -->
|
<!-- Twitter image -->
|
||||||
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<style>
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap" rel="stylesheet">
|
||||||
:root {
|
<style>
|
||||||
--bg-color-start: #6a11cb;
|
body {
|
||||||
--bg-color-end: #2575fc;
|
font-family: 'Poppins', sans-serif;
|
||||||
--text-color: #ffffff;
|
background-color: #f8f9fa;
|
||||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
color: #212529;
|
||||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
}
|
||||||
}
|
.navbar {
|
||||||
body {
|
box-shadow: 0 2px 4px rgba(0,0,0,.1);
|
||||||
margin: 0;
|
}
|
||||||
font-family: 'Inter', sans-serif;
|
.hero-section {
|
||||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
background: linear-gradient(45deg, #28a745, #20c997);
|
||||||
color: var(--text-color);
|
color: white;
|
||||||
display: flex;
|
padding: 100px 0;
|
||||||
justify-content: center;
|
text-align: center;
|
||||||
align-items: center;
|
}
|
||||||
min-height: 100vh;
|
.hero-section h1 {
|
||||||
text-align: center;
|
font-weight: 700;
|
||||||
overflow: hidden;
|
font-size: 3.5rem;
|
||||||
position: relative;
|
}
|
||||||
}
|
.hero-section p {
|
||||||
body::before {
|
font-size: 1.25rem;
|
||||||
content: '';
|
margin-bottom: 2rem;
|
||||||
position: absolute;
|
}
|
||||||
top: 0;
|
.btn-primary {
|
||||||
left: 0;
|
background-color: #fd7e14;
|
||||||
width: 100%;
|
border-color: #fd7e14;
|
||||||
height: 100%;
|
font-weight: 600;
|
||||||
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
|
padding: 0.75rem 1.5rem;
|
||||||
animation: bg-pan 20s linear infinite;
|
border-radius: 0.5rem;
|
||||||
z-index: -1;
|
font-size: 1.1rem;
|
||||||
}
|
}
|
||||||
@keyframes bg-pan {
|
.btn-primary:hover {
|
||||||
0% { background-position: 0% 0%; }
|
background-color: #e66a00;
|
||||||
100% { background-position: 100% 100%; }
|
border-color: #d36000;
|
||||||
}
|
}
|
||||||
main {
|
.section {
|
||||||
padding: 2rem;
|
padding: 60px 0;
|
||||||
}
|
}
|
||||||
.card {
|
.feature-icon {
|
||||||
background: var(--card-bg-color);
|
font-size: 3rem;
|
||||||
border: 1px solid var(--card-border-color);
|
color: #28a745;
|
||||||
border-radius: 16px;
|
}
|
||||||
padding: 2rem;
|
</style>
|
||||||
backdrop-filter: blur(20px);
|
|
||||||
-webkit-backdrop-filter: blur(20px);
|
|
||||||
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
.loader {
|
|
||||||
margin: 1.25rem auto 1.25rem;
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
border: 3px solid rgba(255, 255, 255, 0.25);
|
|
||||||
border-top-color: #fff;
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: spin 1s linear infinite;
|
|
||||||
}
|
|
||||||
@keyframes spin {
|
|
||||||
from { transform: rotate(0deg); }
|
|
||||||
to { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
.hint {
|
|
||||||
opacity: 0.9;
|
|
||||||
}
|
|
||||||
.sr-only {
|
|
||||||
position: absolute;
|
|
||||||
width: 1px; height: 1px;
|
|
||||||
padding: 0; margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
clip: rect(0, 0, 0, 0);
|
|
||||||
white-space: nowrap; border: 0;
|
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
font-size: 3rem;
|
|
||||||
font-weight: 700;
|
|
||||||
margin: 0 0 1rem;
|
|
||||||
letter-spacing: -1px;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
margin: 0.5rem 0;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
code {
|
|
||||||
background: rgba(0,0,0,0.2);
|
|
||||||
padding: 2px 6px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
||||||
}
|
|
||||||
footer {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 1rem;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main>
|
|
||||||
<div class="card">
|
<nav class="navbar navbar-expand-lg navbar-light bg-white sticky-top">
|
||||||
<h1>Analyzing your requirements and generating your website…</h1>
|
<div class="container-fluid">
|
||||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
<a class="navbar-brand" href="#" style="font-weight: 600;">Food Rescue</a>
|
||||||
<span class="sr-only">Loading…</span>
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||||
</div>
|
<span class="navbar-toggler-icon"></span>
|
||||||
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
|
</button>
|
||||||
<p class="hint">This page will update automatically as the plan is implemented.</p>
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
|
<ul class="navbar-nav ms-auto">
|
||||||
</div>
|
<li class="nav-item">
|
||||||
</main>
|
<a class="nav-link active" href="index.php">Home</a>
|
||||||
<footer>
|
</li>
|
||||||
Page updated: <?= htmlspecialchars($now) ?> (UTC)
|
<li class="nav-item">
|
||||||
</footer>
|
<a class="nav-link" href="add_listing.php">Add Listing</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="ngo_dashboard.php">NGO Dashboard</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="volunteer_signup.php">Volunteer Signup</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="volunteer_dashboard.php">Volunteer Dashboard</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="volunteer_hub_old.php">Find Pickups</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="distribution_map.php">Distribution Map</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="admin_panel.php">Admin Panel</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<header class="hero-section">
|
||||||
|
<div class="container">
|
||||||
|
<h1>Reduce Waste, Fight Hunger</h1>
|
||||||
|
<p class="lead">Connect with volunteers to get your surplus food to people in need, in real-time.</p>
|
||||||
|
<a href="add_listing.php" class="btn btn-primary btn-lg">Donate Food Now</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="section bg-light text-center">
|
||||||
|
<div class="container">
|
||||||
|
<h2>How It Works</h2>
|
||||||
|
<p class="lead mb-5">A simple process for a massive impact.</p>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="p-4">
|
||||||
|
<div class="feature-icon mb-3">-</div>
|
||||||
|
<h3>1. List Your Surplus</h3>
|
||||||
|
<p>Restaurants and stores post details about their surplus food in seconds.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="p-4">
|
||||||
|
<div class="feature-icon mb-3">-</div>
|
||||||
|
<h3>2. Get Matched</h3>
|
||||||
|
<p>Our system instantly notifies nearby NGOs and volunteers who can accept the donation.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="p-4">
|
||||||
|
<div class="feature-icon mb-3">-</div>
|
||||||
|
<h3>3. Food is Rescued</h3>
|
||||||
|
<p>A volunteer picks up the food and delivers it to a local charity, feeding those in need.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer class="text-center p-4 bg-white">
|
||||||
|
<p class="mb-0">© <?= date('Y') ?> Food Rescue Initiative. All Rights Reserved.</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
119
ngo_dashboard.php
Normal file
119
ngo_dashboard.php
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
// Simulate a logged-in NGO
|
||||||
|
$ngo_id = 1; // In a real app, this would come from a session
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Fetch the NGO's details
|
||||||
|
$sql_ngo = "SELECT name FROM ngos WHERE id = :ngo_id";
|
||||||
|
$stmt_ngo = $pdo->prepare($sql_ngo);
|
||||||
|
$stmt_ngo->bindParam(':ngo_id', $ngo_id, PDO::PARAM_INT);
|
||||||
|
$stmt_ngo->execute();
|
||||||
|
$ngo = $stmt_ngo->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Fetch listings claimed by this NGO
|
||||||
|
$sql_listings = "SELECT l.id, l.name, l.quantity, l.status, l.pickup_by, v.name as volunteer_name
|
||||||
|
FROM food_listings as l
|
||||||
|
LEFT JOIN volunteer_assignments as va ON l.id = va.listing_id
|
||||||
|
LEFT JOIN volunteers as v ON va.volunteer_id = v.id
|
||||||
|
WHERE l.ngo_id = :ngo_id
|
||||||
|
ORDER BY l.pickup_by DESC";
|
||||||
|
$stmt_listings = $pdo->prepare($sql_listings);
|
||||||
|
$stmt_listings->bindParam(':ngo_id', $ngo_id, PDO::PARAM_INT);
|
||||||
|
$stmt_listings->execute();
|
||||||
|
$listings = $stmt_listings->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$ngo = false;
|
||||||
|
$listings = [];
|
||||||
|
// error_log($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusBadge($status) {
|
||||||
|
switch ($status) {
|
||||||
|
case 'claimed':
|
||||||
|
return '<span class="badge bg-warning text-dark">Awaiting Volunteer</span>';
|
||||||
|
case 'assigned':
|
||||||
|
return '<span class="badge bg-info">Volunteer Assigned</span>';
|
||||||
|
case 'collected':
|
||||||
|
return '<span class="badge bg-success">Collected</span>';
|
||||||
|
default:
|
||||||
|
return '<span class="badge bg-secondary">Unknown</span>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>NGO Dashboard - Food Rescue</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body { font-family: 'Poppins', sans-serif; background-color: #f8f9fa; }
|
||||||
|
.navbar { box-shadow: 0 2px 4px rgba(0,0,0,.1); }
|
||||||
|
.table { background-color: #fff; box-shadow: 0 4px 8px rgba(0,0,0,.1); }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light bg-white sticky-top">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="index.php" style="font-weight: 600;">Food Rescue</a>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="index.php">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="add_listing.php">Add Listing</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link active" href="ngo_dashboard.php">NGO Dashboard</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="volunteer_signup.php">Volunteer Signup</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="volunteer_dashboard.php">Volunteer Dashboard</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="volunteer_hub_old.php">Find Pickups</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="distribution_map.php">Distribution Map</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="admin_panel.php">Admin Panel</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container my-5">
|
||||||
|
<h1 class="h2 mb-4">Dashboard: <?= $ngo ? htmlspecialchars($ngo['name']) : 'NGO' ?></h1>
|
||||||
|
|
||||||
|
<?php if (empty($listings)): ?>
|
||||||
|
<div class="card p-5 text-center">
|
||||||
|
<p class="mb-0 text-muted">You have not claimed any donations yet. Visit the <a href="ngo_dashboard_old.php">public listings</a> to find available food.</p>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover align-middle">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>Food Item</th>
|
||||||
|
<th>Quantity</th>
|
||||||
|
<th>Pickup By</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Volunteer</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($listings as $listing): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($listing['name']) ?></td>
|
||||||
|
<td><?= htmlspecialchars($listing['quantity']) ?></td>
|
||||||
|
<td><?= date('M d, Y h:i A', strtotime($listing['pickup_by'])) ?></td>
|
||||||
|
<td><?= getStatusBadge($listing['status']) ?></td>
|
||||||
|
<td><?= $listing['volunteer_name'] ? htmlspecialchars($listing['volunteer_name']) : '-' ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div class="mt-4 text-center">
|
||||||
|
<a href="ngo_dashboard_old.php" class="btn btn-outline-primary">View All Available Donations</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
167
ngo_dashboard_old.php
Normal file
167
ngo_dashboard_old.php
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$sql = "SELECT id, name, quantity, pickup_by, description, status FROM food_listings WHERE status = 'available' ORDER BY pickup_by ASC";
|
||||||
|
$stmt = $pdo->query($sql);
|
||||||
|
$listings = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$listings = [];
|
||||||
|
// In a real app, log this error
|
||||||
|
// error_log($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
function time_ago($datetime) {
|
||||||
|
$now = new DateTime;
|
||||||
|
$ago = new DateTime($datetime);
|
||||||
|
$diff = $now->diff($ago);
|
||||||
|
|
||||||
|
$diff->w = floor($diff->d / 7);
|
||||||
|
$diff->d -= $diff->w * 7;
|
||||||
|
|
||||||
|
$string = array(
|
||||||
|
'y' => 'year',
|
||||||
|
'm' => 'month',
|
||||||
|
'w' => 'week',
|
||||||
|
'd' => 'day',
|
||||||
|
'h' => 'hour',
|
||||||
|
'i' => 'minute',
|
||||||
|
's' => 'second',
|
||||||
|
);
|
||||||
|
foreach ($string as $k => &$v) {
|
||||||
|
if ($diff->$k) {
|
||||||
|
$v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : '');
|
||||||
|
} else {
|
||||||
|
unset($string[$k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$string = array_slice($string, 0, 1);
|
||||||
|
return $string ? implode(', ', $string) . ' ago' : 'just now';
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>NGO Dashboard - Food Rescue</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
.navbar {
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,.1);
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
border: none;
|
||||||
|
box-shadow: 0 4px 8px rgba(0,0,0,.1);
|
||||||
|
transition: transform .2s;
|
||||||
|
}
|
||||||
|
.card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
.card-title {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.btn-success {
|
||||||
|
background-color: #28a745;
|
||||||
|
border-color: #28a745;
|
||||||
|
}
|
||||||
|
.btn-success:hover {
|
||||||
|
background-color: #218838;
|
||||||
|
border-color: #1e7e34;
|
||||||
|
}
|
||||||
|
.badge {
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light bg-white sticky-top">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="index.php" style="font-weight: 600;">Food Rescue</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="index.php">Home</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="add_listing.php">Add Listing</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" href="ngo_dashboard.php">NGO Dashboard</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="volunteer_signup.php">Volunteer Signup</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="volunteer_hub.php">Volunteer Hub</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="distribution_map.php">Distribution Map</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container my-5">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h1 class="h2">Available Food Donations</h1>
|
||||||
|
<?php if (isset($_GET['status']) && $_GET['status'] == 'claimed'): ?>
|
||||||
|
<div class="alert alert-success mb-0 py-2">Donation claimed!</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row gy-4">
|
||||||
|
<?php if (empty($listings)): ?>
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="card p-5 text-center">
|
||||||
|
<p class="mb-0 text-muted">There are currently no available food donations. Please check back later.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($listings as $listing): ?>
|
||||||
|
<div class="col-md-6 col-lg-4">
|
||||||
|
<div class="card h-100">
|
||||||
|
<div class="card-body d-flex flex-column">
|
||||||
|
<h5 class="card-title"><?= htmlspecialchars($listing['name']) ?></h5>
|
||||||
|
<p class="card-text text-muted">Quantity: <?= htmlspecialchars($listing['quantity']) ?></p>
|
||||||
|
<p class="card-text"><?= htmlspecialchars($listing['description']) ?></p>
|
||||||
|
<div class="mt-auto">
|
||||||
|
<p class="card-text">
|
||||||
|
<small class="text-danger">Pickup by: <?= date('M d, Y h:i A', strtotime($listing['pickup_by'])) ?></small>
|
||||||
|
</p>
|
||||||
|
<form action="accept_listing.php" method="POST" class="d-grid">
|
||||||
|
<input type="hidden" name="id" value="<?= $listing['id'] ?>">
|
||||||
|
<button type="submit" class="btn btn-success">Accept Donation</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer bg-transparent border-0 text-end">
|
||||||
|
<small class="text-muted">Posted <?= time_ago($listing['created_at']) ?></small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
107
ngo_signup.php
Normal file
107
ngo_signup.php
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
$name = trim($_POST['name'] ?? '');
|
||||||
|
$email = trim($_POST['email'] ?? '');
|
||||||
|
|
||||||
|
if (!empty($name) && filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$sql = "INSERT INTO ngos (name, email) VALUES (:name, :email)";
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->bindParam(':name', $name, PDO::PARAM_STR);
|
||||||
|
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
|
||||||
|
if ($stmt->execute()) {
|
||||||
|
header('Location: ngo_signup.php?status=success');
|
||||||
|
} else {
|
||||||
|
header('Location: ngo_signup.php?status=error');
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
if ($e->errorInfo[1] == 1062) { // Duplicate entry
|
||||||
|
header('Location: ngo_signup.php?status=duplicate');
|
||||||
|
} else {
|
||||||
|
header('Location: ngo_signup.php?status=error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
header('Location: ngo_signup.php?status=invalid');
|
||||||
|
}
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>NGO Signup - Food Rescue</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body { font-family: 'Poppins', sans-serif; background-color: #f8f9fa; }
|
||||||
|
.navbar { box-shadow: 0 2px 4px rgba(0,0,0,.1); }
|
||||||
|
.card { border-radius: 0.5rem; border: none; box-shadow: 0 4px 8px rgba(0,0,0,.1); }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light bg-white sticky-top">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="index.php" style="font-weight: 600;">Food Rescue</a>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="index.php">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="add_listing.php">Add Listing</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="ngo_dashboard.php">NGO Dashboard</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="volunteer_signup.php">Volunteer Signup</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="volunteer_hub.php">Volunteer Hub</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="distribution_map.php">Distribution Map</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="admin_panel.php">Admin Panel</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container my-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="card p-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="card-title text-center mb-4">Register Your NGO</h2>
|
||||||
|
<?php if (isset($_GET['status'])): ?>
|
||||||
|
<div class="alert alert-<?php echo $_GET['status'] === 'success' ? 'success' : 'danger'; ?>" role="alert">
|
||||||
|
<?php
|
||||||
|
switch ($_GET['status']) {
|
||||||
|
case 'success':
|
||||||
|
echo 'Thank you for registering your NGO!';
|
||||||
|
break;
|
||||||
|
case 'duplicate':
|
||||||
|
echo 'This email is already registered.';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
echo 'Something went wrong. Please try again.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<form action="ngo_signup.php" method="POST">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="name" class="form-label">NGO Name</label>
|
||||||
|
<input type="text" class="form-control" id="name" name="name" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="email" class="form-label">Contact Email</label>
|
||||||
|
<input type="email" class="form-control" id="email" name="email" required>
|
||||||
|
</div>
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" class="btn btn-primary">Register</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
46
submit_listing.php
Normal file
46
submit_listing.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
header('Location: add_listing.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic server-side validation
|
||||||
|
if (empty($_POST['name']) || empty($_POST['quantity']) || empty($_POST['pickup_by'])) {
|
||||||
|
header('Location: add_listing.php?status=error');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = trim($_POST['name']);
|
||||||
|
$quantity = trim($_POST['quantity']);
|
||||||
|
$pickup_by = $_POST['pickup_by'];
|
||||||
|
$description = trim($_POST['description'] ?? '');
|
||||||
|
$latitude = filter_input(INPUT_POST, 'latitude', FILTER_VALIDATE_FLOAT);
|
||||||
|
$longitude = filter_input(INPUT_POST, 'longitude', FILTER_VALIDATE_FLOAT);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$sql = "INSERT INTO food_listings (name, quantity, pickup_by, description, latitude, longitude) VALUES (:name, :quantity, :pickup_by, :description, :latitude, :longitude)";
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
|
||||||
|
$stmt->bindParam(':name', $name, PDO::PARAM_STR);
|
||||||
|
$stmt->bindParam(':quantity', $quantity, PDO::PARAM_STR);
|
||||||
|
$stmt->bindParam(':pickup_by', $pickup_by, PDO::PARAM_STR);
|
||||||
|
$stmt->bindParam(':description', $description, PDO::PARAM_STR);
|
||||||
|
$stmt->bindParam(':latitude', $latitude, PDO::PARAM_STR); // PDO uses STR for decimals
|
||||||
|
$stmt->bindParam(':longitude', $longitude, PDO::PARAM_STR);
|
||||||
|
|
||||||
|
if ($stmt->execute()) {
|
||||||
|
header('Location: add_listing.php?status=success');
|
||||||
|
} else {
|
||||||
|
header('Location: add_listing.php?status=error');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// In a real app, you would log this error, not expose it.
|
||||||
|
// error_log($e->getMessage());
|
||||||
|
header('Location: add_listing.php?status=error');
|
||||||
|
}
|
||||||
|
|
||||||
|
exit();
|
||||||
40
update_pickup_status.php
Normal file
40
update_pickup_status.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['listing_id']) || !isset($_POST['status'])) {
|
||||||
|
header('Location: volunteer_dashboard.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$listing_id = filter_input(INPUT_POST, 'listing_id', FILTER_VALIDATE_INT);
|
||||||
|
$status = $_POST['status'];
|
||||||
|
|
||||||
|
// Basic validation
|
||||||
|
$allowed_statuses = ['collected', 'en-route', 'delivered'];
|
||||||
|
if ($listing_id === false || !in_array($status, $allowed_statuses)) {
|
||||||
|
header('Location: volunteer_dashboard.php?status=error');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// For this MVP, we are not checking if the volunteer is the one assigned.
|
||||||
|
// In a real app, you would verify the logged-in volunteer's ID against the assignment.
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$sql = "UPDATE food_listings SET status = :status WHERE id = :listing_id";
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->bindParam(':status', $status, PDO::PARAM_STR);
|
||||||
|
$stmt->bindParam(':listing_id', $listing_id, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
if ($stmt->execute()) {
|
||||||
|
header('Location: volunteer_dashboard.php?update=success');
|
||||||
|
} else {
|
||||||
|
header('Location: volunteer_dashboard.php?update=error');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// error_log($e->getMessage());
|
||||||
|
header('Location: volunteer_dashboard.php?update=error');
|
||||||
|
}
|
||||||
|
|
||||||
|
exit();
|
||||||
127
volunteer_dashboard.php
Normal file
127
volunteer_dashboard.php
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
// Simulate a logged-in volunteer
|
||||||
|
$volunteer_id = 1; // In a real app, this would come from a session
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Fetch the volunteer's details
|
||||||
|
$sql_volunteer = "SELECT name FROM volunteers WHERE id = :volunteer_id";
|
||||||
|
$stmt_volunteer = $pdo->prepare($sql_volunteer);
|
||||||
|
$stmt_volunteer->bindParam(':volunteer_id', $volunteer_id, PDO::PARAM_INT);
|
||||||
|
$stmt_volunteer->execute();
|
||||||
|
$volunteer = $stmt_volunteer->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Fetch listings assigned to this volunteer
|
||||||
|
$sql_listings = "SELECT l.id, l.name, l.quantity, l.status, l.pickup_by, n.name as ngo_name
|
||||||
|
FROM food_listings as l
|
||||||
|
JOIN volunteer_assignments as va ON l.id = va.listing_id
|
||||||
|
LEFT JOIN ngos as n ON l.ngo_id = n.id
|
||||||
|
WHERE va.volunteer_id = :volunteer_id
|
||||||
|
ORDER BY l.pickup_by DESC";
|
||||||
|
$stmt_listings = $pdo->prepare($sql_listings);
|
||||||
|
$stmt_listings->bindParam(':volunteer_id', $volunteer_id, PDO::PARAM_INT);
|
||||||
|
$stmt_listings->execute();
|
||||||
|
$assignments = $stmt_listings->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$volunteer = false;
|
||||||
|
$assignments = [];
|
||||||
|
// error_log($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusBadge($status) {
|
||||||
|
$badges = [
|
||||||
|
'assigned' => '<span class="badge bg-primary">Assigned</span>',
|
||||||
|
'collected' => '<span class="badge bg-info">Collected</span>',
|
||||||
|
'en-route' => '<span class="badge bg-warning text-dark">En Route</span>',
|
||||||
|
'delivered' => '<span class="badge bg-success">Delivered</span>',
|
||||||
|
];
|
||||||
|
return $badges[$status] ?? '<span class="badge bg-secondary">Unknown</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNextAction($status, $listing_id) {
|
||||||
|
$actions = [
|
||||||
|
'assigned' => '<button type="submit" name="status" value="collected" class="btn btn-sm btn-primary">Mark Collected</button>',
|
||||||
|
'collected' => '<button type="submit" name="status" value="en-route" class="btn btn-sm btn-warning">Mark En Route</button>',
|
||||||
|
'en-route' => '<button type="submit" name="status" value="delivered" class="btn btn-sm btn-success">Mark Delivered</button>',
|
||||||
|
];
|
||||||
|
if (isset($actions[$status])) {
|
||||||
|
return '<form action="update_pickup_status.php" method="POST" class="d-inline"><input type="hidden" name="listing_id" value="'.$listing_id.'">'.$actions[$status].'</form>';
|
||||||
|
}
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Volunteer Dashboard - Food Rescue</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body { font-family: 'Poppins', sans-serif; background-color: #f8f9fa; }
|
||||||
|
.navbar { box-shadow: 0 2px 4px rgba(0,0,0,.1); }
|
||||||
|
.table { background-color: #fff; box-shadow: 0 4px 8px rgba(0,0,0,.1); }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light bg-white sticky-top">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="index.php" style="font-weight: 600;">Food Rescue</a>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="index.php">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="add_listing.php">Add Listing</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="ngo_dashboard.php">NGO Dashboard</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="volunteer_signup.php">Volunteer Signup</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link active" href="volunteer_dashboard.php">Volunteer Dashboard</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="distribution_map.php">Distribution Map</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="admin_panel.php">Admin Panel</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container my-5">
|
||||||
|
<h1 class="h2 mb-4">Dashboard: <?= $volunteer ? htmlspecialchars($volunteer['name']) : 'Volunteer' ?></h1>
|
||||||
|
|
||||||
|
<?php if (empty($assignments)): ?>
|
||||||
|
<div class="card p-5 text-center">
|
||||||
|
<p class="mb-0 text-muted">You have no assigned pickups. Visit the <a href="volunteer_hub_old.php">Volunteer Hub</a> to find available jobs.</p>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover align-middle">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>Food Item</th>
|
||||||
|
<th>Destination NGO</th>
|
||||||
|
<th>Pickup By</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($assignments as $assignment): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($assignment['name']) ?></td>
|
||||||
|
<td><?= htmlspecialchars($assignment['ngo_name']) ?></td>
|
||||||
|
<td><?= date('M d, Y h:i A', strtotime($assignment['pickup_by'])) ?></td>
|
||||||
|
<td><?= getStatusBadge($assignment['status']) ?></td>
|
||||||
|
<td><?= getNextAction($assignment['status'], $assignment['id']) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div class="mt-4 text-center">
|
||||||
|
<a href="volunteer_hub_old.php" class="btn btn-outline-primary">Find New Pickups</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
93
volunteer_hub_old.php
Normal file
93
volunteer_hub_old.php
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Fetch claimed listings
|
||||||
|
$sql_listings = "SELECT id, name, quantity, pickup_by FROM food_listings WHERE status = 'claimed' ORDER BY pickup_by ASC";
|
||||||
|
$stmt_listings = $pdo->query($sql_listings);
|
||||||
|
$listings = $stmt_listings->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Simulate a logged-in volunteer by fetching the first volunteer
|
||||||
|
$sql_volunteer = "SELECT id, name FROM volunteers ORDER BY id ASC LIMIT 1";
|
||||||
|
$stmt_volunteer = $pdo->query($sql_volunteer);
|
||||||
|
$volunteer = $stmt_volunteer->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$listings = [];
|
||||||
|
$volunteer = false;
|
||||||
|
// error_log($e->getMessage());
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Volunteer Hub - Food Rescue</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body { font-family: 'Poppins', sans-serif; background-color: #f8f9fa; }
|
||||||
|
.navbar { box-shadow: 0 2px 4px rgba(0,0,0,.1); }
|
||||||
|
.card { border-radius: 0.5rem; border: none; box-shadow: 0 4px 8px rgba(0,0,0,.1); }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light bg-white sticky-top">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="index.php" style="font-weight: 600;">Food Rescue</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"><span class="navbar-toggler-icon"></span></button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="index.php">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="add_listing.php">Add Listing</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="ngo_dashboard.php">NGO Dashboard</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="volunteer_signup.php">Volunteer Signup</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link active" href="volunteer_hub.php">Volunteer Hub</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="distribution_map.php">Distribution Map</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="ngo_signup.php">NGO Signup</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container my-5">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h1 class="h2">Available for Pickup</h1>
|
||||||
|
<?php if ($volunteer): ?>
|
||||||
|
<span class="badge bg-primary">Logged in as: <?= htmlspecialchars($volunteer['name']) ?></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if (!$volunteer): ?>
|
||||||
|
<div class="alert alert-warning">Please <a href="volunteer_signup.php">sign up as a volunteer</a> to see and accept pickups.</div>
|
||||||
|
<?php elseif (empty($listings)): ?>
|
||||||
|
<div class="card p-5 text-center">
|
||||||
|
<p class="mb-0 text-muted">There are no donations ready for pickup right now.</p>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="list-group">
|
||||||
|
<?php foreach ($listings as $listing): ?>
|
||||||
|
<div class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
<h5 class="mb-1"><?= htmlspecialchars($listing['name']) ?> (<?= htmlspecialchars($listing['quantity']) ?>)</h5>
|
||||||
|
<small>Pickup by: <?= date('M d, Y h:i A', strtotime($listing['pickup_by'])) ?></small>
|
||||||
|
</div>
|
||||||
|
<form action="assign_pickup.php" method="POST">
|
||||||
|
<input type="hidden" name="listing_id" value="<?= $listing['id'] ?>">
|
||||||
|
<input type="hidden" name="volunteer_id" value="<?= $volunteer['id'] ?>">
|
||||||
|
<button type="submit" class="btn btn-sm btn-info">Assign to Me</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
115
volunteer_signup.php
Normal file
115
volunteer_signup.php
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
<?php
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
$name = trim($_POST['name'] ?? '');
|
||||||
|
$email = trim($_POST['email'] ?? '');
|
||||||
|
|
||||||
|
if (!empty($name) && filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$sql = "INSERT INTO volunteers (name, email) VALUES (:name, :email)";
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->bindParam(':name', $name, PDO::PARAM_STR);
|
||||||
|
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
|
||||||
|
if ($stmt->execute()) {
|
||||||
|
header('Location: volunteer_signup.php?status=success');
|
||||||
|
} else {
|
||||||
|
header('Location: volunteer_signup.php?status=error');
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
if ($e->errorInfo[1] == 1062) { // Duplicate entry
|
||||||
|
header('Location: volunteer_signup.php?status=duplicate');
|
||||||
|
} else {
|
||||||
|
header('Location: volunteer_signup.php?status=error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
header('Location: volunteer_signup.php?status=invalid');
|
||||||
|
}
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Volunteer Signup - Food Rescue</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body { font-family: 'Poppins', sans-serif; background-color: #f8f9fa; }
|
||||||
|
.navbar { box-shadow: 0 2px 4px rgba(0,0,0,.1); }
|
||||||
|
.card { border-radius: 0.5rem; border: none; box-shadow: 0 4px 8px rgba(0,0,0,.1); }
|
||||||
|
.form-label { font-weight: 600; }
|
||||||
|
.btn-primary { background-color: #0d6efd; border-color: #0d6efd; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light bg-white sticky-top">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="index.php" style="font-weight: 600;">Food Rescue</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"><span class="navbar-toggler-icon"></span></button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="index.php">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="add_listing.php">Add Listing</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="ngo_dashboard.php">NGO Dashboard</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link active" href="volunteer_signup.php">Volunteer Signup</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="volunteer_dashboard.php">Volunteer Dashboard</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="volunteer_hub_old.php">Find Pickups</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="distribution_map.php">Distribution Map</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="admin_panel.php">Admin Panel</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container my-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="card p-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="card-title text-center mb-4">Join as a Volunteer</h2>
|
||||||
|
<?php if (isset($_GET['status'])): ?>
|
||||||
|
<div class="alert alert-<?php echo $_GET['status'] === 'success' ? 'success' : 'danger'; ?>" role="alert">
|
||||||
|
<?php
|
||||||
|
switch ($_GET['status']) {
|
||||||
|
case 'success':
|
||||||
|
echo 'Thank you for signing up!';
|
||||||
|
break;
|
||||||
|
case 'duplicate':
|
||||||
|
echo 'This email is already registered.';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
echo 'Something went wrong. Please try again.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<form action="volunteer_signup.php" method="POST">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="name" class="form-label">Full Name</label>
|
||||||
|
<input type="text" class="form-control" id="name" name="name" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="email" class="form-label">Email Address</label>
|
||||||
|
<input type="email" class="form-control" id="email" name="email" required>
|
||||||
|
</div>
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" class="btn btn-primary">Sign Up</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user