238 lines
14 KiB
PHP
238 lines
14 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/includes/layout.php';
|
|
require_user_login();
|
|
|
|
$errors = [];
|
|
$formData = [
|
|
'vehicle_name' => '',
|
|
'vehicle_category' => 'Motor',
|
|
'plate_number' => '',
|
|
'service_name' => 'Ganti oli mesin',
|
|
'last_service_date' => date('Y-m-d'),
|
|
'reminder_interval_days' => 90,
|
|
'odometer_km' => '',
|
|
'notes' => '',
|
|
];
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$formData = array_merge($formData, $_POST);
|
|
$result = validate_service_payload($_POST);
|
|
$errors = $result['errors'];
|
|
$formData = array_merge($formData, $result['clean']);
|
|
|
|
if (!$errors) {
|
|
$newId = create_service($result['clean']);
|
|
set_flash('success', 'Catatan servis berhasil disimpan. Hanya akun kamu yang bisa melihat reminder ini.');
|
|
header('Location: ' . app_url('dashboard.php') . '?created=' . $newId);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
$userId = current_user_id();
|
|
$userName = current_user_name();
|
|
$services = fetch_services_for_user($userId);
|
|
$summary = dashboard_summary_for_user($userId);
|
|
$createdId = isset($_GET['created']) ? (int) $_GET['created'] : 0;
|
|
$catalog = service_catalog();
|
|
|
|
render_page_start([
|
|
'title' => 'Dashboard reminder servis',
|
|
'description' => 'Input servis kendaraan, lihat reminder dashboard, dan cek status item servis yang akan jatuh tempo.',
|
|
'page' => 'dashboard',
|
|
]);
|
|
render_flash(consume_flash());
|
|
?>
|
|
<section class="py-4 py-lg-5 border-bottom dashboard-head dashboard-hero">
|
|
<div class="container">
|
|
<div class="row g-4 align-items-start">
|
|
<div class="col-xl-7">
|
|
<span class="eyebrow">Dashboard pribadi</span>
|
|
<h1 class="section-title mt-2 mb-3">Halo, <?= e($userName) ?>. Semua catatan servis di sini hanya milik akun kamu.</h1>
|
|
<p class="text-secondary mb-4">Kamu bisa menambah reminder baru, memantau item yang telat, lalu membuka detail tanpa khawatir data user lain ikut terlihat.</p>
|
|
<div class="dashboard-summary-grid dashboard-summary-grid-wide">
|
|
<div class="dashboard-stat-card dashboard-stat-primary">
|
|
<div class="metric-label">Total catatan</div>
|
|
<div class="metric-value"><?= (int) $summary['total_services'] ?></div>
|
|
<div class="small text-muted">semua item servis aktif</div>
|
|
</div>
|
|
<div class="dashboard-stat-card dashboard-stat-alert">
|
|
<div class="metric-label">Terlambat</div>
|
|
<div class="metric-value"><?= (int) $summary['overdue_count'] ?></div>
|
|
<div class="small text-muted">prioritas untuk dicek lebih dulu</div>
|
|
</div>
|
|
<div class="dashboard-stat-card">
|
|
<div class="metric-label">Segera jatuh tempo</div>
|
|
<div class="metric-value"><?= (int) $summary['due_soon_count'] ?></div>
|
|
<div class="small text-muted">siapkan jadwal servis berikutnya</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-5">
|
|
<div class="surface-card dashboard-note-card h-100">
|
|
<div class="small text-uppercase text-muted mb-2">Cara paling gampang pakai dashboard</div>
|
|
<h2 class="h5 mb-3">Masukkan satu reminder per item servis.</h2>
|
|
<div class="d-flex flex-column gap-2 small text-secondary">
|
|
<div class="dashboard-note-item">Isi nama kendaraan dan tanggal servis terakhir.</div>
|
|
<div class="dashboard-note-item">Pilih item servis, misalnya oli mesin atau CVT.</div>
|
|
<div class="dashboard-note-item">Atur interval hari agar dashboard menghitung due date berikutnya.</div>
|
|
</div>
|
|
<div class="mt-4 d-flex flex-wrap gap-2">
|
|
<span class="summary-chip">Privat per akun</span>
|
|
<span class="summary-chip">Cocok untuk pemula</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="py-4 py-lg-5">
|
|
<div class="container">
|
|
<div class="row g-4 align-items-start">
|
|
<div class="col-xl-4">
|
|
<div class="surface-card sticky-card dashboard-form-card">
|
|
<div class="d-flex justify-content-between align-items-start mb-3 gap-3">
|
|
<div>
|
|
<h2 class="h4 mb-1">Tambah catatan servis</h2>
|
|
<p class="small text-secondary mb-0">Isi satu item servis per reminder agar jadwalnya tetap akurat dan gampang dicek nanti.</p>
|
|
</div>
|
|
<span class="badge badge-soft">Privat</span>
|
|
</div>
|
|
<div class="form-helper-row mb-3">
|
|
<span class="summary-chip">Motor & mobil</span>
|
|
<span class="summary-chip">Hitung due otomatis</span>
|
|
</div>
|
|
<form method="post" class="vstack gap-3" novalidate>
|
|
<div>
|
|
<label for="vehicle_name" class="form-label">Nama kendaraan</label>
|
|
<input type="text" class="form-control <?= isset($errors['vehicle_name']) ? 'is-invalid' : '' ?>" id="vehicle_name" name="vehicle_name" value="<?= e((string) $formData['vehicle_name']) ?>" placeholder="Contoh: Vario 125 / Avanza Harian">
|
|
<?php if (isset($errors['vehicle_name'])): ?><div class="invalid-feedback"><?= e($errors['vehicle_name']) ?></div><?php endif; ?>
|
|
</div>
|
|
<div class="row g-3">
|
|
<div class="col-sm-6">
|
|
<label for="vehicle_category" class="form-label">Jenis</label>
|
|
<select class="form-select <?= isset($errors['vehicle_category']) ? 'is-invalid' : '' ?>" id="vehicle_category" name="vehicle_category">
|
|
<option value="Motor" <?= ($formData['vehicle_category'] ?? '') === 'Motor' ? 'selected' : '' ?>>Motor</option>
|
|
<option value="Mobil" <?= ($formData['vehicle_category'] ?? '') === 'Mobil' ? 'selected' : '' ?>>Mobil</option>
|
|
</select>
|
|
<?php if (isset($errors['vehicle_category'])): ?><div class="invalid-feedback"><?= e($errors['vehicle_category']) ?></div><?php endif; ?>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<label for="plate_number" class="form-label">Nomor polisi</label>
|
|
<input type="text" class="form-control" id="plate_number" name="plate_number" value="<?= e((string) $formData['plate_number']) ?>" placeholder="B 1234 CD">
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label for="service_name" class="form-label">Item servis</label>
|
|
<select class="form-select <?= isset($errors['service_name']) ? 'is-invalid' : '' ?>" id="service_name" name="service_name" data-service-select>
|
|
<?php foreach ($catalog as $serviceName => $defaultDays): ?>
|
|
<option value="<?= e($serviceName) ?>" data-default-days="<?= (int) $defaultDays ?>" <?= ($formData['service_name'] ?? '') === $serviceName ? 'selected' : '' ?>><?= e($serviceName) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
<?php if (isset($errors['service_name'])): ?><div class="invalid-feedback"><?= e($errors['service_name']) ?></div><?php endif; ?>
|
|
</div>
|
|
<div class="row g-3 align-items-end">
|
|
<div class="col-sm-6">
|
|
<label for="last_service_date" class="form-label">Servis terakhir</label>
|
|
<input type="date" class="form-control <?= isset($errors['last_service_date']) ? 'is-invalid' : '' ?>" id="last_service_date" name="last_service_date" value="<?= e((string) $formData['last_service_date']) ?>">
|
|
<?php if (isset($errors['last_service_date'])): ?><div class="invalid-feedback"><?= e($errors['last_service_date']) ?></div><?php endif; ?>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<label for="reminder_interval_days" class="form-label">Interval (hari)</label>
|
|
<div class="input-group has-validation">
|
|
<input type="number" class="form-control <?= isset($errors['reminder_interval_days']) ? 'is-invalid' : '' ?>" id="reminder_interval_days" name="reminder_interval_days" min="1" max="730" value="<?= e((string) $formData['reminder_interval_days']) ?>" data-interval-input>
|
|
<button class="btn btn-outline-secondary" type="button" data-apply-default>Default</button>
|
|
</div>
|
|
<?php if (isset($errors['reminder_interval_days'])): ?><div class="invalid-feedback d-block"><?= e($errors['reminder_interval_days']) ?></div><?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<div class="row g-3">
|
|
<div class="col-sm-6">
|
|
<label for="odometer_km" class="form-label">Kilometer</label>
|
|
<input type="number" class="form-control <?= isset($errors['odometer_km']) ? 'is-invalid' : '' ?>" id="odometer_km" name="odometer_km" min="0" value="<?= e((string) $formData['odometer_km']) ?>" placeholder="Contoh: 18250">
|
|
<?php if (isset($errors['odometer_km'])): ?><div class="invalid-feedback"><?= e($errors['odometer_km']) ?></div><?php endif; ?>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<label for="notes" class="form-label">Catatan</label>
|
|
<input type="text" class="form-control" id="notes" name="notes" value="<?= e((string) $formData['notes']) ?>" placeholder="Contoh: Pakai oli 10W-40">
|
|
</div>
|
|
</div>
|
|
<button type="submit" class="btn btn-dark w-100">Simpan dan aktifkan reminder</button>
|
|
<div class="small text-muted">Tips: tombol <strong>Default</strong> akan mengisi interval umum sesuai item servis yang dipilih.</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-8">
|
|
<div class="surface-card mb-4 dashboard-list-panel">
|
|
<div class="d-flex flex-column flex-md-row justify-content-between align-items-md-center gap-3 mb-3">
|
|
<div>
|
|
<h2 class="h4 mb-1">Daftar reminder servis</h2>
|
|
<p class="small text-secondary mb-0">Semua catatan di bawah ini hanya milik akun <?= e($userName) ?>.</p>
|
|
</div>
|
|
<div class="d-flex flex-wrap gap-2" role="tablist" aria-label="Filter status reminder">
|
|
<button type="button" class="btn btn-sm btn-dark filter-button is-active" data-filter="all">Semua</button>
|
|
<button type="button" class="btn btn-sm btn-outline-secondary filter-button" data-filter="status-overdue">Terlambat</button>
|
|
<button type="button" class="btn btn-sm btn-outline-secondary filter-button" data-filter="status-soon">Segera</button>
|
|
<button type="button" class="btn btn-sm btn-outline-secondary filter-button" data-filter="status-ok">Aman</button>
|
|
</div>
|
|
</div>
|
|
<?php if ($services): ?>
|
|
<div class="list-grid" data-reminder-list>
|
|
<?php foreach ($services as $service): ?>
|
|
<?php $state = due_state($service['next_due_date'] ?? null); ?>
|
|
<article class="list-card <?= e($state['class']) ?> <?= $createdId === (int) $service['id'] ? 'list-card-highlight' : '' ?>" data-status="<?= e($state['class']) ?>">
|
|
<div class="list-card-top d-flex justify-content-between align-items-start gap-3 mb-3">
|
|
<div>
|
|
<div class="small text-muted mb-1"><?= e($service['vehicle_category']) ?><?= !empty($service['plate_number']) ? ' · ' . e($service['plate_number']) : '' ?></div>
|
|
<h3 class="h5 mb-1"><?= e($service['vehicle_name']) ?></h3>
|
|
<div class="text-secondary small"><?= e($service['service_name']) ?></div>
|
|
</div>
|
|
<span class="status-pill <?= e($state['class']) ?>"><?= e($state['label']) ?></span>
|
|
</div>
|
|
<div class="list-meta-grid mb-3">
|
|
<div class="detail-box">
|
|
<div class="detail-label">Terakhir servis</div>
|
|
<div class="detail-number"><?= e(date('d M Y', strtotime((string) $service['last_service_date']))) ?></div>
|
|
</div>
|
|
<div class="detail-box">
|
|
<div class="detail-label">Next due</div>
|
|
<div class="detail-number"><?= e(date('d M Y', strtotime((string) $service['next_due_date']))) ?></div>
|
|
</div>
|
|
<div class="detail-box">
|
|
<div class="detail-label">Interval</div>
|
|
<div class="detail-number"><?= (int) $service['reminder_interval_days'] ?> hari</div>
|
|
</div>
|
|
</div>
|
|
<div class="d-flex justify-content-between align-items-center gap-2 flex-wrap">
|
|
<div class="small text-muted"><?= $service['odometer_km'] ? number_format((int) $service['odometer_km']) . ' km' : 'Kilometer belum diisi' ?></div>
|
|
<a class="btn btn-sm btn-outline-secondary" href="<?= e(app_url('service.php')) ?>?id=<?= (int) $service['id'] ?>">Buka detail</a>
|
|
</div>
|
|
</article>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="empty-state text-center py-5 px-3">
|
|
<h3 class="h5 mb-2">Belum ada reminder di akun ini</h3>
|
|
<p class="text-secondary mb-0">Mulai dari satu catatan sederhana — misalnya ganti oli mesin — lalu dashboard akan langsung menghitung servis berikutnya untuk akun kamu sendiri.</p>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="surface-card muted-panel admin-info-card">
|
|
<div class="row g-3 align-items-center">
|
|
<div class="col-md-8">
|
|
<h2 class="h6 mb-1">Data kamu tetap privat</h2>
|
|
<p class="small text-secondary mb-0">Dashboard ini hanya menampilkan reminder milik akun yang sedang login, jadi catatan servis pengguna lain tidak ikut terlihat di sini.</p>
|
|
</div>
|
|
<div class="col-md-4 text-md-end">
|
|
<span class="small text-muted">Aman dipakai untuk banyak akun.</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<?php render_page_end(); ?>
|