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

vehicles.php

Type
php
Size
12.44 KB
Modified
15 May
vehicles.php 12.44 KB
<?php
require_once __DIR__ . '/../bootstrap.php';

requireAuth();
if (!isAdminRole() && !hasPermission('vehicles.view')) {
    http_response_code(403);
    die('Access denied');
}

$canManage = isAdminRole() || hasPermission('vehicles.edit');
$pageTitle = 'Vehicles';
$msg = [];
$err = [];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!$canManage) {
        http_response_code(403);
        die('Access denied. You do not have permission to manage vehicles.');
    }
    $action = (string)($_POST['action'] ?? '');

    if ($action === 'save_van') {
        $id = (int)($_POST['id'] ?? 0);
        $plate_full = trim((string)($_POST['plate_full'] ?? ''));
        $plate_short = trim((string)($_POST['plate_short'] ?? ''));
        $make = trim((string)($_POST['make'] ?? ''));
        $model = trim((string)($_POST['model'] ?? ''));
        $year = trim((string)($_POST['year'] ?? ''));
        $yearVal = ($year !== '') ? (int)$year : null;
        $color = trim((string)($_POST['color'] ?? ''));
        $tag_color = trim((string)($_POST['tag_color'] ?? '')) ?: null;
        $notes = trim((string)($_POST['notes'] ?? ''));
        $is_active = isset($_POST['is_active']) ? 1 : 0;

        if ($plate_full === '') $err[] = 'Vehicle registration is required.';
        if ($plate_short === '') $plate_short = substr(preg_replace('/\s+/', '', $plate_full), -3);

        if (!$err) {
            try {
                if ($id > 0) {
                    $stmt = $pdo->prepare('UPDATE vans SET plate_full=?, plate_short=?, make=?, model=?, year=?, color=?, tag_color=?, notes=?, is_active=? WHERE id=?');
                    $stmt->execute([$plate_full, $plate_short, $make, $model, $yearVal, $color, $tag_color, $notes, $is_active, $id]);
                    $msg[] = 'Vehicle updated.';
                    logActivity('vans.update', 'van', $id, "Updated vehicle: $plate_full");
                } else {
                    $stmt = $pdo->prepare('INSERT INTO vans (plate_full, plate_short, make, model, year, color, tag_color, notes, is_active) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)');
                    $stmt->execute([$plate_full, $plate_short, $make, $model, $yearVal, $color, $tag_color, $notes, $is_active]);
                    $id = (int)$pdo->lastInsertId();
                    $msg[] = 'Vehicle added.';
                    logActivity('vans.create', 'van', $id, "Added vehicle: $plate_full");
                }
            } catch (PDOException $e) {
                $err[] = str_contains($e->getMessage(), 'Duplicate entry') ? 'A vehicle with this registration already exists.' : ('Database error: ' . $e->getMessage());
            }
        }
    }

    if ($action === 'toggle_active') {
        $id = (int)($_POST['id'] ?? 0);
        if ($id > 0) {
            try {
                $stmt = $pdo->prepare('UPDATE vans SET is_active = NOT is_active WHERE id=?');
                $stmt->execute([$id]);
                $msg[] = 'Vehicle status updated.';
                logActivity('vans.update', 'van', $id, 'Toggled vehicle active status');
            } catch (PDOException $e) { $err[] = 'Failed to update status: ' . $e->getMessage(); }
        }
    }

    if ($action === 'delete_van') {
        $id = (int)($_POST['id'] ?? 0);
        if ($id > 0) {
            try {
                $stmt = $pdo->prepare('DELETE FROM vans WHERE id=?');
                $stmt->execute([$id]);
                $msg[] = 'Vehicle deleted.';
                logActivity('vans.delete', 'van', $id, 'Deleted vehicle');
            } catch (PDOException $e) { $err[] = 'Failed to delete vehicle: ' . $e->getMessage(); }
        }
    }
}

$vans = [];
try {
    $stmt = $pdo->query('SELECT * FROM vans ORDER BY is_active DESC, plate_full ASC');
    $vans = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) { $err[] = 'Failed to load vehicles: ' . $e->getMessage(); }

$extraHead = '<style>
.vehicle-toolbar{display:flex;gap:10px;flex-wrap:wrap;justify-content:flex-end;align-items:center;}
.vehicle-status{display:inline-flex;align-items:center;gap:8px;}
.vehicle-dot{width:10px;height:10px;border-radius:50%;display:inline-block;}
.vehicle-dot.active{background:#2ecc71;}.vehicle-dot.inactive{background:#e74c3c;}
.vehicle-modal-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;}
@media(max-width:720px){.vehicle-modal-grid{grid-template-columns:1fr;}.vehicle-toolbar{justify-content:flex-start;}}
</style>';
include __DIR__ . '/../partials/header.php';
?>

<div class="content-header">
    <div>
        <h1 class="content-title">🚐 Vehicles</h1>
        <p class="content-subtitle">Vehicle records for operations. TruTrak device mapping is now under Administration → TruTrak Admin.</p>
    </div>
    <div class="vehicle-toolbar">
        <?php if (isAdminRole() || hasPermission('trutrak.manage')): ?><a class="btn btn-secondary" href="<?= e(app_url('admin/trutrak')) ?>#vehicle-mapping">🧭 TruTrak Mapping</a><?php endif; ?>
        <?php if ($canManage): ?><button class="btn btn-primary" type="button" data-open-vehicle-modal>➕ Add Vehicle</button><?php endif; ?>
    </div>
</div>

<?php foreach ($msg as $m): ?><div class="alert alert-success"><?= e($m) ?></div><?php endforeach; ?>
<?php foreach ($err as $e): ?><div class="alert alert-error"><?= e($e) ?></div><?php endforeach; ?>

<div class="card">
    <div class="card-header"><h3 class="card-title">Vehicle List (<?= count($vans) ?>)</h3></div>
    <?php if (!$vans): ?>
        <div class="text-muted" style="padding:20px;">No vehicles found.</div>
    <?php else: ?>
        <div class="table-wrap">
            <table class="table" style="min-width:960px;">
                <thead><tr><th>Status</th><th>Registration</th><th>Short</th><th>Make / Model</th><th>Year</th><th>Vehicle Colour</th><th>Tag</th><th>Notes</th><th>Actions</th></tr></thead>
                <tbody>
                    <?php foreach ($vans as $van): ?>
                        <?php $tag = $van['tag_color'] ?? '#ff8c1a'; ?>
                        <tr style="<?= !empty($van['is_active']) ? '' : 'opacity:.55;' ?>">
                            <td><span class="vehicle-status"><span class="vehicle-dot <?= !empty($van['is_active']) ? 'active' : 'inactive' ?>"></span><?= !empty($van['is_active']) ? 'Active' : 'Inactive' ?></span></td>
                            <td><strong><?= e((string)$van['plate_full']) ?></strong></td>
                            <td><span class="badge" style="background:var(--accent);color:#000;"><?= e((string)$van['plate_short']) ?></span></td>
                            <td><?= e(trim((string)($van['make'] ?? '') . ' ' . (string)($van['model'] ?? '')) ?: '—') ?></td>
                            <td><?= e((string)($van['year'] ?? '—')) ?></td>
                            <td><?= e((string)($van['color'] ?? '—')) ?></td>
                            <td><span style="display:inline-block;width:18px;height:18px;border-radius:4px;background:<?= e($tag) ?>;border:1px solid var(--border);vertical-align:middle;margin-right:6px;"></span><span class="small"><?= e($tag) ?></span></td>
                            <td><span class="small"><?= e(mb_strimwidth((string)($van['notes'] ?? ''), 0, 60, '…')) ?></span></td>
                            <td>
                                <?php if ($canManage): ?>
                                    <div class="d-flex gap-sm" style="flex-wrap:wrap;">
                                        <button class="btn btn-secondary btn-xs" type="button" data-edit-vehicle='<?= e(json_encode($van, JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP)) ?>'>Edit</button>
                                        <form method="post" onsubmit="return confirm('Toggle active status for this vehicle?');" style="display:inline;"><input type="hidden" name="action" value="toggle_active"><input type="hidden" name="id" value="<?= (int)$van['id'] ?>"><button class="btn btn-secondary btn-xs" type="submit"><?= !empty($van['is_active']) ? 'Deactivate' : 'Activate' ?></button></form>
                                        <form method="post" onsubmit="return confirm('Delete this vehicle? This cannot be undone.');" style="display:inline;"><input type="hidden" name="action" value="delete_van"><input type="hidden" name="id" value="<?= (int)$van['id'] ?>"><button class="btn btn-danger btn-xs" type="submit">Delete</button></form>
                                    </div>
                                <?php else: ?>
                                    <span class="text-muted small">View only</span>
                                <?php endif; ?>
                            </td>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
        </div>
    <?php endif; ?>
</div>

<?php if ($canManage): ?>
<div class="modal-overlay" id="vehicleModal" style="display:none;">
    <div class="modal modal-medium">
        <div class="modal-header">
            <h3 class="modal-title" id="vehicleModalTitle">Add Vehicle</h3>
            <button class="modal-close" type="button" data-close-vehicle-modal>×</button>
        </div>
        <form method="post" id="vehicleForm">
            <input type="hidden" name="action" value="save_van">
            <input type="hidden" name="id" id="vehicle_id" value="">
            <div class="modal-body vehicle-modal-grid">
                <div><label class="field-label">Registration</label><input class="input" name="plate_full" id="plate_full" required placeholder="AB12 CDE"></div>
                <div><label class="field-label">Short plate</label><input class="input" name="plate_short" id="plate_short" placeholder="Last 3, auto-filled if blank"></div>
                <div><label class="field-label">Make</label><input class="input" name="make" id="make" placeholder="Ford"></div>
                <div><label class="field-label">Model</label><input class="input" name="model" id="model" placeholder="Transit"></div>
                <div><label class="field-label">Year</label><input class="input" name="year" id="year" type="number" min="1900" max="2100"></div>
                <div><label class="field-label">Vehicle colour</label><input class="input" name="color" id="color" placeholder="White"></div>
                <div><label class="field-label">Tag colour</label><input class="input" name="tag_color" id="tag_color" type="color" value="#ff8c1a"></div>
                <div style="display:flex;align-items:end;"><label class="d-flex align-center gap-2"><input type="checkbox" name="is_active" id="is_active" value="1" checked> Active</label></div>
                <div style="grid-column:1 / -1;"><label class="field-label">Notes</label><textarea class="input" name="notes" id="notes" rows="3"></textarea></div>
            </div>
            <div class="modal-footer"><button class="btn btn-secondary" type="button" data-close-vehicle-modal>Cancel</button><button class="btn btn-primary" type="submit">Save Vehicle</button></div>
        </form>
    </div>
</div>
<script>
(function(){
    const modal = document.getElementById('vehicleModal');
    const form = document.getElementById('vehicleForm');
    function setVal(id, val){ const el=document.getElementById(id); if(el) el.value = val ?? ''; }
    function openVehicle(data){
        if(!modal || !form) return;
        form.reset();
        document.getElementById('vehicleModalTitle').textContent = data ? 'Edit Vehicle' : 'Add Vehicle';
        setVal('vehicle_id', data?.id || '');
        setVal('plate_full', data?.plate_full || '');
        setVal('plate_short', data?.plate_short || '');
        setVal('make', data?.make || '');
        setVal('model', data?.model || '');
        setVal('year', data?.year || '');
        setVal('color', data?.color || '');
        setVal('tag_color', data?.tag_color || '#ff8c1a');
        setVal('notes', data?.notes || '');
        const active=document.getElementById('is_active'); if(active) active.checked = data ? Number(data.is_active) === 1 : true;
        modal.style.display = 'flex';
    }
    function closeVehicle(){ if(modal) modal.style.display='none'; }
    document.addEventListener('click', function(ev){
        if(ev.target.closest('[data-open-vehicle-modal]')) { ev.preventDefault(); openVehicle(null); }
        const edit = ev.target.closest('[data-edit-vehicle]');
        if(edit){ ev.preventDefault(); try{ openVehicle(JSON.parse(edit.getAttribute('data-edit-vehicle') || '{}')); }catch(e){} }
        if(ev.target.closest('[data-close-vehicle-modal]')) { ev.preventDefault(); closeVehicle(); }
        if(ev.target === modal) closeVehicle();
    });
})();
</script>
<?php endif; ?>

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