35607-vm/index.php
Flatlogic Bot 9b5a06451f SInarKasih
2025-11-10 04:11:47 +00:00

209 lines
7.6 KiB
PHP

<?php
require_once __DIR__ . '/includes/auth.php';
require_login();
require_once __DIR__ . '/db/config.php';
// Run migrations on first load
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
if (!isset($_SESSION['migrated'])) {
run_migrations();
$_SESSION['migrated'] = true;
}
require_once __DIR__ . '/includes/header.php';
// Fetch some stats for the dashboard
$total_products = db()->query('SELECT COUNT(*) FROM products')->fetchColumn();
// Today's Sales
$today = date('Y-m-d');
$stmt_today = db()->prepare("SELECT COUNT(*) as num_transactions, SUM(total_amount) as total_sales FROM sales WHERE DATE(sale_date) = ?");
$stmt_today->execute([$today]);
$today_sales = $stmt_today->fetch(PDO::FETCH_ASSOC);
// All-Time Sales
$stmt_all_time = db()->query("SELECT COUNT(*) as num_transactions, SUM(total_amount) as total_sales FROM sales");
$all_time_sales = $stmt_all_time->fetch(PDO::FETCH_ASSOC);
// Low Stock
$low_stock_threshold = 5;
$stmt_low_stock = db()->prepare('SELECT COUNT(*) FROM products WHERE stock <= ?');
$stmt_low_stock->execute([$low_stock_threshold]);
$low_stock_count = $stmt_low_stock->fetchColumn();
?>
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">Dashboard</h1>
</div>
<div class="row">
<div class="col-md-3">
<div class="card text-white bg-primary mb-3">
<div class="card-header">Total Products</div>
<div class="card-body">
<h5 class="card-title"><?php echo $total_products; ?></h5>
<p class="card-text">items in inventory.</p>
<a href="products.php" class="text-white">View details &rarr;</a>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-success mb-3">
<div class="card-header">Today's Sales</div>
<div class="card-body">
<h5 class="card-title">Rp <?php echo number_format($today_sales['total_sales'] ?? 0, 2); ?></h5>
<p class="card-text">from <?php echo $today_sales['num_transactions'] ?? 0; ?> transactions.</p>
<a href="reports.php?start_date=<?php echo $today; ?>&end_date=<?php echo $today; ?>" class="text-white">View details &rarr;</a>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-info mb-3">
<div class="card-header">All-Time Sales</div>
<div class="card-body">
<h5 class="card-title">Rp <?php echo number_format($all_time_sales['total_sales'] ?? 0, 2); ?></h5>
<p class="card-text">from <?php echo $all_time_sales['num_transactions'] ?? 0; ?> transactions.</p>
<a href="reports.php" class="text-white">View details &rarr;</a>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-warning mb-3">
<div class="card-header">Low Stock Alerts</div>
<div class="card-body">
<h5 class="card-title"><?php echo $low_stock_count; ?></h5>
<p class="card-text">items need restocking.</p>
<a href="products.php?filter_low_stock=1" class="text-white">View details &rarr;</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8">
<div class="card">
<div class="card-header">
Sales Trend (Last 7 Days)
</div>
<div class="card-body">
<canvas id="salesChart"></canvas>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header">
Best-Selling Products
</div>
<div class="card-body">
<canvas id="bestSellingChart"></canvas>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
// Sales Trend Chart
fetch('_get_sales_data.php')
.then(response => response.json())
.then(data => {
const salesCtx = document.getElementById('salesChart').getContext('2d');
new Chart(salesCtx, {
type: 'line',
data: {
labels: data.labels,
datasets: [{
label: 'Total Sales (Rp)',
data: data.data,
backgroundColor: 'rgba(13, 110, 253, 0.2)',
borderColor: 'rgba(13, 110, 253, 1)',
borderWidth: 1,
fill: true,
tension: 0.4
}]
},
options: {
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value) {
return 'Rp ' + value.toLocaleString();
}
}
}
},
plugins: {
tooltip: {
callbacks: {
label: function(context) {
let label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
label += 'Rp ' + context.parsed.y.toLocaleString();
}
return label;
}
}
}
}
}
});
});
// Best-Selling Products Chart
fetch('_get_best_selling_products.php')
.then(response => response.json())
.then(data => {
const bestSellingCtx = document.getElementById('bestSellingChart').getContext('2d');
new Chart(bestSellingCtx, {
type: 'bar',
data: {
labels: data.map(p => p.name),
datasets: [{
label: 'Quantity Sold',
data: data.map(p => p.total_quantity),
backgroundColor: [
'rgba(255, 99, 132, 0.5)',
'rgba(54, 162, 235, 0.5)',
'rgba(255, 206, 86, 0.5)',
'rgba(75, 192, 192, 0.5)',
'rgba(153, 102, 255, 0.5)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)'
],
borderWidth: 1
}]
},
options: {
indexAxis: 'y',
scales: {
x: {
beginAtZero: true
}
},
plugins: {
legend: {
display: false
}
}
}
});
});
});
</script>
<?php require_once __DIR__ . '/includes/footer.php'; ?>