Files
backend_parkir/resources/views/setup.blade.php
T
pand03-CEOandClaude Sonnet 5 2a9b28581c Rapihin setup/member/lot-parking + fitur intercom, exclude WIP controller & file sampah dari git
Kumpulan perubahan yang udah numpuk di working tree: refactor Setup
(Gate/Vehicle/Member), rapihin memberin & stiker, service parking baru
(ParkingUtilsServices, NetworkService), model/migration lot-parking &
DHCP reservation, dan fitur baru Intercom (controller/model/migration/
view).

ReportTransaksiController versi lokal ini WIP (~90%, masih didebug) -
versi yang bener ada di server, jadi dikeluarin dari git (ditambahin
ke .gitignore) biar gak numpuk nindihin punya server pas git pull di
sana. Sekalian keluarin dump mentah tabel softseting (1.8MB, nyasar
ke-commit), file .bak, dan arsip ad-hoc (api.tgz, c.zip) yang emang
bukan source code.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EAJc2mrpj2cSTe4oowLPzQ
2026-10-04 07:15:54 +07:00

32 lines
6.3 KiB
PHP

<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Persiapan Aplikasi | P-Solution Parking</title>
<style>
:root { --navy:#102a43; --blue:#1f6feb; --mint:#2dd4bf; --ink:#152536; --muted:#6b7b8d; --line:#dce5ef; } *{box-sizing:border-box} body{min-height:100vh;margin:0;color:var(--ink);font-family:Inter,ui-sans-serif,system-ui,sans-serif;background:radial-gradient(circle at 10% 10%,#d8f3f0 0,transparent 30%),linear-gradient(135deg,#f8fbff,#edf3f9)} .shell{width:min(760px,calc(100% - 32px));margin:0 auto;padding:clamp(42px,10vh,96px) 0}.brand{display:flex;gap:12px;align-items:center;color:var(--navy);font-size:14px;font-weight:750;letter-spacing:.04em;text-transform:uppercase}.brand-mark{width:34px;height:34px;display:grid;place-items:center;color:white;font-weight:800;border-radius:11px;background:linear-gradient(135deg,var(--blue),#254f94)}.panel{margin-top:24px;padding:clamp(26px,5vw,46px);background:#fff;border-radius:24px;box-shadow:0 24px 70px #102a431c}h1{max-width:620px;margin:0;color:var(--navy);font-size:clamp(28px,5vw,42px);letter-spacing:-.04em;line-height:1.08}.lead{max-width:610px;margin:15px 0 30px;color:var(--muted);font-size:16px;line-height:1.7}.progress{height:8px;overflow:hidden;border-radius:99px;background:#e8eef5}.progress-bar{height:100%;border-radius:inherit;background:linear-gradient(90deg,var(--blue),var(--mint));transition:width .5s ease}.progress-copy{display:flex;justify-content:space-between;margin:10px 0 24px;color:var(--muted);font-size:13px}.checks{margin:0;padding:0;list-style:none;border-top:1px solid var(--line)}.check{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 2px;border-bottom:1px solid var(--line)}.check-title{display:flex;align-items:center;gap:10px;font-size:14px;font-weight:650}.dot{width:22px;height:22px;display:grid;place-items:center;flex:0 0 auto;border-radius:50%;font-size:12px}.dot.ok{color:#087e68;background:#d9f8ef}.dot.wait{color:#9a5b00;background:#fff0cc}.badge{padding:5px 8px;border-radius:999px;font-size:11px;font-weight:750;letter-spacing:.05em}.badge.ok{color:#087e68;background:#d9f8ef}.badge.wait{color:#9a5b00;background:#fff0cc}.action{display:flex;gap:14px;align-items:center;margin-top:28px}.button{border:0;border-radius:11px;padding:13px 18px;color:white;cursor:pointer;font:inherit;font-weight:700;background:var(--navy)}.button:disabled{cursor:wait;opacity:.65}.action-note{color:var(--muted);font-size:13px;line-height:1.45}.running,.error{display:none;margin-top:20px;padding:12px 14px;border-radius:10px;font-size:14px}.running{align-items:center;gap:10px;color:#0a5a8d;background:#e8f5ff}.error{color:#a52222;background:#ffebeb}.spinner{width:17px;height:17px;border:2px solid #8cc9ec;border-top-color:#1678b9;border-radius:50%;animation:spin .8s linear infinite}@@keyframes spin{to{transform:rotate(360deg)}}@@media(max-width:520px){.action{align-items:flex-start;flex-direction:column}.check{align-items:flex-start}.badge{margin-left:32px}}
</style>
</head>
<body>
@php
$checks = [
['Koneksi dan keamanan database', $status['pgcrypto']],
['Identitas petugas', $status['pegawai_columns']['id']],
['Informasi kontak petugas', $status['pegawai_columns']['email']],
['Verifikasi akun petugas', $status['pegawai_columns']['email_verified_at']],
['Keamanan sesi petugas', $status['pegawai_columns']['remember_token']],
['Akses masuk aplikasi', $status['users_view']],
['Riwayat verifikasi transaksi', $status['veri_time']],
['Penyimpanan sesi aplikasi', $status['sessions']],
];
$readyCount = count(array_filter(array_column($checks, 1)));
@endphp
<main class="shell"><div class="brand"><span class="brand-mark">P</span>P-Solution Parking</div><section class="panel"><h1>Menyiapkan aplikasi untuk digunakan.</h1><p class="lead">Kami sedang memeriksa kebutuhan awal aplikasi. Data dan pengaturan yang sudah ada tetap aman, lalu aplikasi akan menyesuaikan diri dengan sistem parkir di lokasi ini.</p><div class="progress"><div class="progress-bar" style="width:{{ (int) round(($readyCount / count($checks)) * 100) }}%"></div></div><div class="progress-copy"><span>Status persiapan</span><span>{{ $readyCount }}/{{ count($checks) }} bagian siap</span></div><ul class="checks">@foreach($checks as [$label, $ready])<li class="check"><span class="check-title"><span class="dot {{ $ready ? 'ok' : 'wait' }}">{{ $ready ? '✓' : '!' }}</span>{{ $label }}</span><span class="badge {{ $ready ? 'ok' : 'wait' }}">{{ $ready ? 'SIAP' : 'PERLU DISIAPKAN' }}</span></li>@endforeach</ul><div class="action"><button id="runSetup" class="button" type="button">Siapkan Aplikasi</button><span class="action-note">Proses ini tidak menghapus data transaksi atau data operasional yang sudah ada.</span></div><div id="running" class="running"><span class="spinner"></span><span id="runningText">Menyiapkan aplikasi...</span></div><div id="error" class="error"></div></section></main>
<script>
const button=document.getElementById('runSetup'),running=document.getElementById('running'),runningText=document.getElementById('runningText'),errorBox=document.getElementById('error');button.addEventListener('click',async()=>{button.disabled=true;button.textContent='Sedang menyiapkan...';running.style.display='flex';errorBox.style.display='none';const messages=['Memeriksa kesiapan sistem...','Menyesuaikan data petugas...','Menyiapkan akses aplikasi...','Menyelesaikan pengaturan awal...'];let index=0;const interval=setInterval(()=>runningText.textContent=messages[index++%messages.length],900);try{const response=await fetch('{{ route('setup.run') }}',{method:'POST',headers:{'X-CSRF-TOKEN':document.querySelector('meta[name="csrf-token"]').content,'Accept':'application/json'}});const result=await response.json();if(!response.ok||!result.success)throw new Error(result.message||'Persiapan aplikasi belum berhasil.');clearInterval(interval);runningText.textContent='Aplikasi siap. Mengalihkan ke halaman login...';setTimeout(()=>window.location.assign(result.redirect),800)}catch(error){clearInterval(interval);running.style.display='none';errorBox.textContent=error.message;errorBox.style.display='block';button.disabled=false;button.textContent='Coba Siapkan Lagi'}});
</script>
</body>
</html>