This commit is contained in:
Saufi
2026-06-03 08:51:22 +08:00
commit a14d43fe34
347 changed files with 38197 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
<div class="content-panel p-2 mb-4">
<div class="d-flex flex-wrap gap-2">
<a class="btn btn-sm {{ request()->routeIs('admin.setup.index') ? 'btn-primary' : 'btn-outline-primary' }}" href="{{ route('admin.setup.index') }}">
<i class="bi bi-grid me-1"></i>Overview
</a>
<a class="btn btn-sm {{ request()->routeIs('admin.setup.positions.*') ? 'btn-primary' : 'btn-outline-primary' }}" href="{{ route('admin.setup.positions.index') }}">Jawatan</a>
<a class="btn btn-sm {{ request()->routeIs('admin.setup.pusat.*') ? 'btn-primary' : 'btn-outline-primary' }}" href="{{ route('admin.setup.pusat.index') }}">Pusat</a>
<a class="btn btn-sm {{ request()->routeIs('admin.setup.import.*') ? 'btn-success' : 'btn-outline-success' }}" href="{{ route('admin.setup.import.create') }}">
<i class="bi bi-upload me-1"></i>Import
</a>
@php $activeElection = \App\Models\Election::query()->where('status', 'active')->first(); @endphp
@if ($activeElection)
<a class="btn btn-sm {{ request()->routeIs('admin.setup.settings.*') ? 'btn-warning' : 'btn-outline-warning' }}" href="{{ route('admin.setup.settings.edit', $activeElection) }}">
<i class="bi bi-sliders me-1"></i>Tetapan
</a>
@endif
</div>
</div>

View File

@@ -0,0 +1,25 @@
@csrf
<div class="row g-3">
<div class="col-12 col-lg-4">
<label class="form-label" for="election_id">Election</label>
<select id="election_id" name="election_id" class="form-select" required>
@foreach ($elections as $election)
<option value="{{ $election->id }}" @selected(old('election_id', $bahagian->election_id) == $election->id)>{{ $election->name }}</option>
@endforeach
</select>
</div>
<div class="col-12 col-lg-3">
<label class="form-label" for="code">Kod</label>
<input id="code" name="code" class="form-control" value="{{ old('code', $bahagian->code) }}" required>
</div>
<div class="col-12 col-lg-5">
<label class="form-label" for="name">Nama Bahagian</label>
<input id="name" name="name" class="form-control" value="{{ old('name', $bahagian->name) }}" required>
</div>
</div>
<div class="d-flex justify-content-end gap-2 mt-4">
<a href="{{ route('admin.setup.bahagian.index') }}" class="btn btn-outline-secondary">Batal</a>
<button class="btn btn-primary" type="submit"><i class="bi bi-save me-1"></i>Simpan</button>
</div>

View File

@@ -0,0 +1,13 @@
@extends('layouts.app')
@section('title', 'Tambah Bahagian')
@section('content')
<div class="page-heading"><div class="eyebrow">Setup</div><h1 class="h3 mb-0">Tambah Bahagian Pilihanraya</h1></div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<form method="POST" action="{{ route('admin.setup.bahagian.store') }}">
@include('admin.setup.bahagian._form')
</form>
</div>
@endsection

View File

@@ -0,0 +1,14 @@
@extends('layouts.app')
@section('title', 'Edit Bahagian')
@section('content')
<div class="page-heading"><div class="eyebrow">Setup</div><h1 class="h3 mb-0">Edit Bahagian Pilihanraya</h1></div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<form method="POST" action="{{ route('admin.setup.bahagian.update', $bahagian) }}">
@method('PUT')
@include('admin.setup.bahagian._form')
</form>
</div>
@endsection

View File

@@ -0,0 +1,45 @@
@extends('layouts.app')
@section('title', 'Bahagian Pilihanraya')
@section('content')
<div class="page-heading">
<div class="eyebrow">Setup</div>
<div class="d-flex justify-content-between flex-column flex-lg-row gap-3">
<div>
<h1 class="h3 mb-1">Bahagian Pilihanraya</h1>
<p class="text-secondary mb-0">Senarai bahagian pilihanraya untuk election aktif.</p>
</div>
<a href="{{ route('admin.setup.bahagian.create') }}" class="btn btn-primary"><i class="bi bi-plus-circle me-1"></i>Tambah</a>
</div>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead><tr><x-sort-th column="code" label="Kod" /><x-sort-th column="name" label="Nama" /><th>Election</th><th class="text-end no-sort">Tindakan</th></tr></thead>
<tbody>
@forelse ($bahagians as $bahagian)
<tr>
<td class="fw-semibold">{{ $bahagian->code }}</td>
<td>{{ $bahagian->name }}</td>
<td>{{ $bahagian->election?->name }}</td>
<td class="text-end">
<a href="{{ route('admin.setup.bahagian.edit', $bahagian) }}" class="btn btn-sm btn-outline-primary">Edit</a>
<form method="POST" action="{{ route('admin.setup.bahagian.destroy', $bahagian) }}" class="d-inline" data-confirm>
@csrf @method('DELETE')
<button class="btn btn-sm btn-outline-danger" type="submit">Padam</button>
</form>
</td>
</tr>
@empty
<tr><td colspan="4" class="text-center text-secondary py-4">Tiada rekod.</td></tr>
@endforelse
</tbody>
</table>
</div>
{{ $bahagians->links() }}
</div>
@endsection

View File

@@ -0,0 +1,33 @@
@csrf
<div class="row g-3">
<div class="col-12 col-lg-4">
<label class="form-label" for="election_id">Election</label>
<select id="election_id" name="election_id" class="form-select" required>
@foreach ($elections as $election)
<option value="{{ $election->id }}" @selected(old('election_id', $daerah->election_id) == $election->id)>{{ $election->name }}</option>
@endforeach
</select>
</div>
<div class="col-12 col-lg-4">
<label class="form-label" for="bahagian_pilihanraya_id">Bahagian</label>
<select id="bahagian_pilihanraya_id" name="bahagian_pilihanraya_id" class="form-select" required data-tom-select>
@foreach ($bahagians as $bahagian)
<option value="{{ $bahagian->id }}" @selected(old('bahagian_pilihanraya_id', $daerah->bahagian_pilihanraya_id) == $bahagian->id)>{{ $bahagian->code }} - {{ $bahagian->name }}</option>
@endforeach
</select>
</div>
<div class="col-12 col-lg-2">
<label class="form-label" for="code">Kod</label>
<input id="code" name="code" class="form-control" value="{{ old('code', $daerah->code) }}" required>
</div>
<div class="col-12 col-lg-2">
<label class="form-label" for="name">Nama</label>
<input id="name" name="name" class="form-control" value="{{ old('name', $daerah->name) }}" required>
</div>
</div>
<div class="d-flex justify-content-end gap-2 mt-4">
<a href="{{ route('admin.setup.daerah.index') }}" class="btn btn-outline-secondary">Batal</a>
<button class="btn btn-primary" type="submit"><i class="bi bi-save me-1"></i>Simpan</button>
</div>

View File

@@ -0,0 +1,7 @@
@extends('layouts.app')
@section('title', 'Tambah Daerah')
@section('content')
<div class="page-heading"><div class="eyebrow">Setup</div><h1 class="h3 mb-0">Tambah Daerah Mengundi</h1></div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4"><form method="POST" action="{{ route('admin.setup.daerah.store') }}">@include('admin.setup.daerah._form')</form></div>
@endsection

View File

@@ -0,0 +1,7 @@
@extends('layouts.app')
@section('title', 'Edit Daerah')
@section('content')
<div class="page-heading"><div class="eyebrow">Setup</div><h1 class="h3 mb-0">Edit Daerah Mengundi</h1></div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4"><form method="POST" action="{{ route('admin.setup.daerah.update', $daerah) }}">@method('PUT') @include('admin.setup.daerah._form')</form></div>
@endsection

View File

@@ -0,0 +1,41 @@
@extends('layouts.app')
@section('title', 'Daerah Mengundi')
@section('content')
<div class="page-heading">
<div class="eyebrow">Setup</div>
<div class="d-flex justify-content-between flex-column flex-lg-row gap-3">
<div><h1 class="h3 mb-1">Daerah Mengundi</h1><p class="text-secondary mb-0">Daerah mengundi di bawah bahagian pilihanraya.</p></div>
<a href="{{ route('admin.setup.daerah.create') }}" class="btn btn-primary"><i class="bi bi-plus-circle me-1"></i>Tambah</a>
</div>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead><tr><x-sort-th column="code" label="Kod" /><x-sort-th column="name" label="Nama" /><th>Bahagian</th><th>Election</th><th class="text-end no-sort">Tindakan</th></tr></thead>
<tbody>
@forelse ($daerahs as $daerah)
<tr>
<td class="fw-semibold">{{ $daerah->code }}</td>
<td>{{ $daerah->name }}</td>
<td>{{ $daerah->bahagianPilihanraya?->name }}</td>
<td>{{ $daerah->election?->name }}</td>
<td class="text-end">
<a href="{{ route('admin.setup.daerah.edit', $daerah) }}" class="btn btn-sm btn-outline-primary">Edit</a>
<form method="POST" action="{{ route('admin.setup.daerah.destroy', $daerah) }}" class="d-inline" data-confirm>
@csrf @method('DELETE')
<button class="btn btn-sm btn-outline-danger" type="submit">Padam</button>
</form>
</td>
</tr>
@empty
<tr><td colspan="5" class="text-center text-secondary py-4">Tiada rekod.</td></tr>
@endforelse
</tbody>
</table>
</div>
{{ $daerahs->links() }}
</div>
@endsection

View File

@@ -0,0 +1,128 @@
@extends('layouts.app')
@section('title', 'Import Pusat Mengundi')
@section('content')
<div class="page-heading">
<div class="eyebrow">Admin · Setup</div>
<h1 class="h3 mb-1">Import Pusat Mengundi</h1>
<p class="text-secondary mb-0">Upload fail XLSX untuk mencipta DUN, Pusat Mengundi, Saluran, dan Kuota secara automatik.</p>
</div>
@include('admin.setup._nav')
@if (session('import_errors'))
<div class="alert alert-warning" role="alert">
<div class="fw-semibold mb-1">Beberapa baris tidak dapat diimport:</div>
<ul class="mb-0 small">
@foreach (session('import_errors') as $err)
<li>{{ $err }}</li>
@endforeach
</ul>
</div>
@endif
<div class="row g-3">
<div class="col-12 col-xl-7">
<div class="content-panel p-3 p-md-4">
<h2 class="h5 mb-3">Borang Import</h2>
<form method="POST" action="{{ route('admin.setup.import.store') }}" enctype="multipart/form-data">
@csrf
<div class="mb-3">
<label for="election_id" class="form-label fw-semibold">Pilihan Raya</label>
<select id="election_id" name="election_id" class="form-select @error('election_id') is-invalid @enderror" required>
<option value="">Pilih pilihan raya</option>
@foreach ($elections as $election)
<option value="{{ $election->id }}" @selected(old('election_id') == $election->id)>
{{ $election->name }}
</option>
@endforeach
</select>
@error('election_id')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="row g-3 mb-3">
<div class="col-md-4">
<label for="dun_code" class="form-label fw-semibold">Kod DUN</label>
<input id="dun_code" type="text" name="dun_code" value="{{ old('dun_code', 'N49') }}"
class="form-control @error('dun_code') is-invalid @enderror" maxlength="20"
placeholder="cth: N49" required>
@error('dun_code')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="col-md-8">
<label for="dun_name" class="form-label fw-semibold">Nama DUN</label>
<input id="dun_name" type="text" name="dun_name" value="{{ old('dun_name', 'Kota Iskandar') }}"
class="form-control @error('dun_name') is-invalid @enderror" maxlength="255"
placeholder="cth: Kota Iskandar" required>
@error('dun_name')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
</div>
<div class="mb-4">
<label for="file" class="form-label fw-semibold">Fail XLSX Senarai Pusat Mengundi</label>
<input id="file" type="file" name="file" accept=".xlsx"
class="form-control @error('file') is-invalid @enderror" required>
<div class="form-text">Format: .xlsx sahaja, saiz maksimum 10MB.</div>
@error('file')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="alert alert-warning py-2 small" role="alert">
<i class="bi bi-exclamation-triangle me-1"></i>
<strong>Amaran:</strong> Import akan <strong>menggantikan</strong> semua data Pusat Mengundi, Saluran, dan Kuota sedia ada untuk DUN yang sama. Pastikan fail betul sebelum teruskan.
</div>
<div class="d-flex justify-content-end gap-2 mt-3">
<a href="{{ route('admin.setup.index') }}" class="btn btn-outline-secondary">Batal</a>
<button type="submit" class="btn btn-success">
<i class="bi bi-upload me-1"></i>Import Data
</button>
</div>
</form>
</div>
</div>
<div class="col-12 col-xl-5">
<div class="content-panel p-3 p-md-4 h-100">
<h2 class="h5 mb-3">Format Fail XLSX</h2>
<p class="text-secondary small mb-2">Fail mesti mempunyai lajur mengikut susunan berikut (baris pertama = tajuk):</p>
<div class="table-responsive">
<table class="table table-sm table-bordered small">
<thead class="table-light">
<tr>
<th>Lajur</th>
<th>Nama</th>
<th>Keterangan</th>
</tr>
</thead>
<tbody>
<tr><td>A</td><td>SEKOLAH</td><td>Nama Pusat Mengundi</td></tr>
<tr><td>B</td><td>NAMA PPM</td><td>Nama PPM (simpan sebagai metadata)</td></tr>
<tr><td>C</td><td>SALURAN</td><td>Bilangan saluran (nombor)</td></tr>
<tr><td>DF</td><td>KTM, POLIS, KP</td><td>Dikira automatik dari bilangan saluran</td></tr>
<tr><td>G</td><td>PPM</td><td>Kuota PPM per pusat (0 atau 1)</td></tr>
<tr><td>H</td><td>KPDP</td><td>Dikira automatik</td></tr>
<tr><td>I</td><td>PAPM</td><td>Kuota PAPM per pusat (nombor)</td></tr>
<tr><td>J</td><td>JKM</td><td>Kuota JKM per pusat</td></tr>
<tr><td>K</td><td>KKM</td><td>Kuota KKM per pusat</td></tr>
<tr><td>L</td><td>TAMBAHAN</td><td>Dikira automatik</td></tr>
<tr><td>M</td><td>NO TELEFON</td><td>Telefon PPM (simpan sebagai metadata)</td></tr>
</tbody>
</table>
</div>
<p class="text-secondary small mt-2 mb-0">
Lajur dengan formula Excel (KTM, POLIS, KP, KPDP, TAMBAHAN) dikira semula secara automatik berdasarkan bilangan saluran nilai asal dalam fail diabaikan.
</p>
</div>
</div>
</div>
@endsection

View File

@@ -0,0 +1,55 @@
@extends('layouts.app')
@section('title', 'Setup Pilihanraya')
@section('content')
<div class="page-heading">
<div class="eyebrow">Admin</div>
<div class="d-flex justify-content-between flex-column flex-lg-row gap-3">
<div>
<h1 class="h3 mb-1">Setup Pilihanraya</h1>
<p class="text-secondary mb-0">Konfigurasi hierarchy, jawatan, kuota, PPM, dan QR Pusat Mengundi.</p>
</div>
</div>
</div>
@include('admin.setup._nav')
<div class="row g-3">
@foreach ([
['label' => 'Election', 'value' => $counts['elections'], 'icon' => 'bi-calendar-event', 'tone' => 'primary'],
['label' => 'DUN', 'value' => $counts['duns'], 'icon' => 'bi-map', 'tone' => 'info'],
['label' => 'Pusat', 'value' => $counts['pusat'], 'icon' => 'bi-building', 'tone' => 'success'],
['label' => 'Saluran', 'value' => $counts['saluran'], 'icon' => 'bi-diagram-3', 'tone' => 'success'],
['label' => 'Jawatan', 'value' => $counts['positions'], 'icon' => 'bi-person-vcard', 'tone' => 'secondary'],
['label' => 'Kuota', 'value' => $counts['quotas'], 'icon' => 'bi-list-ol', 'tone' => 'warning'],
['label' => 'PPM aktif', 'value' => $counts['ppmAssignments'], 'icon' => 'bi-person-check', 'tone' => 'primary'],
] as $card)
<div class="col-12 col-sm-6 col-xl-3">
<div class="stat-card h-100">
<div class="d-flex justify-content-between gap-3">
<div>
<div class="text-secondary small">{{ $card['label'] }}</div>
<div class="fs-3 fw-bold mt-2">{{ $card['value'] }}</div>
</div>
<span class="stat-icon text-bg-{{ $card['tone'] }}"><i class="bi {{ $card['icon'] }}"></i></span>
</div>
</div>
</div>
@endforeach
</div>
<div class="content-panel mt-4 p-3 p-md-4">
<h2 class="h5 mb-3">Tindakan Setup</h2>
<div class="row g-2">
<div class="col-12 col-md-6 col-xl-3"><a class="btn btn-success w-100 text-start" href="{{ route('admin.setup.import.create') }}"><i class="bi bi-upload me-2"></i>Import Data Pusat</a></div>
<div class="col-12 col-md-6 col-xl-3"><a class="btn btn-outline-primary w-100 text-start" href="{{ route('admin.setup.pusat.index') }}"><i class="bi bi-building me-2"></i>Senarai Pusat</a></div>
<div class="col-12 col-md-6 col-xl-3"><a class="btn btn-outline-primary w-100 text-start" href="{{ route('admin.setup.positions.index') }}"><i class="bi bi-person-vcard me-2"></i>Setup Jawatan</a></div>
<div class="col-12 col-md-6 col-xl-3"><a class="btn btn-outline-primary w-100 text-start" href="{{ route('admin.setup.pusat.index') }}"><i class="bi bi-list-ol me-2"></i>Urus Kuota</a></div>
@php $activeElection = \App\Models\Election::query()->where('status', 'active')->first(); @endphp
@if ($activeElection)
<div class="col-12 col-md-6 col-xl-3"><a class="btn btn-outline-warning w-100 text-start" href="{{ route('admin.setup.settings.edit', $activeElection) }}"><i class="bi bi-sliders me-2"></i>Tetapan Pilihanraya</a></div>
@endif
</div>
</div>
@endsection

View File

@@ -0,0 +1,45 @@
@csrf
<div class="row g-3">
<div class="col-12 col-lg-3">
<label class="form-label" for="code">Kod</label>
<input id="code" name="code" class="form-control" value="{{ old('code', $position->code) }}" required>
</div>
<div class="col-12 col-lg-5">
<label class="form-label" for="name">Nama Jawatan</label>
<input id="name" name="name" class="form-control" value="{{ old('name', $position->name) }}" required>
</div>
<div class="col-12 col-lg-2">
<label class="form-label" for="scope">Skop</label>
<select id="scope" name="scope" class="form-select" required>
@foreach (['pusat' => 'Pusat', 'saluran' => 'Saluran', 'external' => 'External'] as $value => $label)
<option value="{{ $value }}" @selected(old('scope', $position->scope ?: 'pusat') === $value)>{{ $label }}</option>
@endforeach
</select>
</div>
<div class="col-12 col-lg-2">
<label class="form-label" for="sort_order">Susunan</label>
<input id="sort_order" name="sort_order" type="number" min="0" class="form-control" value="{{ old('sort_order', $position->sort_order ?? 0) }}">
</div>
<div class="col-12">
<div class="d-flex flex-wrap gap-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" value="1" id="is_public_applyable" name="is_public_applyable" @checked(old('is_public_applyable', $position->is_public_applyable))>
<label class="form-check-label" for="is_public_applyable">Boleh dipohon awam</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="1" id="is_assignable" name="is_assignable" @checked(old('is_assignable', $position->exists ? $position->is_assignable : true))>
<label class="form-check-label" for="is_assignable">Boleh assign</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="1" id="allows_dual_role" name="allows_dual_role" @checked(old('allows_dual_role', $position->allows_dual_role))>
<label class="form-check-label" for="allows_dual_role">Benarkan dual-role</label>
</div>
</div>
</div>
</div>
<div class="d-flex justify-content-end gap-2 mt-4">
<a href="{{ route('admin.setup.positions.index') }}" class="btn btn-outline-secondary">Batal</a>
<button class="btn btn-primary" type="submit"><i class="bi bi-save me-1"></i>Simpan</button>
</div>

View File

@@ -0,0 +1,7 @@
@extends('layouts.app')
@section('title', 'Tambah Jawatan')
@section('content')
<div class="page-heading"><div class="eyebrow">Setup</div><h1 class="h3 mb-0">Tambah Jawatan</h1></div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4"><form method="POST" action="{{ route('admin.setup.positions.store') }}">@include('admin.setup.positions._form')</form></div>
@endsection

View File

@@ -0,0 +1,7 @@
@extends('layouts.app')
@section('title', 'Edit Jawatan')
@section('content')
<div class="page-heading"><div class="eyebrow">Setup</div><h1 class="h3 mb-0">Edit Jawatan</h1></div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4"><form method="POST" action="{{ route('admin.setup.positions.update', $position) }}">@method('PUT') @include('admin.setup.positions._form')</form></div>
@endsection

View File

@@ -0,0 +1,42 @@
@extends('layouts.app')
@section('title', 'Jawatan')
@section('content')
<div class="page-heading">
<div class="eyebrow">Setup</div>
<div class="d-flex justify-content-between flex-column flex-lg-row gap-3">
<div><h1 class="h3 mb-1">Jawatan</h1><p class="text-secondary mb-0">Tetapan jawatan dan ciri assignment.</p></div>
<a href="{{ route('admin.setup.positions.create') }}" class="btn btn-primary"><i class="bi bi-plus-circle me-1"></i>Tambah</a>
</div>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead><tr><x-sort-th column="code" label="Kod" /><x-sort-th column="name" label="Nama" /><x-sort-th column="scope" label="Skop" /><th>Awam</th><th>Dual-role</th><th class="text-end no-sort">Tindakan</th></tr></thead>
<tbody>
@forelse ($positions as $position)
<tr>
<td class="fw-semibold">{{ $position->code }}</td>
<td>{{ $position->name }}</td>
<td><span class="badge text-bg-light border">{{ $position->scope }}</span></td>
<td>{{ $position->is_public_applyable ? 'Ya' : 'Tidak' }}</td>
<td>{{ $position->allows_dual_role ? 'Ya' : 'Tidak' }}</td>
<td class="text-end">
<a href="{{ route('admin.setup.positions.edit', $position) }}" class="btn btn-sm btn-outline-primary">Edit</a>
<form method="POST" action="{{ route('admin.setup.positions.destroy', $position) }}" class="d-inline" data-confirm>
@csrf @method('DELETE')
<button class="btn btn-sm btn-outline-danger" type="submit">Padam</button>
</form>
</td>
</tr>
@empty
<tr><td colspan="6" class="text-center text-secondary py-4">Tiada rekod.</td></tr>
@endforelse
</tbody>
</table>
</div>
{{ $positions->links() }}
</div>
@endsection

View File

@@ -0,0 +1,105 @@
@csrf
<div class="row g-3">
<div class="col-md-6">
<label for="election_id" class="form-label">Pilihan Raya</label>
<select id="election_id" name="election_id" class="form-select @error('election_id') is-invalid @enderror" required>
<option value="">Pilih pilihan raya</option>
@foreach ($elections as $election)
<option value="{{ $election->id }}" @selected((string) old('election_id', $pusat->election_id) === (string) $election->id)>
{{ $election->name }}
</option>
@endforeach
</select>
@error('election_id')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="col-md-6">
<label for="dun_id" class="form-label">Dewan Undangan Negeri (DUN)</label>
<select id="dun_id" name="dun_id" class="form-select @error('dun_id') is-invalid @enderror">
<option value="">Pilih DUN (pilihan)</option>
@foreach ($duns as $dun)
<option value="{{ $dun->id }}" @selected((string) old('dun_id', $pusat->dun_id) === (string) $dun->id)>
{{ $dun->code }} - {{ $dun->name }}
</option>
@endforeach
</select>
@error('dun_id')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="col-md-4">
<label for="code" class="form-label">Kod Pusat</label>
<input id="code" type="text" name="code" value="{{ old('code', $pusat->code) }}" class="form-control @error('code') is-invalid @enderror" maxlength="50" required>
@error('code')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="col-md-8">
<label for="name" class="form-label">Nama Pusat Mengundi</label>
<input id="name" type="text" name="name" value="{{ old('name', $pusat->name) }}" class="form-control @error('name') is-invalid @enderror" maxlength="255" required>
@error('name')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="col-12">
<label for="address" class="form-label">Alamat</label>
<textarea id="address" name="address" rows="3" class="form-control @error('address') is-invalid @enderror">{{ old('address', $pusat->address) }}</textarea>
@error('address')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
@unless ($pusat->exists)
@php
$operationalFields = [
'saluran_count' => ['label' => 'Bilangan Saluran', 'default' => 1, 'min' => 1],
'ktm_count' => ['label' => 'KTM setiap Saluran', 'default' => 1],
'polis_iring_count' => ['label' => 'Polis Iring setiap Saluran', 'default' => 1],
'kp_count' => ['label' => 'KP setiap Saluran', 'default' => 4],
'ppm_count' => ['label' => 'PPM setiap Pusat', 'default' => 1],
'kpdp_count' => ['label' => 'KPDP setiap Saluran', 'default' => 1],
'papm_count' => ['label' => 'PAPM setiap Pusat', 'default' => 0],
'jkm_count' => ['label' => 'JKM setiap Pusat', 'default' => 1],
'kkm_count' => ['label' => 'KKM setiap Pusat', 'default' => 1],
'calon_tambahan_count' => ['label' => 'Calon Tambahan setiap Saluran', 'default' => 1],
];
@endphp
<div class="col-12 mt-4">
<h2 class="h6 mb-1">Bilangan Operasi</h2>
<p class="text-body-secondary small mb-0">Saluran akan dijana mengikut nombor secara automatik.</p>
</div>
@foreach ($operationalFields as $field => $configuration)
<div class="col-6 col-md-4 col-xl-3">
<label for="{{ $field }}" class="form-label">{{ $configuration['label'] }}</label>
<input
id="{{ $field }}"
type="number"
name="{{ $field }}"
value="{{ old($field, $configuration['default']) }}"
min="{{ $configuration['min'] ?? 0 }}"
max="100"
class="form-control @error($field) is-invalid @enderror"
required
>
@error($field)
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
@endforeach
@endunless
</div>
<div class="d-flex justify-content-end gap-2 mt-4">
<a href="{{ $pusat->exists ? route('admin.setup.pusat.show', $pusat) : route('admin.setup.pusat.index') }}" class="btn btn-outline-secondary">Batal</a>
<button class="btn btn-primary" type="submit">
<i class="bi bi-save me-1"></i>{{ $pusat->exists ? 'Kemas Kini Pusat' : 'Simpan Pusat' }}
</button>
</div>

View File

@@ -0,0 +1,18 @@
@extends('layouts.app')
@section('title', 'Tambah Pusat')
@section('content')
<div class="page-heading">
<div class="eyebrow">Setup</div>
<h1 class="h3 mb-0">Tambah Pusat Mengundi</h1>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<form method="POST" action="{{ route('admin.setup.pusat.store') }}">
@include('admin.setup.pusat._form')
</form>
</div>
@endsection

View File

@@ -0,0 +1,19 @@
@extends('layouts.app')
@section('title', 'Edit Pusat')
@section('content')
<div class="page-heading">
<div class="eyebrow">Setup</div>
<h1 class="h3 mb-0">Edit Pusat Mengundi</h1>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<form method="POST" action="{{ route('admin.setup.pusat.update', $pusat) }}">
@method('PUT')
@include('admin.setup.pusat._form')
</form>
</div>
@endsection

View File

@@ -0,0 +1,47 @@
@extends('layouts.app')
@section('title', 'Pusat Mengundi')
@section('content')
<div class="page-heading">
<div class="eyebrow">Setup</div>
<div class="d-flex justify-content-between flex-column flex-lg-row gap-3">
<div><h1 class="h3 mb-1">Pusat Mengundi</h1><p class="text-secondary mb-0">Pusat Mengundi, QR pendaftaran, dan assignment PPM.</p></div>
<a href="{{ route('admin.setup.pusat.create') }}" class="btn btn-primary"><i class="bi bi-plus-circle me-1"></i>Tambah</a>
</div>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead><tr><x-sort-th column="code" label="Kod" /><x-sort-th column="name" label="Nama" /><th>DUN</th><th>PPM</th><th>Saluran</th><th>QR</th><th class="text-end no-sort">Tindakan</th></tr></thead>
<tbody>
@forelse ($pusats as $pusat)
<tr>
<td class="fw-semibold">{{ $pusat->code }}</td>
<td>{{ $pusat->name }}</td>
<td>{{ $pusat->dun?->code }}</td>
<td class="small text-secondary">{{ $pusat->ppm_name ?: '-' }}</td>
<td>{{ $pusat->saluran_mengundis_count ?? $pusat->saluranMengundis->count() }}</td>
<td><span class="badge {{ $pusat->qr_code_path ? 'text-bg-success' : 'text-bg-secondary' }}">{{ $pusat->qr_code_path ? 'Ada' : 'Belum' }}</span></td>
<td class="text-end">
<a href="{{ route('admin.setup.pusat.show', $pusat) }}" class="btn btn-sm btn-outline-primary">Buka</a>
<a href="{{ route('admin.setup.pusat.saluran.index', $pusat) }}" class="btn btn-sm btn-outline-info">Saluran</a>
<a href="{{ route('admin.setup.pusat.edit', $pusat) }}" class="btn btn-sm btn-outline-secondary">Edit</a>
<form action="{{ route('admin.setup.pusat.destroy', $pusat) }}" method="POST" class="d-inline"
onsubmit="return confirm('Padam {{ addslashes($pusat->name) }}? Tindakan ini tidak boleh diundur.')">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-sm btn-outline-danger">Padam</button>
</form>
</td>
</tr>
@empty
<tr><td colspan="7" class="text-center text-secondary py-4">Tiada rekod. <a href="{{ route('admin.setup.import.create') }}">Import data pusat</a>.</td></tr>
@endforelse
</tbody>
</table>
</div>
{{ $pusats->links() }}
</div>
@endsection

View File

@@ -0,0 +1,87 @@
@extends('layouts.app')
@section('title', $pusat->name)
@section('content')
<div class="page-heading">
<div class="eyebrow">Pusat Mengundi</div>
<div class="d-flex justify-content-between flex-column flex-lg-row gap-3">
<div>
<h1 class="h3 mb-1">{{ $pusat->name }}</h1>
<p class="text-secondary mb-0">{{ $pusat->code }} - {{ $pusat->daerahMengundi?->name }}</p>
</div>
<div class="d-flex gap-2">
<a href="{{ route('admin.setup.pusat.edit', $pusat) }}" class="btn btn-outline-primary"><i class="bi bi-pencil me-1"></i>Edit</a>
<form method="POST" action="{{ route('admin.setup.pusat.generate-qr', $pusat) }}">
@csrf
<button class="btn btn-primary" type="submit"><i class="bi bi-qr-code me-1"></i>Jana QR</button>
</form>
</div>
</div>
</div>
@include('admin.setup._nav')
<div class="row g-4">
<div class="col-12 col-xl-7">
<div class="content-panel p-3 p-md-4 mb-4">
<h2 class="h5 mb-3">Maklumat Pusat</h2>
<dl class="row mb-0">
<dt class="col-sm-4">Election</dt><dd class="col-sm-8">{{ $pusat->election?->name }}</dd>
<dt class="col-sm-4">Alamat</dt><dd class="col-sm-8">{{ $pusat->address ?: '-' }}</dd>
<dt class="col-sm-4">Public UUID</dt><dd class="col-sm-8"><code>{{ $pusat->public_uuid }}</code></dd>
<dt class="col-sm-4">Link QR</dt>
<dd class="col-sm-8">
@if ($pusat->registration_url)
<a href="{{ $pusat->registration_url }}" target="_blank">{{ $pusat->registration_url }}</a>
@else
<span class="text-secondary">Belum dijana.</span>
@endif
</dd>
</dl>
</div>
<div class="content-panel p-3 p-md-4">
<h2 class="h5 mb-3">Saluran</h2>
<div class="table-responsive">
<table class="table table-sm align-middle">
<thead><tr><th>No.</th><th>Nama</th><th>Pengundi</th></tr></thead>
<tbody>
@forelse ($pusat->saluranMengundis as $saluran)
<tr><td>{{ $saluran->number }}</td><td>{{ $saluran->name }}</td><td>{{ $saluran->voter_count ?? '-' }}</td></tr>
@empty
<tr><td colspan="3" class="text-secondary text-center py-3">Tiada saluran.</td></tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
<div class="col-12 col-xl-5">
<div class="content-panel p-3 p-md-4 mb-4">
<h2 class="h5 mb-3">QR Pendaftaran</h2>
@if ($pusat->qr_code_path)
<img class="img-fluid border rounded bg-white p-2 mb-3" style="max-width: 220px" src="{{ route('admin.setup.pusat.qr-svg', $pusat) }}" alt="QR Pusat Mengundi">
@else
<p class="text-secondary">QR belum dijana.</p>
@endif
<div class="small text-secondary">QR menunjuk ke pautan awam Pusat Mengundi ini.</div>
</div>
<div class="content-panel p-3 p-md-4">
<h2 class="h5 mb-3">Tetapan PPM</h2>
<p class="mb-3">PPM semasa: <span class="fw-semibold">{{ $ppmAssignment?->user?->name ?? 'Belum ditetapkan' }}</span></p>
<form method="POST" action="{{ route('admin.setup.pusat.assign-ppm', $pusat) }}">
@csrf
<label for="user_id" class="form-label">Pilih pengguna</label>
<select id="user_id" name="user_id" class="form-select mb-3" required data-tom-select>
@foreach ($users as $user)
<option value="{{ $user->id }}" @selected($ppmAssignment?->user_id === $user->id)>{{ $user->name }} - {{ $user->email }}</option>
@endforeach
</select>
<button class="btn btn-primary" type="submit"><i class="bi bi-person-check me-1"></i>Simpan PPM</button>
</form>
</div>
</div>
</div>
@endsection

View File

@@ -0,0 +1,35 @@
@csrf
<div class="row g-3">
<div class="col-12 col-lg-8">
<label class="form-label fw-semibold" for="position_id">Jawatan</label>
<select id="position_id" name="position_id" class="form-select @error('position_id') is-invalid @enderror" required data-tom-select>
<option value="">Pilih jawatan</option>
@foreach ($positions as $position)
<option value="{{ $position->id }}" @selected((int) old('position_id', $quota->position_id) === $position->id)>
{{ $position->code }} {{ $position->name }}
</option>
@endforeach
</select>
@error('position_id')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="col-12 col-lg-4">
<label class="form-label fw-semibold" for="quota">Bilangan Kekosongan</label>
<input id="quota" name="quota" type="number" min="0" max="9999"
class="form-control @error('quota') is-invalid @enderror"
value="{{ old('quota', $quota->quota ?? 0) }}" required>
@error('quota')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
</div>
<div class="d-flex justify-content-end gap-2 mt-4">
<a href="{{ route('admin.setup.pusat.saluran.kuota.index', [$pusat, $saluran]) }}" class="btn btn-outline-secondary">Batal</a>
<button class="btn btn-primary" type="submit">
<i class="bi bi-save me-1"></i>{{ $quota->exists ? 'Kemas Kini' : 'Simpan' }}
</button>
</div>

View File

@@ -0,0 +1,41 @@
@csrf
<div class="row g-3">
<div class="col-12 col-lg-8">
<label class="form-label fw-semibold" for="position_id">Jawatan</label>
@if ($quota->exists)
{{-- Edit: papar nama sahaja, tidak boleh tukar jawatan (guna updateOrCreate) --}}
<input type="hidden" name="position_id" value="{{ $quota->position_id }}">
<input type="text" class="form-control" value="{{ $quota->position?->code }} — {{ $quota->position?->name }}" disabled>
@else
<select id="position_id" name="position_id" class="form-select @error('position_id') is-invalid @enderror" required data-tom-select>
<option value="">Pilih jawatan</option>
@foreach ($positions as $position)
<option value="{{ $position->id }}" @selected((int) old('position_id', $quota->position_id) === $position->id)>
{{ $position->code }} {{ $position->name }}
</option>
@endforeach
</select>
@error('position_id')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
@endif
</div>
<div class="col-12 col-lg-4">
<label class="form-label fw-semibold" for="quota">Bilangan Kekosongan</label>
<input id="quota" name="quota" type="number" min="0" max="9999"
class="form-control @error('quota') is-invalid @enderror"
value="{{ old('quota', $quota->quota ?? 0) }}" required>
@error('quota')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
</div>
<div class="d-flex justify-content-end gap-2 mt-4">
<a href="{{ route('admin.setup.pusat.kuota.index', $pusat) }}" class="btn btn-outline-secondary">Batal</a>
<button class="btn btn-primary" type="submit">
<i class="bi bi-save me-1"></i>{{ $quota->exists ? 'Kemas Kini' : 'Simpan' }}
</button>
</div>

View File

@@ -0,0 +1,23 @@
@extends('layouts.app')
@section('title', 'Tambah Kuota — Saluran ' . $saluran->number)
@section('content')
<div class="page-heading">
<div class="eyebrow">
Setup ·
<a href="{{ route('admin.setup.pusat.index') }}">Pusat Mengundi</a> ·
<a href="{{ route('admin.setup.pusat.saluran.index', $pusat) }}">{{ $pusat->name }}</a> ·
<a href="{{ route('admin.setup.pusat.saluran.kuota.index', [$pusat, $saluran]) }}">Saluran {{ $saluran->number }}</a>
</div>
<h1 class="h3 mb-0">Tambah Kuota Jawatan</h1>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<form method="POST" action="{{ route('admin.setup.pusat.saluran.kuota.store', [$pusat, $saluran]) }}">
@include('admin.setup.quotas._form')
</form>
</div>
@endsection

View File

@@ -0,0 +1,24 @@
@extends('layouts.app')
@section('title', 'Edit Kuota — ' . $quota->position?->code)
@section('content')
<div class="page-heading">
<div class="eyebrow">
Setup ·
<a href="{{ route('admin.setup.pusat.index') }}">Pusat Mengundi</a> ·
<a href="{{ route('admin.setup.pusat.saluran.index', $pusat) }}">{{ $pusat->name }}</a> ·
<a href="{{ route('admin.setup.pusat.saluran.kuota.index', [$pusat, $saluran]) }}">Saluran {{ $saluran->number }}</a>
</div>
<h1 class="h3 mb-0">Edit Kuota Jawatan</h1>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<form method="POST" action="{{ route('admin.setup.pusat.saluran.kuota.update', [$pusat, $saluran, $quota]) }}">
@method('PUT')
@include('admin.setup.quotas._form')
</form>
</div>
@endsection

View File

@@ -0,0 +1,70 @@
@extends('layouts.app')
@section('title', 'Kuota — Saluran ' . $saluran->number)
@section('content')
<div class="page-heading">
<div class="eyebrow">
Setup ·
<a href="{{ route('admin.setup.pusat.index') }}">Pusat Mengundi</a> ·
<a href="{{ route('admin.setup.pusat.saluran.index', $pusat) }}">{{ $pusat->name }}</a>
</div>
<div class="d-flex justify-content-between flex-column flex-lg-row gap-3">
<div>
<h1 class="h3 mb-1">Kuota Jawatan</h1>
<p class="text-secondary mb-0">{{ $pusat->code }} {{ $pusat->name }} · Saluran {{ $saluran->number }}</p>
</div>
<a href="{{ route('admin.setup.pusat.saluran.kuota.create', [$pusat, $saluran]) }}" class="btn btn-primary">
<i class="bi bi-plus-circle me-1"></i>Tambah Kuota
</a>
</div>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th>Jawatan</th>
<x-sort-th column="quota" label="Kuota" class="text-end" />
<th class="text-end no-sort">Tindakan</th>
</tr>
</thead>
<tbody>
@forelse ($quotas as $quota)
<tr>
<td>
<span class="fw-semibold">{{ $quota->position?->code }}</span>
<div class="small text-secondary">{{ $quota->position?->name }}</div>
</td>
<td class="text-end fw-semibold">{{ $quota->quota }}</td>
<td class="text-end">
<a href="{{ route('admin.setup.pusat.saluran.kuota.edit', [$pusat, $saluran, $quota]) }}" class="btn btn-sm btn-outline-secondary">Edit</a>
<form method="POST" action="{{ route('admin.setup.pusat.saluran.kuota.destroy', [$pusat, $saluran, $quota]) }}" class="d-inline"
onsubmit="return confirm('Padam kuota {{ addslashes($quota->position?->code) }}?')">
@csrf @method('DELETE')
<button class="btn btn-sm btn-outline-danger" type="submit">Padam</button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="3" class="text-center text-secondary py-4">
Tiada kuota. <a href="{{ route('admin.setup.pusat.saluran.kuota.create', [$pusat, $saluran]) }}">Tambah kuota</a>.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
{{ $quotas->links() }}
</div>
<div class="mt-3">
<a href="{{ route('admin.setup.pusat.saluran.index', $pusat) }}" class="btn btn-outline-secondary">
<i class="bi bi-arrow-left me-1"></i>Kembali ke Saluran
</a>
</div>
@endsection

View File

@@ -0,0 +1,23 @@
@extends('layouts.app')
@section('title', 'Tambah Kuota Pusat — ' . $pusat->name)
@section('content')
<div class="page-heading">
<div class="eyebrow">
Setup ·
<a href="{{ route('admin.setup.pusat.index') }}">Pusat Mengundi</a> ·
<a href="{{ route('admin.setup.pusat.saluran.index', $pusat) }}">{{ $pusat->name }}</a> ·
<a href="{{ route('admin.setup.pusat.kuota.index', $pusat) }}">Saluran 0 (Pusat)</a>
</div>
<h1 class="h3 mb-0">Tambah Kuota Peringkat Pusat</h1>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<form method="POST" action="{{ route('admin.setup.pusat.kuota.store', $pusat) }}">
@include('admin.setup.quotas._pusat-form')
</form>
</div>
@endsection

View File

@@ -0,0 +1,24 @@
@extends('layouts.app')
@section('title', 'Edit Kuota Pusat — ' . $quota->position?->code)
@section('content')
<div class="page-heading">
<div class="eyebrow">
Setup ·
<a href="{{ route('admin.setup.pusat.index') }}">Pusat Mengundi</a> ·
<a href="{{ route('admin.setup.pusat.saluran.index', $pusat) }}">{{ $pusat->name }}</a> ·
<a href="{{ route('admin.setup.pusat.kuota.index', $pusat) }}">Saluran 0 (Pusat)</a>
</div>
<h1 class="h3 mb-0">Edit Kuota Peringkat Pusat</h1>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<form method="POST" action="{{ route('admin.setup.pusat.kuota.update', [$pusat, $quota]) }}">
@method('PUT')
@include('admin.setup.quotas._pusat-form')
</form>
</div>
@endsection

View File

@@ -0,0 +1,70 @@
@extends('layouts.app')
@section('title', 'Kuota Pusat — ' . $pusat->name)
@section('content')
<div class="page-heading">
<div class="eyebrow">
Setup ·
<a href="{{ route('admin.setup.pusat.index') }}">Pusat Mengundi</a> ·
<a href="{{ route('admin.setup.pusat.saluran.index', $pusat) }}">{{ $pusat->name }}</a>
</div>
<div class="d-flex justify-content-between flex-column flex-lg-row gap-3">
<div>
<h1 class="h3 mb-1">Kuota Jawatan Peringkat Pusat</h1>
<p class="text-secondary mb-0">{{ $pusat->code }} {{ $pusat->name }} · Saluran 0 (Pusat)</p>
</div>
<a href="{{ route('admin.setup.pusat.kuota.create', $pusat) }}" class="btn btn-primary">
<i class="bi bi-plus-circle me-1"></i>Tambah Kuota
</a>
</div>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th>Jawatan</th>
<x-sort-th column="quota" label="Kuota" class="text-end" />
<th class="text-end no-sort">Tindakan</th>
</tr>
</thead>
<tbody>
@forelse ($quotas as $quota)
<tr>
<td>
<span class="fw-semibold">{{ $quota->position?->code }}</span>
<div class="small text-secondary">{{ $quota->position?->name }}</div>
</td>
<td class="text-end fw-semibold">{{ $quota->quota }}</td>
<td class="text-end">
<a href="{{ route('admin.setup.pusat.kuota.edit', [$pusat, $quota]) }}" class="btn btn-sm btn-outline-secondary">Edit</a>
<form method="POST" action="{{ route('admin.setup.pusat.kuota.destroy', [$pusat, $quota]) }}" class="d-inline"
onsubmit="return confirm('Padam kuota {{ addslashes($quota->position?->code) }}?')">
@csrf @method('DELETE')
<button class="btn btn-sm btn-outline-danger" type="submit">Padam</button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="3" class="text-center text-secondary py-4">
Tiada kuota peringkat pusat. <a href="{{ route('admin.setup.pusat.kuota.create', $pusat) }}">Tambah kuota</a>.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
{{ $quotas->links() }}
</div>
<div class="mt-3">
<a href="{{ route('admin.setup.pusat.saluran.index', $pusat) }}" class="btn btn-outline-secondary">
<i class="bi bi-arrow-left me-1"></i>Kembali ke Saluran
</a>
</div>
@endsection

View File

@@ -0,0 +1,28 @@
@csrf
<div class="row g-3">
<div class="col-md-6">
<label for="number" class="form-label">Nombor Saluran</label>
<input id="number" type="text" name="number" value="{{ old('number', $saluran->number) }}"
class="form-control @error('number') is-invalid @enderror" maxlength="20" required>
@error('number')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="col-md-6">
<label for="voter_count" class="form-label">Bilangan Pengundi</label>
<input id="voter_count" type="number" name="voter_count" value="{{ old('voter_count', $saluran->voter_count) }}"
class="form-control @error('voter_count') is-invalid @enderror" min="0">
@error('voter_count')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
</div>
<div class="d-flex justify-content-end gap-2 mt-4">
<a href="{{ route('admin.setup.pusat.saluran.index', $pusat) }}" class="btn btn-outline-secondary">Batal</a>
<button class="btn btn-primary" type="submit">
<i class="bi bi-save me-1"></i>{{ $saluran->exists ? 'Kemas Kini Saluran' : 'Simpan Saluran' }}
</button>
</div>

View File

@@ -0,0 +1,18 @@
@extends('layouts.app')
@section('title', 'Tambah Saluran — ' . $pusat->name)
@section('content')
<div class="page-heading">
<div class="eyebrow">Setup · <a href="{{ route('admin.setup.pusat.index') }}">Pusat Mengundi</a> · <a href="{{ route('admin.setup.pusat.saluran.index', $pusat) }}">{{ $pusat->name }}</a></div>
<h1 class="h3 mb-0">Tambah Saluran Mengundi</h1>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<form method="POST" action="{{ route('admin.setup.pusat.saluran.store', $pusat) }}">
@include('admin.setup.saluran._form')
</form>
</div>
@endsection

View File

@@ -0,0 +1,19 @@
@extends('layouts.app')
@section('title', 'Edit Saluran — ' . $pusat->name)
@section('content')
<div class="page-heading">
<div class="eyebrow">Setup · <a href="{{ route('admin.setup.pusat.index') }}">Pusat Mengundi</a> · <a href="{{ route('admin.setup.pusat.saluran.index', $pusat) }}">{{ $pusat->name }}</a></div>
<h1 class="h3 mb-0">Edit Saluran Mengundi</h1>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<form method="POST" action="{{ route('admin.setup.pusat.saluran.update', [$pusat, $saluran]) }}">
@method('PUT')
@include('admin.setup.saluran._form')
</form>
</div>
@endsection

View File

@@ -0,0 +1,69 @@
@extends('layouts.app')
@section('title', 'Saluran — ' . $pusat->name)
@section('content')
<div class="page-heading">
<div class="eyebrow">Setup · <a href="{{ route('admin.setup.pusat.index') }}">Pusat Mengundi</a></div>
<div class="d-flex justify-content-between flex-column flex-lg-row gap-3">
<div>
<h1 class="h3 mb-1">Saluran Mengundi</h1>
<p class="text-secondary mb-0">{{ $pusat->code }} {{ $pusat->name }}</p>
</div>
<a href="{{ route('admin.setup.pusat.saluran.create', $pusat) }}" class="btn btn-primary">
<i class="bi bi-plus-circle me-1"></i>Tambah Saluran
</a>
</div>
</div>
@include('admin.setup._nav')
<div class="content-panel p-3 p-md-4">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr><x-sort-th column="number" label="No." /><th>Nama</th><x-sort-th column="voter_count" label="Bilangan Pengundi" /><th class="text-end no-sort">Tindakan</th></tr>
</thead>
<tbody>
{{-- Row tetap: Saluran 0 = Kuota peringkat Pusat --}}
<tr class="table-light">
<td class="fw-semibold text-secondary">0</td>
<td>
<span class="fw-semibold">Pusat</span>
<div class="small text-secondary">Kuota jawatan peringkat pusat (PPM, PAPM, JKM, KKM, dll.)</div>
</td>
<td class="text-secondary"></td>
<td class="text-end">
<a href="{{ route('admin.setup.pusat.kuota.index', $pusat) }}" class="btn btn-sm btn-outline-info">Kuota</a>
</td>
</tr>
@forelse ($salurans as $saluran)
<tr>
<td class="fw-semibold">{{ $saluran->number }}</td>
<td>{{ $saluran->name ?? '-' }}</td>
<td>{{ $saluran->voter_count ?? '-' }}</td>
<td class="text-end">
<a href="{{ route('admin.setup.pusat.saluran.kuota.index', [$pusat, $saluran]) }}" class="btn btn-sm btn-outline-info">Kuota</a>
<a href="{{ route('admin.setup.pusat.saluran.edit', [$pusat, $saluran]) }}" class="btn btn-sm btn-outline-secondary">Edit</a>
<form method="POST" action="{{ route('admin.setup.pusat.saluran.destroy', [$pusat, $saluran]) }}" class="d-inline"
onsubmit="return confirm('Padam saluran {{ $saluran->number }}?')">
@csrf @method('DELETE')
<button class="btn btn-sm btn-outline-danger" type="submit">Padam</button>
</form>
</td>
</tr>
@empty
<tr><td colspan="4" class="text-center text-secondary py-4">Tiada saluran. <a href="{{ route('admin.setup.pusat.saluran.create', $pusat) }}">Tambah saluran</a>.</td></tr>
@endforelse
</tbody>
</table>
</div>
{{ $salurans->links() }}
</div>
<div class="mt-3">
<a href="{{ route('admin.setup.pusat.show', $pusat) }}" class="btn btn-outline-secondary">
<i class="bi bi-arrow-left me-1"></i>Kembali ke {{ $pusat->name }}
</a>
</div>
@endsection

View File

@@ -0,0 +1,213 @@
@extends('layouts.app')
@section('title', 'Tetapan Pilihanraya')
@section('content')
<div class="page-heading">
<div class="eyebrow">Admin · Setup</div>
<div class="d-flex justify-content-between flex-column flex-lg-row gap-3">
<div>
<h1 class="h3 mb-1">Tetapan Pilihanraya</h1>
<p class="text-secondary mb-0">{{ $election->name }} · Kawalan tarikh, mod kehadiran, dan pendaftaran.</p>
</div>
</div>
</div>
@include('admin.setup._nav')
<div class="row g-3">
{{-- Status semasa --}}
<div class="col-12 col-xl-4">
<div class="content-panel p-3 p-md-4 h-100">
<h2 class="h5 mb-3">Status Semasa</h2>
@if ($election->settings)
<dl class="mb-0">
<dt class="text-secondary small">Pilihanraya</dt>
<dd class="mb-3">{{ $election->name }}</dd>
<dt class="text-secondary small">Tarikh Daftar Buka</dt>
<dd class="mb-3">{{ $election->settings->registration_start_date?->format('d/m/Y') ?? '-' }}</dd>
<dt class="text-secondary small">Tarikh Daftar Tutup</dt>
<dd class="mb-3">{{ $election->settings->registration_end_date?->format('d/m/Y') ?? '-' }}</dd>
<dt class="text-secondary small">Tarikh Mengundi</dt>
<dd class="mb-3">{{ $election->settings->polling_date?->format('d/m/Y') ?? '-' }}</dd>
<dt class="text-secondary small">Status Pendaftaran</dt>
<dd class="mb-3">
@if ($isRegistrationOpen)
<span class="badge text-bg-success"><i class="bi bi-door-open me-1"></i>Dibuka</span>
@else
<span class="badge text-bg-secondary"><i class="bi bi-door-closed me-1"></i>Ditutup</span>
@endif
@if ($election->settings->is_registration_open_override !== null)
<span class="badge text-bg-warning ms-1"><i class="bi bi-exclamation-triangle me-1"></i>Override aktif</span>
@endif
</dd>
<dt class="text-secondary small">Mod Kehadiran</dt>
<dd class="mb-0">
@if ($election->settings->is_attendance_active)
<span class="badge text-bg-success"><i class="bi bi-check-circle me-1"></i>Aktif</span>
@else
<span class="badge text-bg-secondary"><i class="bi bi-dash-circle me-1"></i>Tidak aktif</span>
@endif
</dd>
</dl>
@else
<p class="text-secondary small mb-0">Tiada tetapan lagi. Isikan borang untuk mencipta tetapan baru.</p>
@endif
</div>
</div>
{{-- Borang tetapan --}}
<div class="col-12 col-xl-8">
<div class="content-panel p-3 p-md-4">
<h2 class="h5 mb-3">{{ $election->settings ? 'Kemaskini Tetapan' : 'Tetapan Baru' }}</h2>
@php
$isNew = $election->settings === null;
$formAction = $isNew
? route('admin.setup.settings.store', $election)
: route('admin.setup.settings.update', $election);
@endphp
<form method="POST" action="{{ $formAction }}">
@csrf
@unless ($isNew) @method('PATCH') @endunless
{{-- Tarikh --}}
<div class="row g-3 mb-4">
<div class="col-12 col-md-4">
<label for="registration_start_date" class="form-label fw-semibold">Tarikh Daftar Buka</label>
<input type="date" class="form-control @error('registration_start_date') is-invalid @enderror"
id="registration_start_date" name="registration_start_date"
value="{{ old('registration_start_date', $election->settings?->registration_start_date?->format('Y-m-d')) }}">
@error('registration_start_date')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="col-12 col-md-4">
<label for="registration_end_date" class="form-label fw-semibold">Tarikh Daftar Tutup</label>
<input type="date" class="form-control @error('registration_end_date') is-invalid @enderror"
id="registration_end_date" name="registration_end_date"
value="{{ old('registration_end_date', $election->settings?->registration_end_date?->format('Y-m-d')) }}">
@error('registration_end_date')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="col-12 col-md-4">
<label for="polling_date" class="form-label fw-semibold">Tarikh Mengundi</label>
<input type="date" class="form-control @error('polling_date') is-invalid @enderror"
id="polling_date" name="polling_date"
value="{{ old('polling_date', $election->settings?->polling_date?->format('Y-m-d')) }}">
@error('polling_date')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
</div>
<hr>
{{-- Mod Kehadiran --}}
<div class="mb-4">
<label class="form-label fw-semibold">Mod Kehadiran</label>
<p class="text-secondary small mb-2">
Apabila diaktifkan, PPM boleh merekod kehadiran staf pada skrin kehadiran.
Aktifkan hanya pada hari mengundi.
</p>
<div class="d-flex gap-3">
<div class="form-check">
<input class="form-check-input" type="radio" name="is_attendance_active"
id="attendance_off" value="0"
{{ old('is_attendance_active', $election->settings?->is_attendance_active ? '1' : '0') === '0' ? 'checked' : '' }}>
<label class="form-check-label" for="attendance_off">
<span class="badge text-bg-secondary"><i class="bi bi-dash-circle me-1"></i>Tidak aktif</span>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="is_attendance_active"
id="attendance_on" value="1"
{{ old('is_attendance_active', $election->settings?->is_attendance_active ? '1' : '0') === '1' ? 'checked' : '' }}>
<label class="form-check-label" for="attendance_on">
<span class="badge text-bg-success"><i class="bi bi-check-circle me-1"></i>Aktif</span>
</label>
</div>
</div>
@error('is_attendance_active')
<div class="text-danger small mt-1">{{ $message }}</div>
@enderror
</div>
<hr>
{{-- Override Pendaftaran --}}
<div class="mb-4">
<label class="form-label fw-semibold">Override Tempoh Pendaftaran</label>
<p class="text-secondary small mb-2">
Secara lalai, sistem mengikut tarikh buka dan tutup pendaftaran yang ditetapkan.
Gunakan override hanya apabila perlu buka atau tutup pendaftaran di luar tarikh tersebut.
</p>
@php
$currentOverride = old('is_registration_open_override',
$election->settings?->is_registration_open_override === null
? ''
: ($election->settings->is_registration_open_override ? '1' : '0')
);
@endphp
<div class="d-flex flex-wrap gap-3">
<div class="form-check">
<input class="form-check-input" type="radio" name="is_registration_open_override"
id="override_auto" value=""
{{ $currentOverride === '' ? 'checked' : '' }}>
<label class="form-check-label" for="override_auto">
<span class="fw-semibold">Auto</span>
<div class="text-secondary small">Ikut tarikh buka/tutup pendaftaran</div>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="is_registration_open_override"
id="override_open" value="1"
{{ $currentOverride === '1' ? 'checked' : '' }}>
<label class="form-check-label" for="override_open">
<span class="fw-semibold text-success">Buka Paksa</span>
<div class="text-secondary small">Buka walaupun di luar tempoh tarikh</div>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="is_registration_open_override"
id="override_closed" value="0"
{{ $currentOverride === '0' ? 'checked' : '' }}>
<label class="form-check-label" for="override_closed">
<span class="fw-semibold text-danger">Tutup Paksa</span>
<div class="text-secondary small">Tutup walaupun dalam tempoh tarikh</div>
</label>
</div>
</div>
@error('is_registration_open_override')
<div class="text-danger small mt-1">{{ $message }}</div>
@enderror
</div>
@if ($election->settings?->is_registration_open_override !== null)
<div class="alert alert-warning py-2" role="alert">
<i class="bi bi-exclamation-triangle me-2"></i>
Override sedang aktif. Tetapkan semula ke <strong>Auto</strong> untuk kembali kepada kawalan tarikh biasa.
</div>
@endif
<div class="d-flex justify-content-end gap-2 mt-3">
<a class="btn btn-outline-secondary" href="{{ route('admin.setup.index') }}">Kembali</a>
<button class="btn btn-primary" type="submit">
<i class="bi bi-save me-1"></i>{{ $isNew ? 'Cipta Tetapan' : 'Simpan Tetapan' }}
</button>
</div>
</form>
</div>
</div>
</div>
@endsection