Files
controls-web/lasuca/growers/dashboard.php
2026-02-17 09:29:34 -06:00

737 lines
27 KiB
PHP

<?php
// phpcs:ignoreFile
if (!isset($requiredGrowerId)) {
http_response_code(400);
echo 'Grower dashboard misconfiguration.';
exit();
}
$rootDir = dirname(__DIR__);
require_once $rootDir . '/grower-session.php';
require_once $rootDir . '/inc/dbconfig.php';
require_once $rootDir . '/inc/opendb.php';
require_once $rootDir . '/inc/auth.php';
require_once $rootDir . '/inc/grower_helpers.php';
function lasuca_env($key, $fallback = null)
{
$value = getenv($key);
if ($value === false || $value === null || $value === '') {
return $fallback;
}
return $value;
}
function format_metric_value($value, $decimals = 0, $unit = '')
{
if (!is_numeric($value)) {
return '—';
}
$formatted = number_format((float) $value, $decimals);
if ($unit !== '') {
$formatted .= ' ' . $unit;
}
return $formatted;
}
function number_or_dash($value, $decimals = 0)
{
if (!is_numeric($value)) {
return '—';
}
return number_format((float) $value, $decimals);
}
function format_datetime_label($value, $format = 'g:i A')
{
if ($value instanceof DateTime) {
return $value->format($format);
}
if ($value === null || $value === '') {
return '—';
}
$timestamp = strtotime((string) $value);
if ($timestamp === false) {
return '—';
}
return date($format, $timestamp);
}
function calculate_net_weight($scaleWeight, $grossWeight)
{
if (!is_numeric($scaleWeight) || !is_numeric($grossWeight)) {
return 0.0;
}
$scale = (float) $scaleWeight;
$gross = (float) $grossWeight;
if ($scale > 100000 && $scale > $gross) {
return $scale - $gross;
}
return 0.0;
}
function parse_boolean_value($value)
{
if (is_bool($value)) {
return $value;
}
if (is_numeric($value)) {
return ((int) $value) === 1;
}
if (is_string($value)) {
$normalized = strtolower(trim($value));
return in_array($normalized, array('1', 'true', 'yes', 'y'), true);
}
return false;
}
function capture_metric_from_include($path)
{
if (!file_exists($path)) {
return null;
}
ob_start();
$result = @include $path;
$output = trim(ob_get_clean());
if ($result === false || $output === '') {
return null;
}
if (!preg_match('/-?\d+(?:\.\d+)?/', $output, $matches)) {
return null;
}
return (float) $matches[0];
}
function fetch_factory_metrics($rootDir)
{
$metrics = array(
'current_rate' => null,
'avg_15_min' => null,
'tons_today' => null,
'tons_prev' => null,
'run_hours_today' => null,
'run_hours_prev' => null,
'updated_at_raw' => null,
'error' => null
);
if (!class_exists('mysqli')) {
$metrics['error'] = 'Factory data currently unavailable.';
return $metrics;
}
$itemsPath = $rootDir . '/inc/items.php';
if (!file_exists($itemsPath)) {
$metrics['error'] = 'Factory data currently unavailable.';
return $metrics;
}
$value = array();
$rounded = array();
$time = array();
require $itemsPath;
$hasTonsToday = false;
$tonsToday = 0.0;
if (isset($value['CANETOT'])) {
$tonsToday += (float) $value['CANETOT'];
$hasTonsToday = true;
}
if (isset($value['W TONS GROUND'])) {
$tonsToday += (float) $value['W TONS GROUND'];
$hasTonsToday = true;
}
$metrics['tons_today'] = $hasTonsToday ? $tonsToday : null;
$hasTonsPrev = false;
$tonsPrev = 0.0;
if (isset($value['PREVTONS'])) {
$tonsPrev += (float) $value['PREVTONS'];
$hasTonsPrev = true;
}
if (isset($value['WPREVGROUND'])) {
$tonsPrev += (float) $value['WPREVGROUND'];
$hasTonsPrev = true;
}
$metrics['tons_prev'] = $hasTonsPrev ? $tonsPrev : null;
if (isset($rounded['RUNHRSTODAY'])) {
$metrics['run_hours_today'] = (float) $rounded['RUNHRSTODAY'];
}
if (isset($value['PREVTIME'])) {
$metrics['run_hours_prev'] = (float) $value['PREVTIME'];
}
$timestampCandidates = array('CANETOT', 'RUNHRSTODAY', 'PREVTONS', 'PREVTIME');
foreach ($timestampCandidates as $candidate) {
if (isset($time[$candidate]) && $time[$candidate] !== null && $time[$candidate] !== '') {
$metrics['updated_at_raw'] = $time[$candidate];
break;
}
}
$stableratePath = $rootDir . '/inc/stablerate30.php';
$metrics['current_rate'] = capture_metric_from_include($stableratePath);
$avgPath = $rootDir . '/inc/east15minavg.php';
$metrics['avg_15_min'] = capture_metric_from_include($avgPath);
if ($metrics['current_rate'] === null) {
$hasRate = false;
$rateSum = 0.0;
if (isset($value['E TONS PER HOUR'])) {
$rateSum += (float) $value['E TONS PER HOUR'];
$hasRate = true;
}
if (isset($value['W RATE'])) {
$rateSum += (float) $value['W RATE'];
$hasRate = true;
}
if ($hasRate) {
$metrics['current_rate'] = $rateSum;
}
}
if ($metrics['avg_15_min'] === null) {
$hasAvg = false;
$avgSum = 0.0;
if (isset($rounded['E 15 MIN AVG'])) {
$avgSum += (float) $rounded['E 15 MIN AVG'];
$hasAvg = true;
}
if (isset($rounded['W 15 MIN AVG'])) {
$avgSum += (float) $rounded['W 15 MIN AVG'];
$hasAvg = true;
}
if ($hasAvg) {
$metrics['avg_15_min'] = $avgSum;
}
}
if ($metrics['current_rate'] === null &&
$metrics['avg_15_min'] === null &&
$metrics['tons_today'] === null &&
$metrics['run_hours_today'] === null) {
$metrics['error'] = 'Factory data currently unavailable.';
}
return $metrics;
}
function connect_scale_db()
{
if (!function_exists('sqlsrv_connect')) {
return null;
}
$server = lasuca_env('SQLSRV_HOST', 'CBM2K12\\SQLEXPRESS');
$database = lasuca_env('SQLSRV_DATABASE', 'SugarCaneScale');
$user = lasuca_env('SQLSRV_USERNAME', 'cbmclient');
$password = lasuca_env('SQLSRV_PASSWORD', 'ascbm2k');
$connectionInfo = array(
'Database' => $database,
'UID' => $user,
'PWD' => $password,
'ReturnDatesAsStrings' => true,
'CharacterSet' => 'UTF-8'
);
$link = @call_user_func('sqlsrv_connect', $server, $connectionInfo);
if ($link === false) {
return null;
}
return $link;
}
function fetch_today_load_summary($connection, $growerId)
{
if (!function_exists('sqlsrv_query')) {
return array();
}
$sql = "SELECT COUNT(*) AS load_count,
SUM(Tons) AS total_tons,
SUM(GrossWt) AS total_gross,
SUM(TareWt) AS total_tare,
SUM(CASE WHEN ScaleWt > 100000 AND ScaleWt > GrossWt THEN ScaleWt - GrossWt ELSE 0 END) AS total_net,
MAX(DateOut) AS last_load_time
FROM LoadData
WHERE FarmerId_Fk = ? AND CONVERT(date, DateOut) = CONVERT(date, GETDATE())";
$params = array((int) $growerId);
$stmt = call_user_func('sqlsrv_query', $connection, $sql, $params);
if ($stmt === false) {
return array();
}
$fetchAssoc = defined('SQLSRV_FETCH_ASSOC') ? constant('SQLSRV_FETCH_ASSOC') : 2;
$row = call_user_func('sqlsrv_fetch_array', $stmt, $fetchAssoc);
if (function_exists('sqlsrv_free_stmt')) {
call_user_func('sqlsrv_free_stmt', $stmt);
}
if (!$row) {
return array();
}
$loadCount = isset($row['load_count']) ? (int) $row['load_count'] : 0;
$summary = array(
'load_count' => $loadCount,
'total_tons' => isset($row['total_tons']) ? (float) $row['total_tons'] : 0.0,
'total_gross' => isset($row['total_gross']) ? (float) $row['total_gross'] : 0.0,
'total_tare' => isset($row['total_tare']) ? (float) $row['total_tare'] : 0.0,
'total_net' => isset($row['total_net']) ? (float) $row['total_net'] : 0.0,
'last_load_time' => isset($row['last_load_time']) ? $row['last_load_time'] : null
);
if ($loadCount > 0) {
$summary['avg_tons'] = $summary['total_tons'] / $loadCount;
$summary['avg_gross'] = $summary['total_gross'] / $loadCount;
$summary['avg_tare'] = $summary['total_tare'] / $loadCount;
$summary['avg_net'] = $summary['total_net'] / $loadCount;
} else {
$summary['avg_tons'] = 0.0;
$summary['avg_gross'] = 0.0;
$summary['avg_tare'] = 0.0;
$summary['avg_net'] = 0.0;
}
return $summary;
}
function fetch_today_loads($connection, $growerId, $limit = 25)
{
if (!function_exists('sqlsrv_query')) {
return array();
}
$limit = max(1, (int) $limit);
$sql = "SELECT TOP {$limit}
LoadId_Pk,
VehicleId_Fk,
TractId_Fk,
Tons,
TareWt,
GrossWt,
ScaleWt,
Parked,
DateOut
FROM LoadData
WHERE FarmerId_Fk = ? AND CONVERT(date, DateOut) = CONVERT(date, GETDATE())
ORDER BY DateOut DESC, LoadId_Pk DESC";
$params = array((int) $growerId);
$stmt = call_user_func('sqlsrv_query', $connection, $sql, $params);
if ($stmt === false) {
return array();
}
$loads = array();
$fetchAssoc = defined('SQLSRV_FETCH_ASSOC') ? constant('SQLSRV_FETCH_ASSOC') : 2;
while ($row = call_user_func('sqlsrv_fetch_array', $stmt, $fetchAssoc)) {
$loads[] = array(
'load_id' => isset($row['LoadId_Pk']) ? (int) $row['LoadId_Pk'] : null,
'vehicle' => isset($row['VehicleId_Fk']) ? (string) $row['VehicleId_Fk'] : '',
'tract' => isset($row['TractId_Fk']) ? (string) $row['TractId_Fk'] : '',
'tons' => isset($row['Tons']) ? (float) $row['Tons'] : null,
'tare_weight' => isset($row['TareWt']) ? (float) $row['TareWt'] : null,
'gross_weight' => isset($row['GrossWt']) ? (float) $row['GrossWt'] : null,
'net_weight' => calculate_net_weight(isset($row['ScaleWt']) ? $row['ScaleWt'] : null, isset($row['GrossWt']) ? $row['GrossWt'] : null),
'date_out' => isset($row['DateOut']) ? $row['DateOut'] : null,
'parked' => parse_boolean_value(isset($row['Parked']) ? $row['Parked'] : null)
);
}
if (function_exists('sqlsrv_free_stmt')) {
call_user_func('sqlsrv_free_stmt', $stmt);
}
return $loads;
}
$username = isset($_SESSION['myusername']) ? $_SESSION['myusername'] : '';
$growerId = isset($_SESSION['growerid']) ? (string) $_SESSION['growerid'] : '';
if ($growerId !== (string) $requiredGrowerId) {
header('Location: /grower-login.php');
exit();
}
$member = auth_find_member($username);
$memberData = grower_member_defaults($member);
$recentFiles = grower_recent_files($username, 5);
$displayName = '';
if (is_array($member)) {
$first = isset($member['firstname']) ? trim((string) $member['firstname']) : '';
$last = isset($member['lastname']) ? trim((string) $member['lastname']) : '';
$displayName = trim($first . ' ' . $last);
if ($displayName === '' && isset($member['growername'])) {
$displayName = trim((string) $member['growername']);
}
}
if ($displayName === '') {
$displayName = 'Grower ' . (string) $growerId;
}
$factoryMetrics = fetch_factory_metrics($rootDir);
$scaleConnection = connect_scale_db();
$todayLoadSummary = array();
$todayLoads = array();
if ($scaleConnection) {
$todayLoadSummary = fetch_today_load_summary($scaleConnection, $growerId);
$todayLoads = fetch_today_loads($scaleConnection, $growerId, 25);
if (function_exists('sqlsrv_close')) {
call_user_func('sqlsrv_close', $scaleConnection);
}
}
require_once $rootDir . '/inc/closedb.php';
$loadSummaryCount = isset($todayLoadSummary['load_count']) ? (int) $todayLoadSummary['load_count'] : 0;
if ($loadSummaryCount > 0) {
$totalTonsText = number_or_dash(isset($todayLoadSummary['total_tons']) ? $todayLoadSummary['total_tons'] : null, 1);
if ($totalTonsText === '—') {
$heroSummaryText = sprintf(
'We\'ve logged %s %s today. Keep scrolling for mill stats and the live load list.',
number_format($loadSummaryCount),
$loadSummaryCount === 1 ? 'load' : 'loads'
);
} else {
$heroSummaryText = sprintf(
'We\'ve logged %s %s so far today totaling %s tons. Keep scrolling for mill stats and the live load list.',
number_format($loadSummaryCount),
$loadSummaryCount === 1 ? 'load' : 'loads',
$totalTonsText
);
}
} else {
$heroSummaryText = 'Your loads will appear below as soon as the first ticket clears the scale today. In the meantime, check your recent PDFs and mill performance snapshots.';
}
$heroFootnoteParts = array();
if (empty($factoryMetrics['error'])) {
$factoryUpdatedLabel = format_datetime_label(isset($factoryMetrics['updated_at_raw']) ? $factoryMetrics['updated_at_raw'] : null, 'g:i A');
if ($factoryUpdatedLabel !== '—') {
$heroFootnoteParts[] = 'Factory snapshot updated ' . $factoryUpdatedLabel;
}
} else {
$factoryUpdatedLabel = '—';
}
if ($loadSummaryCount > 0) {
$lastLoadSource = isset($todayLoadSummary['last_load_time']) ? $todayLoadSummary['last_load_time'] : null;
if ($lastLoadSource === null && !empty($todayLoads)) {
$lastLoadSource = $todayLoads[0]['date_out'];
}
$lastLoadLabel = format_datetime_label($lastLoadSource, 'g:i A');
if ($lastLoadLabel !== '—') {
$heroFootnoteParts[] = 'Last load recorded at ' . $lastLoadLabel;
}
} else {
$lastLoadLabel = '';
}
$lastLoginLabel = grower_format_datetime($memberData['last_login_at']);
if ($lastLoginLabel !== 'Never') {
$heroFootnoteParts[] = 'Last login ' . $lastLoginLabel;
}
$heroFootnote = '';
if (!empty($heroFootnoteParts)) {
$heroFootnote = implode(' · ', $heroFootnoteParts);
}
if (empty($factoryMetrics['error']) && (!isset($factoryUpdatedLabel) || $factoryUpdatedLabel === '—')) {
$factoryUpdatedLabel = 'Live reading';
}
$heroFootnoteText = $heroFootnote !== '' ? $heroFootnote : 'Data refreshes every few minutes · Last check ' . date('g:i A');
?>
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8" />
<title>Grower Dashboard</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="/new/css/styles.css" />
<link rel="stylesheet" href="/new/css/lasuca-theme.css" />
<link rel="stylesheet" href="/new/css/grower-dashboard.css" />
</head>
<body class="lasuca-theme theme-dark">
<nav class="navbar navbar-expand-lg navbar-dark">
<div class="container">
<a class="navbar-brand" href="/grower-dashboard.php">
<img src="/images/logo2.png" alt="LASUCA logo" />
<span>Grower Portal</span>
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#growerNav" aria-controls="growerNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="growerNav">
<ul class="navbar-nav ms-auto mb-2 mb-lg-0">
<li class="nav-item"><a class="nav-link" href="/home.php">Home</a></li>
<li class="nav-item"><a class="nav-link active" href="/grower-dashboard.php">Dashboard</a></li>
<li class="nav-item"><a class="nav-link" href="/grower-files.php">Daily Reports</a></li>
<li class="nav-item"><a class="nav-link" href="/grower-account.php">Manage Account</a></li>
<li class="nav-item"><a class="nav-link" href="/grower-logout.php">Log Out</a></li>
<?php require $rootDir . '/inc/theme-toggle.php'; ?>
</ul>
</div>
</div>
</nav>
<main>
<header class="hero">
<div class="container">
<div class="hero-content">
<span class="badge">Welcome back, <?php echo htmlspecialchars($displayName, ENT_QUOTES, 'UTF-8'); ?></span>
<h1>Today&rsquo;s field and factory pulse.</h1>
<p><?php echo htmlspecialchars($heroSummaryText, ENT_QUOTES, 'UTF-8'); ?></p>
<div class="hero-actions d-flex flex-column flex-sm-row gap-3">
<a class="btn btn-primary" href="/grower-files.php">Daily Ticket PDFs</a>
<a class="btn btn-outline-light" href="loads.php">View Full Load History</a>
</div>
<p class="mt-3 mb-0 text-white-50 small"><?php echo htmlspecialchars($heroFootnoteText, ENT_QUOTES, 'UTF-8'); ?></p>
</div>
</div>
</header>
<section class="data-glance">
<div class="container">
<div class="row g-4">
<div class="col-xl-4">
<div class="data-panel h-100">
<h3 class="mb-4">Today's Data</h3>
<div class="metric-grid">
<div class="metric-card">
<span class="metric-label">Grower ID</span>
<span class="metric-value"><?php echo htmlspecialchars((string) $growerId, ENT_QUOTES, 'UTF-8'); ?></span>
</div>
<div class="metric-card">
<span class="metric-label">Loads today</span>
<span class="metric-value"><?php echo number_format($loadSummaryCount); ?></span>
</div>
<div class="metric-card">
<span class="metric-label">Tons today</span>
<span class="metric-value"><?php echo htmlspecialchars(number_or_dash(isset($todayLoadSummary['total_tons']) ? $todayLoadSummary['total_tons'] : null, 1), ENT_QUOTES, 'UTF-8'); ?></span>
</div>
<div class="metric-card">
<span class="metric-label">Avg tons/load</span>
<span class="metric-value"><?php echo htmlspecialchars(number_or_dash(isset($todayLoadSummary['avg_tons']) ? $todayLoadSummary['avg_tons'] : null, 1), ENT_QUOTES, 'UTF-8'); ?></span>
</div>
<div class="metric-card">
<span class="metric-label">Last load</span>
<span class="metric-value"><?php echo htmlspecialchars($lastLoadLabel !== '' ? $lastLoadLabel : '—', ENT_QUOTES, 'UTF-8'); ?></span>
</div>
<div class="metric-card">
<span class="metric-label">Last login</span>
<span class="metric-value"><?php echo htmlspecialchars($lastLoginLabel, ENT_QUOTES, 'UTF-8'); ?></span>
</div>
</div>
<p class="metric-footnote mb-0">Updates as tickets clear the scale.</p>
</div>
</div>
<div class="col-xl-8">
<div class="row g-4">
<div class="col-md-6">
<div class="feature-card h-100">
<h3>Factory Data</h3>
<?php if (!empty($factoryMetrics['error'])): ?>
<p class="mb-0 text-muted">Mill metrics are offline right now. Please check back shortly.</p>
<?php else: ?>
<ul class="stat-list">
<li>
<span class="stat-label">Current grinding rate</span>
<span class="stat-value"><?php echo htmlspecialchars(format_metric_value(isset($factoryMetrics['current_rate']) ? $factoryMetrics['current_rate'] : null, 0, 'tons/hr'), ENT_QUOTES, 'UTF-8'); ?></span>
</li>
<li>
<span class="stat-label">15-minute average</span>
<span class="stat-value"><?php echo htmlspecialchars(format_metric_value(isset($factoryMetrics['avg_15_min']) ? $factoryMetrics['avg_15_min'] : null, 0, 'tons'), ENT_QUOTES, 'UTF-8'); ?></span>
</li>
<li>
<span class="stat-label">Tons ground today</span>
<span class="stat-value"><?php echo htmlspecialchars(format_metric_value(isset($factoryMetrics['tons_today']) ? $factoryMetrics['tons_today'] : null, 0, 'tons'), ENT_QUOTES, 'UTF-8'); ?></span>
</li>
<li>
<span class="stat-label">Previous day tons</span>
<span class="stat-value"><?php echo htmlspecialchars(format_metric_value(isset($factoryMetrics['tons_prev']) ? $factoryMetrics['tons_prev'] : null, 0, 'tons'), ENT_QUOTES, 'UTF-8'); ?></span>
</li>
<li>
<span class="stat-label">Run hours today</span>
<span class="stat-value"><?php echo htmlspecialchars(format_metric_value(isset($factoryMetrics['run_hours_today']) ? $factoryMetrics['run_hours_today'] : null, 1, 'hrs'), ENT_QUOTES, 'UTF-8'); ?></span>
</li>
<li>
<span class="stat-label">Previous day hours</span>
<span class="stat-value"><?php echo htmlspecialchars(format_metric_value(isset($factoryMetrics['run_hours_prev']) ? $factoryMetrics['run_hours_prev'] : null, 1, 'hrs'), ENT_QUOTES, 'UTF-8'); ?></span>
</li>
</ul>
<p class="small text-muted mt-3 mb-0"><?php echo htmlspecialchars('Last updated ' . $factoryUpdatedLabel, ENT_QUOTES, 'UTF-8'); ?></p>
<?php endif; ?>
</div>
</div>
<div class="col-md-6">
<div class="feature-card h-100">
<h3>Recent files</h3>
<?php if (!empty($recentFiles)): ?>
<ul class="recent-files-list">
<?php foreach ($recentFiles as $file): ?>
<li>
<a href="<?php echo htmlspecialchars($file['path'], ENT_QUOTES, 'UTF-8'); ?>" target="_blank"><?php echo htmlspecialchars($file['name'], ENT_QUOTES, 'UTF-8'); ?></a>
<span class="file-meta"><?php echo htmlspecialchars(grower_format_datetime(date('Y-m-d H:i:s', $file['modified'])), ENT_QUOTES, 'UTF-8'); ?></span>
</li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<p class="mb-3 text-muted">We haven&rsquo;t spotted any recent files in your folder yet.</p>
<?php endif; ?>
<a class="btn btn-sm btn-outline-success mt-3" href="/grower-files.php">Open file browser</a>
</div>
</div>
<div class="col-12">
<div class="feature-card h-100">
<h3>Daily report links</h3>
<p class="mb-3">Jump straight to your most common folders. These links open in a new tab.</p>
<div class="row g-3">
<div class="col-md-6">
<a class="btn w-100 btn-outline-success" href="index.php">PDF Reports</a>
</div>
<div class="col-md-6">
<a class="btn w-100 btn-outline-success" href="/grower-account.php">Manage account</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="py-5">
<div class="container">
<div class="feature-card load-table">
<div class="d-flex flex-column flex-lg-row align-items-lg-center justify-content-between gap-2 mb-4">
<div>
<h3 class="mb-1">Today&rsquo;s loads</h3>
<p class="mb-0 text-muted">Showing up to 25 of your most recent tickets. Full history lives in the load data view.</p>
</div>
<a class="btn btn-outline-success" href="loads.php">Open full load history</a>
</div>
<?php if (!empty($todayLoads)): ?>
<div class="table-responsive">
<table class="table align-middle mb-0">
<thead>
<tr>
<th scope="col">Load</th>
<th scope="col">Vehicle</th>
<th scope="col">Tract</th>
<th scope="col">Tons</th>
<th scope="col">Gross</th>
<th scope="col">Tare</th>
<th scope="col">Net</th>
<th scope="col">Parked</th>
<th scope="col">Time out</th>
</tr>
</thead>
<tbody>
<?php foreach ($todayLoads as $load): ?>
<tr>
<td><?php echo htmlspecialchars(number_format(isset($load['load_id']) ? $load['load_id'] : 0), ENT_QUOTES, 'UTF-8'); ?></td>
<td><?php echo htmlspecialchars($load['vehicle'], ENT_QUOTES, 'UTF-8'); ?></td>
<td><?php echo htmlspecialchars($load['tract'], ENT_QUOTES, 'UTF-8'); ?></td>
<td><?php echo htmlspecialchars(format_metric_value($load['tons'], 2), ENT_QUOTES, 'UTF-8'); ?></td>
<td><?php echo htmlspecialchars(format_metric_value($load['gross_weight'], 0), ENT_QUOTES, 'UTF-8'); ?></td>
<td><?php echo htmlspecialchars(format_metric_value($load['tare_weight'], 0), ENT_QUOTES, 'UTF-8'); ?></td>
<td><?php echo htmlspecialchars(format_metric_value($load['net_weight'], 0), ENT_QUOTES, 'UTF-8'); ?></td>
<td><?php echo $load['parked'] ? '<span class="badge bg-warning text-dark">Yes</span>' : '<span class="badge bg-success">No</span>'; ?></td>
<td>
<?php echo htmlspecialchars(format_datetime_label(isset($load['date_out']) ? $load['date_out'] : null, 'g:i A'), ENT_QUOTES, 'UTF-8'); ?>
<span class="load-time"><?php echo htmlspecialchars(format_datetime_label(isset($load['date_out']) ? $load['date_out'] : null, 'M j'), ENT_QUOTES, 'UTF-8'); ?></span>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php else: ?>
<p class="mb-0 text-muted">No loads have been recorded today yet. Once the first ticket clears the scale you&rsquo;ll see it here instantly.</p>
<?php endif; ?>
</div>
</div>
</section>
</main>
<footer class="lasuca-footer">
<div class="container">
<div class="row g-3 align-items-center">
<div class="col-md-6">
<strong>Louisiana Sugar Cane Cooperative</strong><br />
341 Sugar Mill Road &middot; St. Martinville, LA 70582
</div>
<div class="col-md-6 text-md-end">
<small>&copy; <?php echo date('Y'); ?> LASUCA. All rights reserved.</small>
</div>
</div>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="/new/js/scripts.js"></script>
</body>
</html>
}