37214-vm/index.php
2025-12-30 21:40:31 +00:00

367 lines
19 KiB
PHP

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Community Command Center</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.7/css/dataTables.bootstrap5.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/buttons/2.4.2/css/buttons.bootstrap5.min.css">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">
<img src="assets/pasted-20251230-211133-cc45faf9.png" alt="Company Logo" style="height: 40px;">
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Dashboard</a>
</li>
</ul>
<span class="navbar-text me-3">
<i class="bi bi-geo-alt-fill"></i> Valencia Sound
</span>
<span class="navbar-text">
<i class="bi bi-calendar-fill"></i> December 2025
</span>
</div>
</div>
</nav>
<div class="container-fluid p-4">
<div class="row g-4">
<!-- Participation & Usage -->
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">1. Participation & Usage</h5>
</div>
<div class="card-body">
<div class="row text-center">
<div class="col-md-3 col-6 kpi-container" data-kpi="unique_members" data-title="Unique Members">
<div id="unique_members_kpi" class="kpi-value text-primary">342</div>
<div class="kpi-label">Unique Members</div>
</div>
<div class="col-md-3 col-6 kpi-container" data-kpi="avg_class_attendance" data-title="Avg Class Attendance">
<div id="avg_class_attendance_kpi" class="kpi-value text-primary">12</div>
<div class="kpi-label">Avg Class Attendance</div>
</div>
<div class="col-md-3 col-6 mt-3 mt-md-0 kpi-container" data-kpi="classes_lightly_attended" data-title="Classes Lightly Attended">
<div id="classes_lightly_attended_kpi" class="kpi-value text-primary">15%</div>
<div class="kpi-label">Classes Lightly Attended</div>
</div>
<div class="col-md-3 col-6 mt-3 mt-md-0 kpi-container" data-kpi="attendance_trend" data-title="Attendance Trend">
<div id="attendance_trend_kpi" class="kpi-value text-success">+5% <i class="bi bi-arrow-up-right"></i></div>
<div class="kpi-label">Attendance Trend</div>
</div>
</div>
<div class="mt-4">
<canvas id="attendance_chart"></canvas>
</div>
</div>
</div>
</div>
<!-- Member Engagement Depth -->
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">2. Member Engagement Depth</h5>
</div>
<div class="card-body">
<div class="row text-center">
<div class="col-md-6 col-6 kpi-container" data-kpi="avg_visits_per_member" data-title="Avg Visits per Member">
<div id="avg_visits_per_member_kpi" class="kpi-value text-primary">4.2</div>
<div class="kpi-label">Avg Visits per Member</div>
</div>
<div class="col-md-6 col-6 kpi-container" data-kpi="high_frequency_members" data-title="High Frequency Members">
<div id="high_frequency_members_kpi" class="kpi-value text-primary">45%</div>
<div class="kpi-label">High Frequency Members</div>
</div>
</div>
<div class="mt-4">
<canvas id="visit_frequency_chart"></canvas>
</div>
</div>
</div>
</div>
<!-- Revenue Performance -->
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header bg-success text-white">
<h5 class="mb-0">3. Revenue Performance</h5>
</div>
<div class="card-body">
<div class="row text-center">
<div class="col-md-6 col-6 kpi-container" data-kpi="total_revenue" data-title="Total Revenue">
<div id="total_revenue_kpi" class="kpi-value text-success">$22,450</div>
<div class="kpi-label">Total Revenue</div>
</div>
<div class="col-md-6 col-6 kpi-container" data-kpi="revenue_per_active_member" data-title="Revenue per Active Member">
<div id="revenue_per_active_member_kpi" class="kpi-value text-success">$65.64</div>
<div class="kpi-label">Revenue per Active Member</div>
</div>
</div>
</div>
</div>
</div>
<!-- Engagement Risk -->
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header bg-danger text-white">
<h5 class="mb-0">4. Engagement Risk</h5>
</div>
<div class="card-body">
<div class="row text-center">
<div class="col-md-6 col-6 kpi-container" data-kpi="inactive_members" data-title="Inactive Members">
<div id="inactive_members_kpi" class="kpi-value text-danger">0%</div>
<div class="kpi-label">Inactive Members</div>
</div>
<div class="col-md-6 col-6 kpi-container" data-kpi="visits_dropped" data-title="Visits Dropped">
<div id="visits_dropped_kpi" class="kpi-value text-danger">0% <i class="bi bi-arrow-down-right"></i></div>
<div class="kpi-label">Visits Dropped</div>
</div>
</div>
</div>
</div>
</div>
<!-- Member Feedback -->
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header bg-info text-white">
<h5 class="mb-0">5. Member Feedback</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-4">
<h6><i class="bi bi-hand-thumbs-up-fill text-success"></i> Top Praises</h6>
<ul class="list-unstyled">
<li>"Love the new yoga class!"</li>
<li>"Instructor was fantastic."</li>
</ul>
</div>
<div class="col-md-4">
<h6><i class="bi bi-lightbulb-fill text-warning"></i> Top Requests</h6>
<ul class="list-unstyled">
<li>"More evening classes."</li>
<li>"Wish there was a smoothie bar."</li>
</ul>
</div>
<div class="col-md-4">
<h6><i class="bi bi-exclamation-triangle-fill text-danger"></i> Top Frictions</h6>
<ul class="list-unstyled">
<li>"Locker room needs attention."</li>
<li>"Difficulty booking online."</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- Alignment Insight -->
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header" style="background-color: #ffc107; color: #fff;">
<h5 class="mb-0">6. Alignment Insight</h5>
</div>
<div class="card-body">
<h4><span class="badge bg-warning">Noticeable Shift</span></h4>
<p class="lead"><strong>Risk:</strong> While revenue is up, the drop in visit frequency and recent negative feedback on facilities could impact retention next period.</p>
<p class="lead"><strong>Opportunity:</strong> High praise for specific instructors suggests promoting them more could boost attendance.</p>
</div>
</div>
</div>
</div>
<!-- Overall Status Banner -->
<div class="alert alert-warning mt-4 text-center" role="alert">
<strong>CAUTION:</strong> Visits Dropped 10%
</div>
</div>
<!-- Drill-down Modal -->
<div class="modal fade" id="drilldownModal" tabindex="-1" aria-labelledby="drilldownModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="drilldownModalLabel">Drill-down</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<table id="drilldownTable" class="table table-striped table-bordered">
<thead>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.datatables.net/1.13.7/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.7/js/dataTables.bootstrap5.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.4.2/js/dataTables.buttons.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.bootstrap5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.html5.min.js"></script>
<script>
$(document).ready(function() {
let community_id = 1; // Default community
let start_date = '2025-12-01'; // Default start date
let end_date = '2025-12-31'; // Default end date
function updateKPIs() {
$.getJSON(`api.php?kpi=unique_members&community_id=${community_id}&start_date=${start_date}&end_date=${end_date}`, function(data) {
$('#unique_members_kpi').text(data.unique_members);
});
$.getJSON(`api.php?kpi=avg_class_attendance&community_id=${community_id}&start_date=${start_date}&end_date=${end_date}`, function(data) {
$('#avg_class_attendance_kpi').text(data.avg_class_attendance);
});
$.getJSON(`api.php?kpi=classes_lightly_attended&community_id=${community_id}&start_date=${start_date}&end_date=${end_date}`, function(data) {
$('#classes_lightly_attended_kpi').text(data.classes_lightly_attended + '%');
});
$.getJSON(`api.php?kpi=attendance_trend&community_id=${community_id}&start_date=${start_date}&end_date=${end_date}`, function(data) {
let trend_html = '';
if (data.attendance_trend > 0) {
trend_html = `<span class="text-success">+${data.attendance_trend}% <i class="bi bi-arrow-up-right"></i></span>`;
} else if (data.attendance_trend < 0) {
trend_html = `<span class="text-danger">${data.attendance_trend}% <i class="bi bi-arrow-down-right"></i></span>`;
} else {
trend_html = `<span>${data.attendance_trend}%</span>`;
}
$('#attendance_trend_kpi').html(trend_html);
});
$.getJSON(`api.php?kpi=avg_visits_per_member&community_id=${community_id}&start_date=${start_date}&end_date=${end_date}`, function(data) {
$('#avg_visits_per_member_kpi').text(data.avg_visits_per_member);
});
$.getJSON(`api.php?kpi=high_frequency_members&community_id=${community_id}&start_date=${start_date}&end_date=${end_date}`, function(data) {
$('#high_frequency_members_kpi').text(data.high_frequency_members + '%');
});
$.getJSON(`api.php?kpi=total_revenue&community_id=${community_id}&start_date=${start_date}&end_date=${end_date}`, function(data) {
$('#total_revenue_kpi').text('$' + data.total_revenue);
});
$.getJSON(`api.php?kpi=revenue_per_active_member&community_id=${community_id}&start_date=${start_date}&end_date=${end_date}`, function(data) {
$('#revenue_per_active_member_kpi').text('$' + data.revenue_per_active_member);
});
$.getJSON(`api.php?kpi=inactive_members&community_id=${community_id}&start_date=${start_date}&end_date=${end_date}`, function(data) {
$('#inactive_members_kpi').text(data.inactive_members + '%');
});
$.getJSON(`api.php?kpi=visits_dropped&community_id=${community_id}&start_date=${start_date}&end_date=${end_date}`, function(data) {
let trend_html = '';
if (data.visits_dropped > 0) {
trend_html = `<span class="text-success">+${data.visits_dropped}% <i class="bi bi-arrow-up-right"></i></span>`;
} else if (data.visits_dropped < 0) {
trend_html = `<span class="text-danger">${data.visits_dropped}% <i class="bi bi-arrow-down-right"></i></span>`;
} else {
trend_html = `<span>${data.visits_dropped}%</span>`;
}
$('#visits_dropped_kpi').html(trend_html);
});
let table;
function openDrilldown(kpi, title) {
$('#drilldownModalLabel').text(title);
if (table) {
table.destroy();
}
$.getJSON(`api.php?kpi=${kpi}_drilldown&community_id=${community_id}&start_date=${start_date}&end_date=${end_date}`, function(data) {
let columns = [];
if (data.length > 0) {
columns = Object.keys(data[0]).map(function(key) {
return { title: key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()), data: key };
});
}
table = $('#drilldownTable').DataTable({
data: data,
columns: columns,
dom: 'Bfrtip',
buttons: [
'csv'
]
});
$('#drilldownModal').modal('show');
});
}
$('.kpi-container').on('click', function() {
const kpi = $(this).data('kpi');
const title = $(this).data('title');
openDrilldown(kpi, title);
});
updateKPIs();
updateCharts();
let attendanceChart;
let visitFrequencyChart;
function updateCharts() {
$.getJSON(`api.php?kpi=attendance_over_time&community_id=${community_id}&start_date=${start_date}&end_date=${end_date}`, function(data) {
const ctx = document.getElementById('attendance_chart').getContext('2d');
if(attendanceChart) {
attendanceChart.destroy();
}
attendanceChart = new Chart(ctx, {
type: 'line',
data: {
labels: data.labels,
datasets: [{
label: 'Attendance Over Time',
data: data.data,
borderColor: '#0d6efd',
tension: 0.1
}]
}
});
});
$.getJSON(`api.php?kpi=visit_frequency_distribution&community_id=${community_id}&start_date=${start_date}&end_date=${end_date}`, function(data) {
const ctx = document.getElementById('visit_frequency_chart').getContext('2d');
if(visitFrequencyChart) {
visitFrequencyChart.destroy();
}
visitFrequencyChart = new Chart(ctx, {
type: 'pie',
data: {
labels: data.labels,
datasets: [{
label: 'Visit Frequency Distribution',
data: data.data,
backgroundColor: [
'#0d6efd',
'#198754',
'#ffc107',
'#dc3545'
]
}]
}
});
});
}
});
</script>
</body>