add financial summery
This commit is contained in:
parent
a4dccb579a
commit
699f776eee
80
admin/audit_logs.php
Normal file
80
admin/audit_logs.php
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'auth.php';
|
||||||
|
require_once '../db/config.php';
|
||||||
|
require_login();
|
||||||
|
|
||||||
|
$user = get_user();
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Fetch audit logs with user info
|
||||||
|
$logs = $pdo->query("
|
||||||
|
SELECT l.*, u.email as user_email
|
||||||
|
FROM audit_logs l
|
||||||
|
LEFT JOIN users u ON l.user_id = u.id
|
||||||
|
ORDER BY l.created_at DESC
|
||||||
|
LIMIT 100
|
||||||
|
")->fetchAll();
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Audit Logs - CharityHub Admin</title>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
||||||
|
<style>
|
||||||
|
:root { --sidebar-width: 260px; --primary-color: #059669; }
|
||||||
|
body { background-color: #f3f4f6; }
|
||||||
|
.sidebar { width: var(--sidebar-width); height: 100vh; position: fixed; left: 0; top: 0; background: #111827; color: #fff; padding: 1.5rem; }
|
||||||
|
.main-content { margin-left: var(--sidebar-width); padding: 2rem; }
|
||||||
|
.nav-link { color: #9ca3af; margin-bottom: 0.5rem; border-radius: 8px; }
|
||||||
|
.nav-link:hover, .nav-link.active { color: #fff; background: #1f2937; }
|
||||||
|
.nav-link.active { background: var(--primary-color); }
|
||||||
|
.card { border: none; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php include "sidebar.php"; ?>
|
||||||
|
|
||||||
|
<div class="main-content">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h2 class="mb-0">Activity Audit Logs</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card p-0">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover mb-0">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th class="ps-4">User</th>
|
||||||
|
<th>Action</th>
|
||||||
|
<th>Details</th>
|
||||||
|
<th>Date</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($logs as $log): ?>
|
||||||
|
<tr>
|
||||||
|
<td class="ps-4">
|
||||||
|
<strong><?= htmlspecialchars($log['user_email'] ?? 'System/Unknown') ?></strong>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge bg-secondary rounded-pill"><?= htmlspecialchars($log['action']) ?></span>
|
||||||
|
</td>
|
||||||
|
<td><?= htmlspecialchars($log['details']) ?></td>
|
||||||
|
<td><?= date('Y-m-d H:i:s', strtotime($log['created_at'])) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php if (empty($logs)): ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" class="text-center py-4 text-muted">No logs found.</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -44,3 +44,15 @@ function is_super_admin() {
|
|||||||
$user = get_user();
|
$user = get_user();
|
||||||
return $user && $user['role'] === 'super_admin';
|
return $user && $user['role'] === 'super_admin';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log an administrative action to the audit_logs table
|
||||||
|
*/
|
||||||
|
function log_action($action, $details = null) {
|
||||||
|
require_once __DIR__ . '/../db/config.php';
|
||||||
|
$pdo = db();
|
||||||
|
$userId = $_SESSION['user_id'] ?? null;
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO audit_logs (user_id, action, details) VALUES (?, ?, ?)");
|
||||||
|
$stmt->execute([$userId, $action, $details]);
|
||||||
|
}
|
||||||
|
|||||||
@ -6,10 +6,41 @@ require_login();
|
|||||||
$pdo = db();
|
$pdo = db();
|
||||||
$msg = '';
|
$msg = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic Image Optimization
|
||||||
|
*/
|
||||||
|
function optimize_image($source, $destination, $quality = 80) {
|
||||||
|
$info = getimagesize($source);
|
||||||
|
if ($info['mime'] == 'image/jpeg') {
|
||||||
|
$image = imagecreatefromjpeg($source);
|
||||||
|
imagejpeg($image, $destination, $quality);
|
||||||
|
} elseif ($info['mime'] == 'image/png') {
|
||||||
|
$image = imagecreatefrompng($source);
|
||||||
|
imagepalettetotruecolor($image);
|
||||||
|
imagealphablending($image, false);
|
||||||
|
imagesavealpha($image, true);
|
||||||
|
imagepng($image, $destination, round(9 * ($quality/100)));
|
||||||
|
} elseif ($info['mime'] == 'image/webp') {
|
||||||
|
$image = imagecreatefromwebp($source);
|
||||||
|
imagewebp($image, $destination, $quality);
|
||||||
|
}
|
||||||
|
return $destination;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle Delete
|
// Handle Delete
|
||||||
if (isset($_GET['delete'])) {
|
if (isset($_GET['delete'])) {
|
||||||
$id = (int)$_GET['delete'];
|
$id = (int)$_GET['delete'];
|
||||||
$pdo->prepare("DELETE FROM cases WHERE id = ?")->execute([$id]);
|
|
||||||
|
// Fetch title for logging before deleting
|
||||||
|
$stmt = $pdo->prepare("SELECT title_en FROM cases WHERE id = ?");
|
||||||
|
$stmt->execute([$id]);
|
||||||
|
$case_to_delete = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($case_to_delete) {
|
||||||
|
$pdo->prepare("DELETE FROM cases WHERE id = ?")->execute([$id]);
|
||||||
|
log_action('delete_case', "Deleted case: " . $case_to_delete['title_en'] . " (ID: $id)");
|
||||||
|
}
|
||||||
|
|
||||||
header('Location: cases.php?success=deleted');
|
header('Location: cases.php?success=deleted');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@ -40,7 +71,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$upload_dir = '../assets/images/cases/';
|
$upload_dir = '../assets/images/cases/';
|
||||||
if (!is_dir($upload_dir)) mkdir($upload_dir, 0775, true);
|
if (!is_dir($upload_dir)) mkdir($upload_dir, 0775, true);
|
||||||
|
|
||||||
if (move_uploaded_file($_FILES['image']['tmp_name'], $upload_dir . $filename)) {
|
$temp_path = $_FILES['image']['tmp_name'];
|
||||||
|
$target_path = $upload_dir . $filename;
|
||||||
|
|
||||||
|
if (move_uploaded_file($temp_path, $target_path)) {
|
||||||
|
// Optimize the uploaded image
|
||||||
|
if ($ext !== 'gif') {
|
||||||
|
optimize_image($target_path, $target_path, 75);
|
||||||
|
}
|
||||||
$image_url = 'assets/images/cases/' . $filename;
|
$image_url = 'assets/images/cases/' . $filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,9 +87,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
if ($id) {
|
if ($id) {
|
||||||
$stmt = $pdo->prepare("UPDATE cases SET category_id=?, title_en=?, title_ar=?, desc_en=?, desc_ar=?, goal=?, image_url=?, importance=?, status=? WHERE id=?");
|
$stmt = $pdo->prepare("UPDATE cases SET category_id=?, title_en=?, title_ar=?, desc_en=?, desc_ar=?, goal=?, image_url=?, importance=?, status=? WHERE id=?");
|
||||||
$stmt->execute([$category_id, $title_en, $title_ar, $desc_en, $desc_ar, $goal, $image_url, $importance, $status, $id]);
|
$stmt->execute([$category_id, $title_en, $title_ar, $desc_en, $desc_ar, $goal, $image_url, $importance, $status, $id]);
|
||||||
|
log_action('edit_case', "Updated case: $title_en (ID: $id)");
|
||||||
} else {
|
} else {
|
||||||
$stmt = $pdo->prepare("INSERT INTO cases (category_id, title_en, title_ar, desc_en, desc_ar, goal, raised, image_url, importance, status) VALUES (?, ?, ?, ?, ?, ?, 0, ?, ?, ?)");
|
$stmt = $pdo->prepare("INSERT INTO cases (category_id, title_en, title_ar, desc_en, desc_ar, goal, raised, image_url, importance, status) VALUES (?, ?, ?, ?, ?, ?, 0, ?, ?, ?)");
|
||||||
$stmt->execute([$category_id, $title_en, $title_ar, $desc_en, $desc_ar, $goal, $image_url, $importance, $status]);
|
$stmt->execute([$category_id, $title_en, $title_ar, $desc_en, $desc_ar, $goal, $image_url, $importance, $status]);
|
||||||
|
$new_id = $pdo->lastInsertId();
|
||||||
|
log_action('create_case', "Created new case: $title_en (ID: $new_id)");
|
||||||
}
|
}
|
||||||
header('Location: cases.php?success=saved');
|
header('Location: cases.php?success=saved');
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@ -40,7 +40,10 @@ $donations = $pdo->query("SELECT d.*, c.title_en as case_title, cat.name_en as c
|
|||||||
|
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<h2>Donations History</h2>
|
<h2 class="mb-0">Donations History</h2>
|
||||||
|
<a href="export_donations.php" class="btn btn-outline-success">
|
||||||
|
<i class="bi bi-file-earmark-excel me-2"></i>Export to CSV
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card p-0">
|
<div class="card p-0">
|
||||||
@ -61,6 +64,9 @@ $donations = $pdo->query("SELECT d.*, c.title_en as case_title, cat.name_en as c
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="ps-4">
|
<td class="ps-4">
|
||||||
<strong><?= htmlspecialchars($don['donor_name'] ?: 'Anonymous') ?></strong>
|
<strong><?= htmlspecialchars($don['donor_name'] ?: 'Anonymous') ?></strong>
|
||||||
|
<?php if ($don['is_gift']): ?>
|
||||||
|
<span class="badge bg-info-subtle text-info rounded-pill ms-2" style="font-size: 0.7rem;">Gift</span>
|
||||||
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="small"><?= htmlspecialchars($don['donor_email']) ?></div>
|
<div class="small"><?= htmlspecialchars($don['donor_email']) ?></div>
|
||||||
|
|||||||
88
admin/donors.php
Normal file
88
admin/donors.php
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'auth.php';
|
||||||
|
require_once '../db/config.php';
|
||||||
|
require_login();
|
||||||
|
|
||||||
|
$user = get_user();
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Fetch unique donors based on email, with total amount and count
|
||||||
|
$donors = $pdo->query("
|
||||||
|
SELECT
|
||||||
|
donor_email,
|
||||||
|
donor_name,
|
||||||
|
donor_phone,
|
||||||
|
SUM(amount) as total_contributed,
|
||||||
|
COUNT(*) as donation_count,
|
||||||
|
MAX(created_at) as last_donation
|
||||||
|
FROM donations
|
||||||
|
WHERE status = 'completed'
|
||||||
|
GROUP BY donor_email
|
||||||
|
ORDER BY total_contributed DESC
|
||||||
|
")->fetchAll();
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Donors CRM - CharityHub Admin</title>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
||||||
|
<style>
|
||||||
|
:root { --sidebar-width: 260px; --primary-color: #059669; }
|
||||||
|
body { background-color: #f3f4f6; }
|
||||||
|
.sidebar { width: var(--sidebar-width); height: 100vh; position: fixed; left: 0; top: 0; background: #111827; color: #fff; padding: 1.5rem; }
|
||||||
|
.main-content { margin-left: var(--sidebar-width); padding: 2rem; }
|
||||||
|
.nav-link { color: #9ca3af; margin-bottom: 0.5rem; border-radius: 8px; }
|
||||||
|
.nav-link:hover, .nav-link.active { color: #fff; background: #1f2937; }
|
||||||
|
.nav-link.active { background: var(--primary-color); }
|
||||||
|
.card { border: none; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php include "sidebar.php"; ?>
|
||||||
|
|
||||||
|
<div class="main-content">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h2 class="mb-0">Donor CRM</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card p-0">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover mb-0">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th class="ps-4">Donor Name</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Phone</th>
|
||||||
|
<th>Donations</th>
|
||||||
|
<th>Total Amount</th>
|
||||||
|
<th>Last Donation</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($donors as $donor): ?>
|
||||||
|
<tr>
|
||||||
|
<td class="ps-4">
|
||||||
|
<strong><?= htmlspecialchars($donor['donor_name'] ?: 'Anonymous') ?></strong>
|
||||||
|
</td>
|
||||||
|
<td><?= htmlspecialchars($donor['donor_email']) ?></td>
|
||||||
|
<td><?= htmlspecialchars($donor['donor_phone'] ?? 'N/A') ?></td>
|
||||||
|
<td><span class="badge bg-primary rounded-pill"><?= $donor['donation_count'] ?></span></td>
|
||||||
|
<td><strong>OMR <?= number_format($donor['total_contributed'], 3) ?></strong></td>
|
||||||
|
<td class="small text-muted"><?= date('M j, Y', strtotime($donor['last_donation'])) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php if (empty($donors)): ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="text-center py-4 text-muted">No donors found with completed payments.</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
47
admin/export_donations.php
Normal file
47
admin/export_donations.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'auth.php';
|
||||||
|
require_once '../db/config.php';
|
||||||
|
require_login();
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Fetch all donations with details
|
||||||
|
$stmt = $pdo->query("
|
||||||
|
SELECT d.id, d.donor_name, d.donor_email, d.donor_phone, c.title_en as case_title, d.amount, d.status, d.transaction_id, d.created_at, d.is_gift, d.gift_recipient_name, d.gift_recipient_phone
|
||||||
|
FROM donations d
|
||||||
|
JOIN cases c ON d.case_id = c.id
|
||||||
|
ORDER BY d.created_at DESC
|
||||||
|
");
|
||||||
|
|
||||||
|
$filename = "donations_" . date('Y-m-d') . ".csv";
|
||||||
|
|
||||||
|
header('Content-Type: text/csv; charset=utf-8');
|
||||||
|
header('Content-Disposition: attachment; filename=' . $filename);
|
||||||
|
|
||||||
|
$output = fopen('php://output', 'w');
|
||||||
|
|
||||||
|
// Set CSV headers
|
||||||
|
fputcsv($output, [
|
||||||
|
'ID',
|
||||||
|
'Donor Name',
|
||||||
|
'Donor Email',
|
||||||
|
'Donor Phone',
|
||||||
|
'Case',
|
||||||
|
'Amount (OMR)',
|
||||||
|
'Status',
|
||||||
|
'Transaction ID',
|
||||||
|
'Date',
|
||||||
|
'Is Gift',
|
||||||
|
'Recipient Name',
|
||||||
|
'Recipient Phone'
|
||||||
|
]);
|
||||||
|
|
||||||
|
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
// Clean up status for CSV
|
||||||
|
$row['status'] = ucfirst($row['status']);
|
||||||
|
$row['is_gift'] = $row['is_gift'] ? 'Yes' : 'No';
|
||||||
|
fputcsv($output, $row);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($output);
|
||||||
|
exit;
|
||||||
281
admin/financial_summary.php
Normal file
281
admin/financial_summary.php
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'auth.php';
|
||||||
|
require_once '../db/config.php';
|
||||||
|
require_login();
|
||||||
|
|
||||||
|
$user = get_user();
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Basic Stats
|
||||||
|
$stats = $pdo->query("
|
||||||
|
SELECT
|
||||||
|
COUNT(*) as total_count,
|
||||||
|
SUM(CASE WHEN status = 'completed' THEN amount ELSE 0 END) as total_revenue,
|
||||||
|
AVG(CASE WHEN status = 'completed' THEN amount ELSE NULL END) as avg_donation,
|
||||||
|
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending_count,
|
||||||
|
SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed_count
|
||||||
|
FROM donations
|
||||||
|
")->fetch();
|
||||||
|
|
||||||
|
// Revenue by Category
|
||||||
|
$category_revenue = $pdo->query("
|
||||||
|
SELECT c.name_en, SUM(d.amount) as total
|
||||||
|
FROM categories c
|
||||||
|
JOIN cases cs ON cs.category_id = c.id
|
||||||
|
JOIN donations d ON d.case_id = cs.id
|
||||||
|
WHERE d.status = 'completed'
|
||||||
|
GROUP BY c.id
|
||||||
|
ORDER BY total DESC
|
||||||
|
")->fetchAll();
|
||||||
|
|
||||||
|
$cat_labels = [];
|
||||||
|
$cat_totals = [];
|
||||||
|
foreach ($category_revenue as $row) {
|
||||||
|
$cat_labels[] = $row['name_en'];
|
||||||
|
$cat_totals[] = (float)$row['total'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monthly Revenue Trend (Last 12 Months)
|
||||||
|
$monthly_trend = $pdo->query("
|
||||||
|
SELECT
|
||||||
|
DATE_FORMAT(created_at, '%Y-%m') as month,
|
||||||
|
SUM(amount) as total
|
||||||
|
FROM donations
|
||||||
|
WHERE status = 'completed' AND created_at >= DATE_SUB(NOW(), INTERVAL 12 MONTH)
|
||||||
|
GROUP BY month
|
||||||
|
ORDER BY month ASC
|
||||||
|
")->fetchAll();
|
||||||
|
|
||||||
|
$trend_labels = [];
|
||||||
|
$trend_totals = [];
|
||||||
|
foreach ($monthly_trend as $row) {
|
||||||
|
$trend_labels[] = date('M Y', strtotime($row['month'] . '-01'));
|
||||||
|
$trend_totals[] = (float)$row['total'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top Cases by Revenue
|
||||||
|
$top_cases = $pdo->query("
|
||||||
|
SELECT cs.title_en, SUM(d.amount) as total, cs.goal
|
||||||
|
FROM cases cs
|
||||||
|
JOIN donations d ON d.case_id = cs.id
|
||||||
|
WHERE d.status = 'completed'
|
||||||
|
GROUP BY cs.id
|
||||||
|
ORDER BY total DESC
|
||||||
|
LIMIT 5
|
||||||
|
")->fetchAll();
|
||||||
|
|
||||||
|
// Gift vs Regular
|
||||||
|
$gift_stats = $pdo->query("
|
||||||
|
SELECT
|
||||||
|
is_gift,
|
||||||
|
COUNT(*) as count,
|
||||||
|
SUM(amount) as total
|
||||||
|
FROM donations
|
||||||
|
WHERE status = 'completed'
|
||||||
|
GROUP BY is_gift
|
||||||
|
")->fetchAll();
|
||||||
|
|
||||||
|
$gift_labels = ['Regular', 'Gift'];
|
||||||
|
$gift_totals = [0, 0];
|
||||||
|
foreach ($gift_stats as $row) {
|
||||||
|
if ($row['is_gift']) {
|
||||||
|
$gift_totals[1] = (float)$row['total'];
|
||||||
|
} else {
|
||||||
|
$gift_totals[0] = (float)$row['total'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Financial Summary - CharityHub Admin</title>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<style>
|
||||||
|
:root { --sidebar-width: 260px; --primary-color: #059669; }
|
||||||
|
body { background-color: #f3f4f6; }
|
||||||
|
.sidebar { width: var(--sidebar-width); height: 100vh; position: fixed; left: 0; top: 0; background: #111827; color: #fff; padding: 1.5rem; }
|
||||||
|
.main-content { margin-left: var(--sidebar-width); padding: 2rem; }
|
||||||
|
.card { border: none; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
|
||||||
|
.stat-card { padding: 1.5rem; border-left: 4px solid var(--primary-color); }
|
||||||
|
.chart-container { position: relative; height: 250px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php include "sidebar.php"; ?>
|
||||||
|
|
||||||
|
<div class="main-content">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<div>
|
||||||
|
<h2 class="mb-0">Financial Summary</h2>
|
||||||
|
<p class="text-muted mb-0">Detailed analysis of donations and revenue streams.</p>
|
||||||
|
</div>
|
||||||
|
<div class="text-muted"><?= date('l, F j, Y') ?></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Summary Cards -->
|
||||||
|
<div class="row g-4 mb-4">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card stat-card">
|
||||||
|
<div class="text-muted small">Total Revenue</div>
|
||||||
|
<div class="h3 mb-0">OMR <?= number_format($stats['total_revenue'] ?? 0, 3) ?></div>
|
||||||
|
<div class="text-success small"><i class="bi bi-check-circle"></i> From <?= $stats['completed_count'] ?> donations</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card stat-card" style="border-left-color: #3b82f6;">
|
||||||
|
<div class="text-muted small">Avg. Donation</div>
|
||||||
|
<div class="h3 mb-0">OMR <?= number_format($stats['avg_donation'] ?? 0, 3) ?></div>
|
||||||
|
<div class="text-primary small">Per completed donation</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card stat-card" style="border-left-color: #f59e0b;">
|
||||||
|
<div class="text-muted small">Pending Revenue</div>
|
||||||
|
<div class="h3 mb-0"><?= $stats['pending_count'] ?></div>
|
||||||
|
<div class="text-warning small">Awaiting payment</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card stat-card" style="border-left-color: #ec4899;">
|
||||||
|
<div class="text-muted small">Total Donations</div>
|
||||||
|
<div class="h3 mb-0"><?= $stats['total_count'] ?></div>
|
||||||
|
<div class="text-danger small">All statuses included</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-4 mb-4">
|
||||||
|
<!-- Monthly Trend -->
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card p-4 h-100">
|
||||||
|
<h5 class="mb-4">Monthly Revenue Trend (Last 12 Months)</h5>
|
||||||
|
<div style="height: 300px;">
|
||||||
|
<canvas id="trendChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Category Distribution -->
|
||||||
|
<div class="col-lg-4">
|
||||||
|
<div class="card p-4 h-100">
|
||||||
|
<h5 class="mb-4">Revenue by Category</h5>
|
||||||
|
<div class="chart-container">
|
||||||
|
<canvas id="categoryChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-4 mb-4">
|
||||||
|
<!-- Top Cases -->
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="card p-4 h-100">
|
||||||
|
<h5 class="mb-4">Top Performing Cases</h5>
|
||||||
|
<div class="list-group list-group-flush">
|
||||||
|
<?php foreach ($top_cases as $case): ?>
|
||||||
|
<div class="list-group-item px-0 border-0 mb-3">
|
||||||
|
<div class="d-flex justify-content-between mb-1">
|
||||||
|
<span class="fw-bold"><?= htmlspecialchars($case['title_en']) ?></span>
|
||||||
|
<span>OMR <?= number_format($case['total'], 3) ?></span>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
$percent = $case['goal'] > 0 ? ($case['total'] / $case['goal']) * 100 : 0;
|
||||||
|
?>
|
||||||
|
<div class="progress" style="height: 8px;">
|
||||||
|
<div class="progress-bar bg-success" role="progressbar" style="width: <?= min(100, $percent) ?>%"></div>
|
||||||
|
</div>
|
||||||
|
<div class="text-muted small mt-1"><?= number_format($percent, 1) ?>% of OMR <?= number_format($case['goal'], 0) ?> goal</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Gift vs Regular -->
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="card p-4 h-100">
|
||||||
|
<h5 class="mb-4">Regular vs Gift Donations (Revenue)</h5>
|
||||||
|
<div class="d-flex align-items-center justify-content-center" style="height: 250px;">
|
||||||
|
<canvas id="giftChart"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 row text-center">
|
||||||
|
<div class="col-6">
|
||||||
|
<div class="text-muted small">Regular</div>
|
||||||
|
<div class="h5">OMR <?= number_format($gift_totals[0], 3) ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<div class="text-muted small">Gift</div>
|
||||||
|
<div class="h5">OMR <?= number_format($gift_totals[1], 3) ?></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Trend Chart
|
||||||
|
new Chart(document.getElementById('trendChart'), {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: <?= json_encode($trend_labels) ?>,
|
||||||
|
datasets: [{
|
||||||
|
label: 'Revenue (OMR)',
|
||||||
|
data: <?= json_encode($trend_totals) ?>,
|
||||||
|
backgroundColor: '#059669',
|
||||||
|
borderRadius: 6
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {
|
||||||
|
y: { beginAtZero: true, grid: { color: '#f3f4f6' } },
|
||||||
|
x: { grid: { display: false } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Category Chart
|
||||||
|
new Chart(document.getElementById('categoryChart'), {
|
||||||
|
type: 'doughnut',
|
||||||
|
data: {
|
||||||
|
labels: <?= json_encode($cat_labels) ?>,
|
||||||
|
datasets: [{
|
||||||
|
data: <?= json_encode($cat_totals) ?>,
|
||||||
|
backgroundColor: ['#059669', '#3b82f6', '#f59e0b', '#ec4899', '#8b5cf6', '#06b6d4']
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
plugins: {
|
||||||
|
legend: { position: 'bottom', labels: { boxWidth: 12 } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Gift Chart
|
||||||
|
new Chart(document.getElementById('giftChart'), {
|
||||||
|
type: 'pie',
|
||||||
|
data: {
|
||||||
|
labels: <?= json_encode($gift_labels) ?>,
|
||||||
|
datasets: [{
|
||||||
|
data: <?= json_encode($gift_totals) ?>,
|
||||||
|
backgroundColor: ['#10b981', '#f472b6']
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
plugins: {
|
||||||
|
legend: { display: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -11,6 +11,22 @@ $total_categories = $pdo->query("SELECT COUNT(*) FROM categories")->fetchColumn(
|
|||||||
$total_cases = $pdo->query("SELECT COUNT(*) FROM cases")->fetchColumn();
|
$total_cases = $pdo->query("SELECT COUNT(*) FROM cases")->fetchColumn();
|
||||||
$total_donations = $pdo->query("SELECT SUM(amount) FROM donations WHERE status = 'completed'")->fetchColumn() ?: 0;
|
$total_donations = $pdo->query("SELECT SUM(amount) FROM donations WHERE status = 'completed'")->fetchColumn() ?: 0;
|
||||||
|
|
||||||
|
// Fetch chart data (last 30 days)
|
||||||
|
$chart_data = $pdo->query("
|
||||||
|
SELECT DATE(created_at) as date, SUM(amount) as total
|
||||||
|
FROM donations
|
||||||
|
WHERE status = 'completed' AND created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)
|
||||||
|
GROUP BY DATE(created_at)
|
||||||
|
ORDER BY date ASC
|
||||||
|
")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$labels = [];
|
||||||
|
$totals = [];
|
||||||
|
foreach ($chart_data as $row) {
|
||||||
|
$labels[] = date('M j', strtotime($row['date']));
|
||||||
|
$totals[] = (float)$row['total'];
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch recent donations
|
// Fetch recent donations
|
||||||
$recent_donations = $pdo->query("
|
$recent_donations = $pdo->query("
|
||||||
SELECT d.*, c.title_en as case_title
|
SELECT d.*, c.title_en as case_title
|
||||||
@ -28,6 +44,7 @@ $recent_donations = $pdo->query("
|
|||||||
<title>Dashboard - CharityHub Admin</title>
|
<title>Dashboard - CharityHub Admin</title>
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
<style>
|
<style>
|
||||||
:root { --sidebar-width: 260px; --primary-color: #059669; }
|
:root { --sidebar-width: 260px; --primary-color: #059669; }
|
||||||
body { background-color: #f3f4f6; }
|
body { background-color: #f3f4f6; }
|
||||||
@ -42,6 +59,7 @@ $recent_donations = $pdo->query("
|
|||||||
.badge-pending { background-color: #fef3c7; color: #92400e; }
|
.badge-pending { background-color: #fef3c7; color: #92400e; }
|
||||||
.badge-completed { background-color: #d1fae5; color: #065f46; }
|
.badge-completed { background-color: #d1fae5; color: #065f46; }
|
||||||
.badge-failed { background-color: #fee2e2; color: #991b1b; }
|
.badge-failed { background-color: #fee2e2; color: #991b1b; }
|
||||||
|
.chart-container { height: 300px; position: relative; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -92,6 +110,27 @@ $recent_donations = $pdo->query("
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-4 mb-4">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card p-4">
|
||||||
|
<h5 class="mb-4">Donation Trends (Last 30 Days)</h5>
|
||||||
|
<div class="chart-container">
|
||||||
|
<canvas id="donationsChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-4">
|
||||||
|
<div class="card p-4 h-100">
|
||||||
|
<h5 class="mb-4">Quick Links</h5>
|
||||||
|
<div class="d-grid gap-2">
|
||||||
|
<a href="cases.php" class="btn btn-outline-primary text-start"><i class="bi bi-plus-circle me-2"></i> Create New Case</a>
|
||||||
|
<a href="donations.php" class="btn btn-outline-success text-start"><i class="bi bi-download me-2"></i> Export Donations</a>
|
||||||
|
<a href="settings.php" class="btn btn-outline-secondary text-start"><i class="bi bi-gear me-2"></i> System Settings</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card p-4">
|
<div class="card p-4">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
<h5 class="mb-0">Recent Donations</h5>
|
<h5 class="mb-0">Recent Donations</h5>
|
||||||
@ -136,5 +175,42 @@ $recent_donations = $pdo->query("
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const ctx = document.getElementById('donationsChart').getContext('2d');
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: <?= json_encode($labels) ?>,
|
||||||
|
datasets: [{
|
||||||
|
label: 'Donations (OMR)',
|
||||||
|
data: <?= json_encode($totals) ?>,
|
||||||
|
borderColor: '#059669',
|
||||||
|
backgroundColor: 'rgba(5, 150, 105, 0.1)',
|
||||||
|
fill: true,
|
||||||
|
tension: 0.4,
|
||||||
|
borderWidth: 3,
|
||||||
|
pointRadius: 4,
|
||||||
|
pointBackgroundColor: '#059669'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
plugins: {
|
||||||
|
legend: { display: false }
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true,
|
||||||
|
grid: { color: '#f3f4f6' }
|
||||||
|
},
|
||||||
|
x: {
|
||||||
|
grid: { display: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -33,6 +33,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
// Regenerate ID for security
|
// Regenerate ID for security
|
||||||
session_regenerate_id(true);
|
session_regenerate_id(true);
|
||||||
|
|
||||||
|
// Log the successful login
|
||||||
|
log_action('login', "User $email logged in successfully.");
|
||||||
|
|
||||||
header('Location: index.php');
|
header('Location: index.php');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,10 @@ $current_page = basename($_SERVER['PHP_SELF']);
|
|||||||
<a href="categories.php" class="nav-link <?= $current_page == 'categories.php' ? 'active' : '' ?>"><i class="bi bi-tags me-2"></i> Categories</a>
|
<a href="categories.php" class="nav-link <?= $current_page == 'categories.php' ? 'active' : '' ?>"><i class="bi bi-tags me-2"></i> Categories</a>
|
||||||
<a href="cases.php" class="nav-link <?= $current_page == 'cases.php' ? 'active' : '' ?>"><i class="bi bi-grid me-2"></i> Cases</a>
|
<a href="cases.php" class="nav-link <?= $current_page == 'cases.php' ? 'active' : '' ?>"><i class="bi bi-grid me-2"></i> Cases</a>
|
||||||
<a href="donations.php" class="nav-link <?= $current_page == 'donations.php' ? 'active' : '' ?>"><i class="bi bi-cash-stack me-2"></i> Donations</a>
|
<a href="donations.php" class="nav-link <?= $current_page == 'donations.php' ? 'active' : '' ?>"><i class="bi bi-cash-stack me-2"></i> Donations</a>
|
||||||
|
<a href="financial_summary.php" class="nav-link <?= $current_page == 'financial_summary.php' ? 'active' : '' ?>"><i class="bi bi-graph-up-arrow me-2"></i> Financial Summary</a>
|
||||||
|
<a href="donors.php" class="nav-link <?= $current_page == 'donors.php' ? 'active' : '' ?>"><i class="bi bi-people me-2"></i> Donors (CRM)</a>
|
||||||
|
<a href="audit_logs.php" class="nav-link <?= $current_page == 'audit_logs.php' ? 'active' : '' ?>"><i class="bi bi-journal-text me-2"></i> Audit Logs</a>
|
||||||
<hr>
|
<hr>
|
||||||
<a href="logout.php" class="nav-link"><i class="bi bi-box-arrow-right me-2"></i> Logout</a>
|
<a href="logout.php" class="nav-link text-danger"><i class="bi bi-box-arrow-right me-2"></i> Logout</a>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
106
certificate.php
Normal file
106
certificate.php
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
$donation_id = $_GET['id'] ?? null;
|
||||||
|
if (!$donation_id) exit('Invalid donation ID');
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
SELECT d.*, c.title_en as case_title, c.title_ar as case_title_ar
|
||||||
|
FROM donations d
|
||||||
|
JOIN cases c ON d.case_id = c.id
|
||||||
|
WHERE d.id = ? AND d.status = 'completed'
|
||||||
|
");
|
||||||
|
$stmt->execute([$donation_id]);
|
||||||
|
$don = $stmt->fetch();
|
||||||
|
|
||||||
|
if (!$don) exit('Donation not found or not completed.');
|
||||||
|
|
||||||
|
$org = $pdo->query("SELECT * FROM org_profile LIMIT 1")->fetch();
|
||||||
|
|
||||||
|
// This is a simple HTML certificate that can be printed or saved as PDF by the user
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Donation Certificate - CharityHub</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700&family=Inter:wght@400;600&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body { background: #f3f4f6; padding: 40px 20px; font-family: 'Inter', sans-serif; }
|
||||||
|
.certificate-container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: #fff;
|
||||||
|
padding: 60px;
|
||||||
|
border: 20px solid #059669;
|
||||||
|
position: relative;
|
||||||
|
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.certificate-container::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 10px; left: 10px; right: 10px; bottom: 10px;
|
||||||
|
border: 2px solid #059669;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.cert-header { font-family: 'Cinzel', serif; font-size: 3rem; color: #111827; margin-bottom: 10px; }
|
||||||
|
.cert-sub { font-size: 1.25rem; color: #059669; font-weight: 600; text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 40px; }
|
||||||
|
.cert-body { font-size: 1.2rem; color: #4b5563; line-height: 1.8; margin-bottom: 40px; }
|
||||||
|
.cert-name { font-family: 'Cinzel', serif; font-size: 2.5rem; color: #059669; margin: 20px 0; border-bottom: 2px solid #e5e7eb; display: inline-block; padding: 0 40px; }
|
||||||
|
.cert-footer { margin-top: 60px; display: flex; justify-content: space-between; align-items: flex-end; }
|
||||||
|
.signature { border-top: 1px solid #9ca3af; padding-top: 10px; width: 200px; font-style: italic; color: #6b7280; }
|
||||||
|
.stamp { width: 120px; height: 120px; border: 4px double #059669; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: #059669; font-weight: 800; transform: rotate(-15deg); font-size: 0.8rem; margin: 0 auto; }
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
body { background: #fff; padding: 0; }
|
||||||
|
.certificate-container { box-shadow: none; border-width: 15px; }
|
||||||
|
.no-print { display: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-print { margin-top: 30px; text-align: center; }
|
||||||
|
.btn-print { background: #059669; color: #fff; border: none; padding: 12px 30px; border-radius: 9999px; font-weight: 600; cursor: pointer; text-decoration: none; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="certificate-container">
|
||||||
|
<div class="cert-header">Certificate</div>
|
||||||
|
<div class="cert-sub">of Appreciation</div>
|
||||||
|
|
||||||
|
<div class="cert-body">
|
||||||
|
This certificate is proudly presented to
|
||||||
|
<br>
|
||||||
|
<div class="cert-name"><?= htmlspecialchars($don['donor_name'] ?: 'Valued Donor') ?></div>
|
||||||
|
<br>
|
||||||
|
In recognition of their generous donation of <strong>OMR <?= number_format($don['amount'], 3) ?></strong>
|
||||||
|
<br>
|
||||||
|
towards the cause: <strong><?= htmlspecialchars($don['case_title']) ?></strong>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stamp">
|
||||||
|
OFFICIAL<br>SEAL<br>CHARITYHUB
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cert-footer">
|
||||||
|
<div class="signature">
|
||||||
|
Date: <?= date('M j, Y', strtotime($don['created_at'])) ?>
|
||||||
|
</div>
|
||||||
|
<div class="signature">
|
||||||
|
Authorized Signature<br>
|
||||||
|
<?= htmlspecialchars($org['name_en'] ?? 'CharityHub') ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="no-print">
|
||||||
|
<button onclick="window.print()" class="btn-print">Print or Save as PDF</button>
|
||||||
|
<a href="index.php" style="margin-left: 15px; color: #6b7280; text-decoration: none;">Back to Home</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
21
success.php
21
success.php
@ -66,12 +66,15 @@ if ($donation) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$success = true;
|
$success = true;
|
||||||
|
$final_donation_id = $fullDonation['id'];
|
||||||
} else {
|
} else {
|
||||||
// Check if it was already completed (user refreshed page)
|
// Check if it was already completed (user refreshed page)
|
||||||
$stmt = $pdo->prepare("SELECT * FROM donations transaction_id = ? AND status = 'completed'");
|
$stmt = $pdo->prepare("SELECT * FROM donations WHERE transaction_id = ? AND status = 'completed'");
|
||||||
$stmt->execute([$session_id]);
|
$stmt->execute([$session_id]);
|
||||||
if ($stmt->fetch()) {
|
$existing = $stmt->fetch();
|
||||||
|
if ($existing) {
|
||||||
$success = true;
|
$success = true;
|
||||||
|
$final_donation_id = $existing['id'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@ -82,12 +85,15 @@ if ($donation) {
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Donation Successful - CharityHub</title>
|
<title>Donation Successful - CharityHub</title>
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
||||||
<style>
|
<style>
|
||||||
body { background-color: #f8fafc; font-family: 'Inter', sans-serif; }
|
body { background-color: #f8fafc; font-family: 'Inter', sans-serif; }
|
||||||
.success-card { max-width: 600px; border-radius: 24px; border: none; overflow: hidden; }
|
.success-card { max-width: 600px; border-radius: 24px; border: none; overflow: hidden; }
|
||||||
.success-icon { background: #ecfdf5; color: #10b981; width: 100px; height: 100px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto; }
|
.success-icon { background: #ecfdf5; color: #10b981; width: 100px; height: 100px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto; }
|
||||||
.btn-home { background: #059669; color: white; border: none; padding: 12px 40px; border-radius: 12px; font-weight: 600; transition: all 0.3s; }
|
.btn-home { background: #059669; color: white; border: none; padding: 12px 40px; border-radius: 12px; font-weight: 600; transition: all 0.3s; }
|
||||||
.btn-home:hover { background: #047857; color: white; transform: translateY(-2px); }
|
.btn-home:hover { background: #047857; color: white; transform: translateY(-2px); }
|
||||||
|
.btn-cert { background: #fff; color: #059669; border: 2px solid #059669; padding: 12px 40px; border-radius: 12px; font-weight: 600; transition: all 0.3s; text-decoration: none; display: inline-block; }
|
||||||
|
.btn-cert:hover { background: #ecfdf5; color: #047857; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -103,6 +109,14 @@ if ($donation) {
|
|||||||
</div>
|
</div>
|
||||||
<h1 class="fw-bold mb-3">Thank You!</h1>
|
<h1 class="fw-bold mb-3">Thank You!</h1>
|
||||||
<p class="text-muted fs-5 mb-4">Your donation has been successfully processed. Your generosity helps us continue our mission.</p>
|
<p class="text-muted fs-5 mb-4">Your donation has been successfully processed. Your generosity helps us continue our mission.</p>
|
||||||
|
|
||||||
|
<div class="d-flex flex-column flex-sm-row gap-3 justify-content-center mb-5">
|
||||||
|
<a href="certificate.php?id=<?= $final_donation_id ?>" target="_blank" class="btn-cert">
|
||||||
|
<i class="bi bi-patch-check me-2"></i>Download Certificate
|
||||||
|
</a>
|
||||||
|
<a href="index.php" class="btn btn-home">Return to Home</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="bg-light p-4 rounded-4 mb-4 text-start">
|
<div class="bg-light p-4 rounded-4 mb-4 text-start">
|
||||||
<div class="d-flex justify-content-between mb-2">
|
<div class="d-flex justify-content-between mb-2">
|
||||||
<span class="text-muted">Transaction ID</span>
|
<span class="text-muted">Transaction ID</span>
|
||||||
@ -113,8 +127,7 @@ if ($donation) {
|
|||||||
<span class="badge bg-success rounded-pill px-3">Completed</span>
|
<span class="badge bg-success rounded-pill px-3">Completed</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="small text-muted mb-4">Confirmation messages have been sent to the relevant parties.</p>
|
<p class="small text-muted mb-0">Confirmation messages have been sent to the relevant parties.</p>
|
||||||
<a href="index.php" class="btn btn-home">Return to Home</a>
|
|
||||||
</div>
|
</div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<div class="card border-0 shadow-lg p-5 rounded-4">
|
<div class="card border-0 shadow-lg p-5 rounded-4">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user