BROOKO icon
BROOKO UK NETWORK
Where code meets creativity & adventure
File viewer

rota.php

Type
php
Size
10.53 KB
Modified
21 Apr
rota.php 10.53 KB
<?php
require_once __DIR__ . '/../bootstrap.php';
requireAuth();

requirePermission('rota.view');

$pageTitle = 'Rota';
$canManage = isAdminRole() || hasPermission('rota.manage');

// ── Helpers ───────────────────────────────────────────────────────────
function wp_ordinal(int $n): string {
    $nAbs = abs($n);
    $mod100 = $nAbs % 100;
    if ($mod100 >= 11 && $mod100 <= 13) return $n . 'th';
    return match ($nAbs % 10) {
        1 => $n . 'st',
        2 => $n . 'nd',
        3 => $n . 'rd',
        default => $n . 'th',
    };
}

function wp_week_start(string $anchor): int {
    $ts = strtotime($anchor) ?: time();
    $dow = (int)date('N', $ts); // 1 (Mon) .. 7 (Sun)
    return (int)strtotime('-' . ($dow - 1) . ' days', $ts);
}

// ── Params ────────────────────────────────────────────────────────────
$anchor = $_GET['date'] ?? date('Y-m-d');
$span   = (int)($_GET['span'] ?? 2);
if ($span < 1) $span = 1;
if ($span > 4) $span = 4;
$print  = isset($_GET['print']) && $_GET['print'] === '1';

$baseWeekStartTs = wp_week_start($anchor);
$weekStarts = [];
for ($i = 0; $i < $span; $i++) {
    $weekStarts[] = date('Y-m-d', strtotime('+' . ($i * 7) . ' days', $baseWeekStartTs));
}

// Navigation jumps by the visible span
$jumpDays = $span * 7;
$prevAnchor = date('Y-m-d', strtotime('-' . $jumpDays . ' days', $baseWeekStartTs));
$nextAnchor = date('Y-m-d', strtotime('+' . $jumpDays . ' days', $baseWeekStartTs));

// ── Load lanes (columns) ──────────────────────────────────────────────
$crewLanes = [];
$officeLanes = [];
$dbOk = true;
try {
    $lanes = $pdo->query("SELECT id, code, label, lane_type, sort_order FROM rota_lanes WHERE is_active=1 ORDER BY sort_order ASC")
        ->fetchAll(PDO::FETCH_ASSOC);
    foreach ($lanes as $l) {
        if (($l['lane_type'] ?? 'crew') === 'office') $officeLanes[] = $l; else $crewLanes[] = $l;
    }
} catch (Throwable $e) {
    $dbOk = false;
}

// ── Load week publish flags + entries ─────────────────────────────────
$weeksMeta = []; // week_start => [is_published]
$entries = [];   // week_start => entry_date => lane_id => value
if ($dbOk) {
    try {
        $in = implode(',', array_fill(0, count($weekStarts), '?'));
        $stmtW = $pdo->prepare("SELECT week_start, is_published FROM rota_weeks WHERE week_start IN ($in)");
        $stmtW->execute($weekStarts);
        foreach ($stmtW->fetchAll(PDO::FETCH_ASSOC) as $w) {
            $weeksMeta[(string)$w['week_start']] = ['is_published' => (int)$w['is_published'] === 1];
        }

        $stmtE = $pdo->prepare("SELECT week_start, entry_date, lane_id, value FROM rota_entries WHERE week_start IN ($in)");
        $stmtE->execute($weekStarts);
        foreach ($stmtE->fetchAll(PDO::FETCH_ASSOC) as $r) {
            $ws = (string)$r['week_start'];
            $d  = (string)$r['entry_date'];
            $lid = (int)$r['lane_id'];
            $entries[$ws] ??= [];
            $entries[$ws][$d] ??= [];
            $entries[$ws][$d][$lid] = (string)($r['value'] ?? '');
        }
    } catch (Throwable $e) {
        $dbOk = false;
    }
}

// Staff should only see published weeks
$visibleWeekStarts = [];
foreach ($weekStarts as $ws) {
    $pub = (bool)($weeksMeta[$ws]['is_published'] ?? false);
    if ($canManage || $pub) $visibleWeekStarts[] = $ws;
}

// Extra head: print layout
if ($print) {
    $extraHead = '<style>
        @media print {
            .sidebar, .page-header-simple, .header-nav, .content-header, .btn, .no-print { display:none !important; }
            .main-area { margin:0 !important; }
            .main-content { padding:0 !important; }
            .app-container { display:block !important; }
        }
        .rota-sheet-header{display:flex;align-items:center;justify-content:space-between;gap:14px;margin:4px 0 18px 0;}
        .rota-sheet-title{font-weight:900;font-size:1.35rem;letter-spacing:.2px;}
        .rota-sheet-sub{margin-top:4px;color:var(--muted-text,#9aa3ad);font-size:.95rem;}
        .rota-logo{width:86px;height:86px;object-fit:contain;border-radius:12px;background:rgba(255,255,255,.04);padding:8px;}
        .rota-week{margin-bottom:28px;}
        .rota-week-heading{font-weight:900;text-transform:uppercase;font-size:.85rem;letter-spacing:.4px;margin:0 0 6px 0;}
        .rota-table{width:100%;border-collapse:collapse;}
        .rota-table th,.rota-table td{border:1px solid rgba(255,145,0,.35);padding:6px 8px;font-size:.86rem;vertical-align:top;}
        .rota-table thead th{background:rgba(255,145,0,.10);font-weight:900;}
        .rota-table tbody tr:nth-child(even) td{background:rgba(255,145,0,.06);}
        .rota-day{font-weight:900;text-transform:uppercase;white-space:nowrap;width:118px;}
        .rota-date{font-weight:900;white-space:nowrap;width:60px;text-align:center;}
        .rota-cell{white-space:pre-wrap;}
        </style>';
}

include __DIR__ . '/../partials/header.php';

$companyName = getSystemInfo('company_name', 'WorkersPanel');
$logoFiles = glob(__DIR__ . '/../assets/images/logo.*') ?: [];
$logoSrc = !empty($logoFiles) ? '/assets/images/' . basename($logoFiles[0]) : '';
if ($logoSrc) {
    $disk = __DIR__ . '/../assets/images/' . basename($logoFiles[0]);
    $logoSrc .= '?v=' . ((int)@filemtime($disk) ?: time());
}
?>

<div class="content-header no-print">
    <div>
        <h1 class="content-title">🗓️ Rota</h1>
        <p class="content-subtitle">Weekly staff rota sheet (no calendar link).</p>
    </div>
    <div style="display:flex;gap:10px;flex-wrap:wrap;">
        <a class="btn btn-secondary" href="/rota?date=<?= e($prevAnchor) ?>&span=<?= (int)$span ?>">← Prev</a>
        <a class="btn btn-secondary" href="/rota?date=<?= e(date('Y-m-d')) ?>&span=<?= (int)$span ?>">Today</a>
        <a class="btn btn-secondary" href="/rota?date=<?= e($nextAnchor) ?>&span=<?= (int)$span ?>">Next →</a>
        <a class="btn btn-primary" href="/rota?date=<?= e($weekStarts[0]) ?>&span=<?= (int)$span ?>&print=1" target="_blank">🖨 Print</a>
        <?php if ($canManage && hasPermission('management.access')): ?>
            <a class="btn btn-secondary" href="/management/rota?date=<?= e($weekStarts[0]) ?>&span=<?= (int)$span ?>">⚙️ Manage</a>
        <?php endif; ?>
    </div>
</div>

<?php if (!$dbOk): ?>
    <div class="alert alert-warning">
        Rota tables are not available in your database yet. Ask an admin to apply the latest update.
    </div>
<?php endif; ?>

<div class="rota-sheet-header">
    <div>
        <div class="rota-sheet-title"><?= e($companyName) ?> Staff Rota</div>
        <div class="rota-sheet-sub">Week commencing Monday · UK format (dd/mm/yyyy)</div>
    </div>
    <?php if ($logoSrc): ?>
        <img class="rota-logo" src="<?= e($logoSrc) ?>" alt="<?= e($companyName) ?>">
    <?php endif; ?>
</div>

<?php if (empty($visibleWeekStarts)): ?>
    <div class="card">
        <div class="card-body">
            <div class="text-muted">No rota published yet.</div>
        </div>
    </div>
<?php else: ?>
    <?php foreach ($visibleWeekStarts as $ws):
        $wsTs = strtotime($ws) ?: time();
        $pub = (bool)($weeksMeta[$ws]['is_published'] ?? false);
        $weekLabel = date('d/m/Y', $wsTs);
        $weekEndLabel = date('d/m/Y', strtotime('+6 days', $wsTs));
        $weekEntries = $entries[$ws] ?? [];
    ?>
        <div class="rota-week">
            <div style="display:flex;justify-content:space-between;align-items:flex-end;gap:12px;flex-wrap:wrap;">
                <div>
                    <div class="rota-week-heading">WEEK COMMENCING: <?= e($weekLabel) ?></div>
                    <div class="text-muted" style="font-size:.9rem;"><?= e($weekLabel) ?> → <?= e($weekEndLabel) ?></div>
                </div>
                <?php if ($canManage): ?>
                    <?php if ($pub): ?>
                        <span class="badge badge-success">Published</span>
                    <?php else: ?>
                        <span class="badge badge-muted">Draft</span>
                    <?php endif; ?>
                <?php endif; ?>
            </div>

            <div class="table-wrap" style="margin-top:10px;">
                <table class="rota-table">
                    <thead>
                        <tr>
                            <th colspan="2">DATE</th>
                            <?php foreach ($crewLanes as $l): ?>
                                <th><?= ($l['label'] !== '' ? e($l['label']) : '&nbsp;') ?></th>
                            <?php endforeach; ?>
                            <?php foreach ($officeLanes as $l): ?>
                                <th><?= ($l['label'] !== '' ? e($l['label']) : '&nbsp;') ?></th>
                            <?php endforeach; ?>
                        </tr>
                    </thead>
                    <tbody>
                        <?php for ($d = 0; $d < 7; $d++):
                            $date = date('Y-m-d', strtotime('+' . $d . ' days', $wsTs));
                            $dayName = strtoupper(date('l', strtotime($date)));
                            $dayNum = (int)date('j', strtotime($date));
                            $dateLabel = wp_ordinal($dayNum);
                        ?>
                            <tr>
                                <td class="rota-day"><?= e($dayName) ?></td>
                                <td class="rota-date"><?= e($dateLabel) ?></td>

                                <?php foreach ($crewLanes as $l):
                                    $lid = (int)$l['id'];
                                    $val = (string)($weekEntries[$date][$lid] ?? '');
                                ?>
                                    <td class="rota-cell"><?= e($val) ?></td>
                                <?php endforeach; ?>


                                <?php foreach ($officeLanes as $l):
                                    $lid = (int)$l['id'];
                                    $val = (string)($weekEntries[$date][$lid] ?? '');
                                ?>
                                    <td class="rota-cell"><?= e($val) ?></td>
                                <?php endforeach; ?>
                            </tr>
                        <?php endfor; ?>
                    </tbody>
                </table>
            </div>
        </div>
    <?php endforeach; ?>
<?php endif; ?>

<?php include __DIR__ . '/../partials/footer.php'; ?>