164 lines
8.0 KiB
PHP
164 lines
8.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Application;
|
|
use App\Models\Attendance;
|
|
use App\Models\BankVerification;
|
|
use App\Models\PusatMengundi;
|
|
use App\Models\SaluranMengundi;
|
|
use App\Models\StaffAssignment;
|
|
use App\Services\Admin\Management\PennempatanService;
|
|
use App\Services\Ktm\KtmScopeService;
|
|
use App\Services\Ppm\PpmScopeService;
|
|
use App\Services\Public\KtmVacancyService;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\View\View;
|
|
|
|
class DashboardController extends Controller
|
|
{
|
|
public function index(Request $request): RedirectResponse|View
|
|
{
|
|
$user = $request->user();
|
|
|
|
if ($user->hasRole('Admin')) {
|
|
return redirect()->route('admin.dashboard');
|
|
}
|
|
|
|
if ($user->hasRole('Admin Kewangan')) {
|
|
return redirect()->route('kewangan.dashboard');
|
|
}
|
|
|
|
if ($user->hasRole('PPM')) {
|
|
return redirect()->route('ppm.dashboard');
|
|
}
|
|
|
|
if ($user->hasRole('KTM')) {
|
|
return redirect()->route('ktm.dashboard');
|
|
}
|
|
|
|
if ($user->hasRole('Pemohon')) {
|
|
return redirect()->route('pemohon.dashboard');
|
|
}
|
|
|
|
return view('dashboards.index', $this->payload(
|
|
'Dashboard',
|
|
'Akaun ini belum mempunyai peranan sistem.',
|
|
'Hubungi Admin untuk penetapan peranan.',
|
|
[
|
|
['label' => 'Peranan aktif', 'value' => '0', 'icon' => 'bi-shield-lock', 'tone' => 'secondary'],
|
|
['label' => 'Akses modul', 'value' => 'Belum aktif', 'icon' => 'bi-door-closed', 'tone' => 'secondary'],
|
|
],
|
|
));
|
|
}
|
|
|
|
public function admin(PennempatanService $pennempatanService): View
|
|
{
|
|
$pusatsWithVacancy = $pennempatanService->pusatsWithVacancySummary();
|
|
|
|
return view('dashboards.admin', [
|
|
'cards' => [
|
|
['label' => 'Pusat Mengundi', 'value' => (string) PusatMengundi::query()->count(), 'icon' => 'bi-building', 'tone' => 'primary'],
|
|
['label' => 'Saluran', 'value' => (string) SaluranMengundi::query()->count(), 'icon' => 'bi-diagram-3', 'tone' => 'info'],
|
|
['label' => 'Pemohon', 'value' => (string) Application::query()->count(), 'icon' => 'bi-people', 'tone' => 'success'],
|
|
['label' => 'Staf Aktif', 'value' => (string) StaffAssignment::query()->where('status', 'active')->count(), 'icon' => 'bi-person-check', 'tone' => 'success'],
|
|
],
|
|
'pusatsWithVacancy' => $pusatsWithVacancy,
|
|
]);
|
|
}
|
|
|
|
public function kewangan(): View
|
|
{
|
|
$missingBankStatement = BankVerification::query()
|
|
->whereHas('application', fn ($query) => $query->whereIn('status', ['approved', 'assigned']))
|
|
->whereHas('application', fn ($query) => $query->whereDoesntHave('documents', fn ($documentQuery) => $documentQuery->where('document_type', 'bank_statement')))
|
|
->count();
|
|
|
|
return view('dashboards.index', $this->payload(
|
|
'Dashboard Admin Kewangan',
|
|
'Semakan bank dan dokumen kewangan',
|
|
'Paparan asas untuk status verifikasi bank tanpa akses perubahan penempatan.',
|
|
[
|
|
['label' => 'Pending bank', 'value' => (string) BankVerification::query()->where('status', 'pending')->whereHas('application', fn ($query) => $query->whereIn('status', ['approved', 'assigned']))->count(), 'icon' => 'bi-bank', 'tone' => 'warning'],
|
|
['label' => 'Dokumen hilang', 'value' => (string) $missingBankStatement, 'icon' => 'bi-file-earmark-x', 'tone' => 'danger'],
|
|
['label' => 'Ditolak', 'value' => (string) BankVerification::query()->where('status', 'rejected')->count(), 'icon' => 'bi-x-circle', 'tone' => 'danger'],
|
|
['label' => 'Perlu pembetulan', 'value' => (string) BankVerification::query()->where('status', 'requires_correction')->count(), 'icon' => 'bi-pencil-square', 'tone' => 'info'],
|
|
],
|
|
[
|
|
['label' => 'Senarai staf diluluskan', 'route' => 'kewangan.bank.index'],
|
|
['label' => 'Semakan akaun bank', 'route' => 'kewangan.bank.index'],
|
|
['label' => 'Export finance list', 'route' => 'kewangan.bank.export'],
|
|
],
|
|
));
|
|
}
|
|
|
|
public function ppm(Request $request, PpmScopeService $scopeService): View
|
|
{
|
|
$pusatIds = $scopeService->assignedPusatIds($request->user());
|
|
|
|
return view('dashboards.index', $this->payload(
|
|
'Dashboard PPM',
|
|
'Pengurusan Pusat Mengundi sendiri',
|
|
'Paparan asas untuk semakan permohonan, tugasan saluran, wakil agensi, dan kehadiran.',
|
|
[
|
|
['label' => 'Pusat jagaan', 'value' => (string) $pusatIds->count(), 'icon' => 'bi-geo-alt', 'tone' => 'primary'],
|
|
['label' => 'Permohonan pending', 'value' => (string) Application::query()->whereIn('pusat_mengundi_id', $pusatIds)->whereIn('status', ['submitted', 'under_ppm_review'])->count(), 'icon' => 'bi-inbox', 'tone' => 'warning'],
|
|
['label' => 'Staf aktif', 'value' => (string) StaffAssignment::query()->whereIn('pusat_mengundi_id', $pusatIds)->where('status', 'active')->count(), 'icon' => 'bi-person-check', 'tone' => 'success'],
|
|
['label' => 'Kehadiran hadir', 'value' => (string) Attendance::query()->whereIn('pusat_mengundi_id', $pusatIds)->where('status', 'present')->count(), 'icon' => 'bi-check2-circle', 'tone' => 'info'],
|
|
],
|
|
[
|
|
['label' => 'Semak permohonan', 'route' => 'ppm.applications.index'],
|
|
['label' => 'Rekod kehadiran', 'route' => 'ppm.attendance.index'],
|
|
'Assign KTM/KP/KPDP',
|
|
],
|
|
));
|
|
}
|
|
|
|
public function ktm(Request $request, KtmScopeService $scopeService, KtmVacancyService $vacancyService): View
|
|
{
|
|
$assignments = $scopeService->assignmentsFor($request->user());
|
|
$assignmentIds = $assignments->pluck('id');
|
|
$kpVacancy = $assignments->sum(fn (StaffAssignment $assignment): int => $vacancyService->remainingForAssignment($assignment, 'KP'));
|
|
|
|
return view('dashboards.index', $this->payload(
|
|
'Dashboard KTM',
|
|
'Pengurusan pasukan KP sendiri',
|
|
'Paparan asas untuk saluran ditugaskan, kekosongan KP, dan pendaftaran KP.',
|
|
[
|
|
['label' => 'Saluran ditugaskan', 'value' => (string) $assignments->count(), 'icon' => 'bi-signpost', 'tone' => 'primary'],
|
|
['label' => 'KP aktif', 'value' => (string) StaffAssignment::query()->whereIn('reports_to_assignment_id', $assignmentIds)->where('status', 'active')->count(), 'icon' => 'bi-people', 'tone' => 'success'],
|
|
['label' => 'Kekosongan KP', 'value' => (string) $kpVacancy, 'icon' => 'bi-person-plus', 'tone' => 'warning'],
|
|
],
|
|
[
|
|
['label' => 'Senarai KP', 'route' => 'ktm.applications.index'],
|
|
['label' => 'Daftar KP', 'route' => 'ktm.applications.create'],
|
|
'Semak permohonan KP',
|
|
],
|
|
));
|
|
}
|
|
|
|
public function pemohon(): View
|
|
{
|
|
return view('dashboards.index', $this->payload(
|
|
'Dashboard Pemohon',
|
|
'Status permohonan',
|
|
'Akaun Pemohon akan digunakan jika portal status kendiri diaktifkan dalam fasa akan datang.',
|
|
[
|
|
['label' => 'Permohonan', 'value' => '0', 'icon' => 'bi-file-text', 'tone' => 'secondary'],
|
|
['label' => 'Status', 'value' => 'Belum aktif', 'icon' => 'bi-info-circle', 'tone' => 'info'],
|
|
],
|
|
));
|
|
}
|
|
|
|
/**
|
|
* @param array<int, array{label: string, value: string, icon: string, tone: string}> $cards
|
|
* @param array<int, string|array{label: string, route: string}> $actions
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function payload(string $title, string $eyebrow, string $description, array $cards, array $actions = []): array
|
|
{
|
|
return compact('title', 'eyebrow', 'description', 'cards', 'actions');
|
|
}
|
|
}
|