Initial commit: MSPE website - full site with admin panel, API, and public pages
This commit is contained in:
Executable
+224
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
/**
|
||||
* MSPE Dashboard Stats API
|
||||
*/
|
||||
|
||||
require_once 'config.php';
|
||||
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
|
||||
if ($method !== 'GET') {
|
||||
jsonResponse(['success' => false, 'message' => 'Method not allowed'], 405);
|
||||
}
|
||||
|
||||
// Require authentication for stats
|
||||
requireAuth();
|
||||
|
||||
$action = $_GET['action'] ?? 'all';
|
||||
$forceRefresh = !empty($_GET['refresh']);
|
||||
|
||||
switch ($action) {
|
||||
case 'all':
|
||||
getAllStats();
|
||||
break;
|
||||
case 'bookings':
|
||||
getBookingStats();
|
||||
break;
|
||||
case 'messages':
|
||||
getMessageStats();
|
||||
break;
|
||||
case 'news':
|
||||
getNewsStats();
|
||||
break;
|
||||
default:
|
||||
getAllStats();
|
||||
}
|
||||
|
||||
function getAllStats() {
|
||||
$cacheKey = 'stats_all_v1';
|
||||
if (!$GLOBALS['forceRefresh']) {
|
||||
$cached = getStatsCache($cacheKey, 30);
|
||||
if ($cached !== null) {
|
||||
jsonResponse($cached);
|
||||
}
|
||||
}
|
||||
|
||||
$bookingStats = calculateBookingStats();
|
||||
$messageStats = calculateMessageStats();
|
||||
$newsStats = calculateNewsStats();
|
||||
$subscriberStats = calculateSubscriberStats();
|
||||
|
||||
$payload = [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'bookings' => $bookingStats,
|
||||
'messages' => $messageStats,
|
||||
'news' => $newsStats,
|
||||
'subscribers' => $subscriberStats
|
||||
]
|
||||
];
|
||||
|
||||
setStatsCache($cacheKey, $payload);
|
||||
jsonResponse($payload);
|
||||
}
|
||||
|
||||
function calculateBookingStats() {
|
||||
global $db;
|
||||
|
||||
$today = date('Y-m-d');
|
||||
$weekStart = date('Y-m-d', strtotime('monday this week'));
|
||||
$weekEnd = date('Y-m-d', strtotime('sunday this week'));
|
||||
|
||||
$totalBookings = $db->count('bookings');
|
||||
$thisWeekCount = $db->countByDateRange('bookings', 'booking_date', $weekStart, $weekEnd);
|
||||
|
||||
// Last week's bookings (for trend)
|
||||
$lastWeekStart = date('Y-m-d', strtotime('monday last week'));
|
||||
$lastWeekEnd = date('Y-m-d', strtotime('sunday last week'));
|
||||
$lastWeekCount = $db->countByDateRange('bookings', 'booking_date', $lastWeekStart, $lastWeekEnd);
|
||||
|
||||
$pendingCount = $db->count('bookings', ['status' => 'pending']);
|
||||
$confirmedCount = $db->count('bookings', ['status' => 'confirmed']);
|
||||
|
||||
// JSON boolean true is compared as string "true" after JSON_UNQUOTE
|
||||
$availableSlotsCount = $db->countByFieldComparison('availability_slots', 'date', '>=', $today, [
|
||||
'is_available' => 'true'
|
||||
]);
|
||||
|
||||
$confirmationRate = $totalBookings > 0 ? round(($confirmedCount / $totalBookings) * 100) : 0;
|
||||
|
||||
// Calculate trend percentages
|
||||
$bookingTrend = $lastWeekCount > 0 ? round((($thisWeekCount - $lastWeekCount) / $lastWeekCount) * 100) : ($thisWeekCount > 0 ? 100 : 0);
|
||||
|
||||
return [
|
||||
'this_week' => $thisWeekCount,
|
||||
'pending' => $pendingCount,
|
||||
'confirmed' => $confirmedCount,
|
||||
'available_slots' => $availableSlotsCount,
|
||||
'confirmation_rate' => $confirmationRate,
|
||||
'trend' => $bookingTrend,
|
||||
'total' => $totalBookings
|
||||
];
|
||||
}
|
||||
|
||||
function calculateMessageStats() {
|
||||
global $db;
|
||||
|
||||
$total = $db->count('messages');
|
||||
$unread = $db->count('messages', ['status' => 'unread']);
|
||||
|
||||
$weekStart = date('Y-m-d', strtotime('monday this week'));
|
||||
$weekEnd = date('Y-m-d', strtotime('sunday this week'));
|
||||
$thisWeek = $db->countByDateRange('messages', 'created_at', $weekStart . ' 00:00:00', $weekEnd . ' 23:59:59');
|
||||
|
||||
return [
|
||||
'total' => $total,
|
||||
'unread' => $unread,
|
||||
'this_week' => $thisWeek
|
||||
];
|
||||
}
|
||||
|
||||
function calculateNewsStats() {
|
||||
global $db;
|
||||
|
||||
return [
|
||||
'total' => $db->count('news'),
|
||||
'published' => $db->count('news', ['status' => 'published']),
|
||||
'draft' => $db->count('news', ['status' => 'draft'])
|
||||
];
|
||||
}
|
||||
|
||||
function calculateSubscriberStats() {
|
||||
global $db;
|
||||
|
||||
return [
|
||||
'total' => $db->count('subscribers'),
|
||||
'active' => $db->count('subscribers', ['status' => 'active'])
|
||||
];
|
||||
}
|
||||
|
||||
function getBookingStats() {
|
||||
$cacheKey = 'stats_bookings_v1';
|
||||
if (!$GLOBALS['forceRefresh']) {
|
||||
$cached = getStatsCache($cacheKey, 30);
|
||||
if ($cached !== null) {
|
||||
jsonResponse($cached);
|
||||
}
|
||||
}
|
||||
|
||||
$payload = [
|
||||
'success' => true,
|
||||
'data' => calculateBookingStats()
|
||||
];
|
||||
|
||||
setStatsCache($cacheKey, $payload);
|
||||
jsonResponse($payload);
|
||||
}
|
||||
|
||||
function getMessageStats() {
|
||||
$cacheKey = 'stats_messages_v1';
|
||||
if (!$GLOBALS['forceRefresh']) {
|
||||
$cached = getStatsCache($cacheKey, 30);
|
||||
if ($cached !== null) {
|
||||
jsonResponse($cached);
|
||||
}
|
||||
}
|
||||
|
||||
$payload = [
|
||||
'success' => true,
|
||||
'data' => calculateMessageStats()
|
||||
];
|
||||
|
||||
setStatsCache($cacheKey, $payload);
|
||||
jsonResponse($payload);
|
||||
}
|
||||
|
||||
function getNewsStats() {
|
||||
$cacheKey = 'stats_news_v1';
|
||||
if (!$GLOBALS['forceRefresh']) {
|
||||
$cached = getStatsCache($cacheKey, 30);
|
||||
if ($cached !== null) {
|
||||
jsonResponse($cached);
|
||||
}
|
||||
}
|
||||
|
||||
$payload = [
|
||||
'success' => true,
|
||||
'data' => calculateNewsStats()
|
||||
];
|
||||
|
||||
setStatsCache($cacheKey, $payload);
|
||||
jsonResponse($payload);
|
||||
}
|
||||
|
||||
function getStatsCache($cacheKey, $ttlSeconds) {
|
||||
$cacheDir = DATA_DIR . 'cache/';
|
||||
$cacheFile = $cacheDir . 'stats_' . md5($cacheKey) . '.json';
|
||||
|
||||
if (!file_exists($cacheFile)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$age = time() - (int)filemtime($cacheFile);
|
||||
if ($age > (int)$ttlSeconds) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$content = @file_get_contents($cacheFile);
|
||||
if ($content === false || $content === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$decoded = json_decode($content, true);
|
||||
return is_array($decoded) ? $decoded : null;
|
||||
}
|
||||
|
||||
function setStatsCache($cacheKey, $payload) {
|
||||
$cacheDir = DATA_DIR . 'cache/';
|
||||
if (!is_dir($cacheDir)) {
|
||||
@mkdir($cacheDir, 0755, true);
|
||||
}
|
||||
|
||||
$cacheFile = $cacheDir . 'stats_' . md5($cacheKey) . '.json';
|
||||
@file_put_contents($cacheFile, json_encode($payload), LOCK_EX);
|
||||
}
|
||||
Reference in New Issue
Block a user