03348cad79
Key areas: [OrderStatusService.php](/Users/tyemeclifford/Documents/GH/fatbottomgrille/app/Services/OrderStatusService.php), [AdminController.php](/Users/tyemeclifford/Documents/GH/fatbottomgrille/app/Controllers/AdminController.php), and [Database.php](/Users/tyemeclifford/Documents/GH/fatbottomgrille/app/Core/Database.php). SQLite migration applied successfully. PHP/JS syntax, integration workflows, rendered pages, database integrity, and tracker authorization all passed. Invalid tracker tokens correctly return 403.
99 lines
4.4 KiB
PHP
99 lines
4.4 KiB
PHP
<div class="stat-grid">
|
||
<article class="stat-card stat-primary">
|
||
<span>Today’s sales</span>
|
||
<strong><?= money($stats['today_sales']) ?></strong>
|
||
<small><?= (int) $stats['today_orders'] ?> paid orders</small>
|
||
</article>
|
||
<article class="stat-card">
|
||
<span>Open orders</span>
|
||
<strong><?= (int) $stats['open_orders'] ?></strong>
|
||
<small>Paid through ready</small>
|
||
</article>
|
||
<article class="stat-card">
|
||
<span>Abandoned carts</span>
|
||
<strong><?= (int) $stats['abandoned_carts'] ?></strong>
|
||
<small>Inactive for 30+ minutes</small>
|
||
</article>
|
||
<article class="stat-card">
|
||
<span>Today’s visitors</span>
|
||
<strong><?= (int) $stats['today_visitors'] ?></strong>
|
||
<small><?= (int) $stats['newsletter_members'] ?> news subscribers</small>
|
||
</article>
|
||
</div>
|
||
|
||
<?php if (password_verify('ChangeMe123!', (string) $currentUser['password_hash'])): ?>
|
||
<div class="notice admin-security-notice">
|
||
<strong>Security reminder:</strong> the initial administrator password is still active.
|
||
Change it from <a href="<?= e(url('/account')) ?>">My Account</a> before deployment.
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<div class="admin-dashboard-grid">
|
||
<section class="admin-panel admin-panel-wide">
|
||
<div class="admin-panel-heading">
|
||
<div>
|
||
<span class="eyebrow">Live queue</span>
|
||
<h2>Recent Orders</h2>
|
||
</div>
|
||
<a class="button button-small" href="<?= e(url('/admin/orders')) ?>">View All Orders</a>
|
||
</div>
|
||
<div class="table-wrap">
|
||
<table>
|
||
<thead><tr><th>Order</th><th>Customer</th><th>Placed</th><th>Status</th><th>Total</th></tr></thead>
|
||
<tbody>
|
||
<?php if (!$recentOrders): ?>
|
||
<tr><td colspan="5" class="empty-cell">No orders yet. The kitchen is standing by.</td></tr>
|
||
<?php endif; ?>
|
||
<?php foreach ($recentOrders as $order): ?>
|
||
<tr>
|
||
<td><a href="<?= e(url('/admin/order')) ?>?id=<?= (int) $order['id'] ?>"><?= e($order['order_number']) ?></a></td>
|
||
<td><?= e($order['customer_name']) ?><small><?= e($order['customer_phone']) ?></small></td>
|
||
<td><?= e(store_datetime((string) $order['placed_at'], 'g:i A')) ?></td>
|
||
<td><span class="status-pill status-<?= e($order['status']) ?>"><?= e(order_status_label((string) $order['status'])) ?></span></td>
|
||
<td><?= money($order['total_cents']) ?></td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
<section class="admin-panel">
|
||
<div class="admin-panel-heading">
|
||
<div>
|
||
<span class="eyebrow">Last 7 days</span>
|
||
<h2>Store Traffic</h2>
|
||
</div>
|
||
</div>
|
||
<?php $maxTraffic = max(1, ...array_map(static fn (array $row): int => (int) $row['visitors'], $traffic)); ?>
|
||
<div class="bar-chart">
|
||
<?php if (!$traffic): ?><p class="muted">Traffic data will appear as visitors arrive.</p><?php endif; ?>
|
||
<?php foreach ($traffic as $day): ?>
|
||
<div>
|
||
<span class="bar-value"><?= (int) $day['visitors'] ?></span>
|
||
<i style="height:<?= max(8, round(((int) $day['visitors'] / $maxTraffic) * 120)) ?>px"></i>
|
||
<small><?= e((new DateTimeImmutable((string) $day['day']))->format('D')) ?></small>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</section>
|
||
<section class="admin-panel">
|
||
<div class="admin-panel-heading">
|
||
<div>
|
||
<span class="eyebrow">What’s moving</span>
|
||
<h2>Popular Items</h2>
|
||
</div>
|
||
</div>
|
||
<div class="rank-list">
|
||
<?php if (!$popularItems): ?><p class="muted">Item sales will appear after the first order.</p><?php endif; ?>
|
||
<?php foreach ($popularItems as $index => $item): ?>
|
||
<div>
|
||
<span><?= $index + 1 ?></span>
|
||
<strong><?= e($item['item_name']) ?></strong>
|
||
<small><?= (int) $item['quantity'] ?> sold</small>
|
||
<b><?= money($item['sales_cents']) ?></b>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</section>
|
||
</div>
|