448 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
			
		
		
	
	
			448 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
<?php
 | 
						|
 | 
						|
namespace App\Helpers;
 | 
						|
 | 
						|
use App\Models\PerizinanStatus;
 | 
						|
use App\Models\FastestPermohonan;
 | 
						|
use App\Models\TerakhirTerbit;
 | 
						|
use Carbon\Carbon;
 | 
						|
 | 
						|
class DashboardHelper
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * Data master untuk setiap jenis izin - fallback untuk data yang belum ada di API
 | 
						|
     */
 | 
						|
    public static function getFallbackDataByType(string $type): array
 | 
						|
    {
 | 
						|
        $data = [
 | 
						|
            'pertek' => [
 | 
						|
                ['id' => 'ditolak', 'label' => 'Izin Ditolak', 'value' => 8, 'color' => 'danger'],
 | 
						|
                ['id' => 'selesai', 'label' => 'Izin Selesai', 'value' => 45, 'color' => 'success'],
 | 
						|
                ['id' => 'proses', 'label' => 'Dalam Proses', 'value' => 12, 'color' => 'info'],
 | 
						|
            ],
 | 
						|
            'amdal' => [
 | 
						|
                ['id' => 'ditolak', 'label' => 'Izin Ditolak', 'value' => 3, 'color' => 'danger'],
 | 
						|
                ['id' => 'selesai', 'label' => 'Izin Selesai', 'value' => 15, 'color' => 'success'],
 | 
						|
                ['id' => 'proses', 'label' => 'Dalam Proses', 'value' => 9, 'color' => 'info'],
 | 
						|
            ],
 | 
						|
            'rintek' => [
 | 
						|
                ['id' => 'ditolak', 'label' => 'Izin Ditolak', 'value' => 5, 'color' => 'danger'],
 | 
						|
                ['id' => 'selesai', 'label' => 'Izin Selesai', 'value' => 28, 'color' => 'success'],
 | 
						|
                ['id' => 'proses', 'label' => 'Dalam Proses', 'value' => 7, 'color' => 'info'],
 | 
						|
            ],
 | 
						|
            'izin_angkut' => [
 | 
						|
                ['id' => 'ditolak', 'label' => 'Izin Ditolak', 'value' => 12, 'color' => 'danger'],
 | 
						|
                ['id' => 'selesai', 'label' => 'Izin Selesai', 'value' => 67, 'color' => 'success'],
 | 
						|
                ['id' => 'proses', 'label' => 'Dalam Proses', 'value' => 18, 'color' => 'info'],
 | 
						|
            ],
 | 
						|
            'uji_emisi' => [
 | 
						|
                ['id' => 'ditolak', 'label' => 'Izin Ditolak', 'value' => 6, 'color' => 'danger'],
 | 
						|
                ['id' => 'selesai', 'label' => 'Izin Selesai', 'value' => 89, 'color' => 'success'],
 | 
						|
                ['id' => 'proses', 'label' => 'Dalam Proses', 'value' => 23, 'color' => 'info'],
 | 
						|
            ],
 | 
						|
        ];
 | 
						|
 | 
						|
        return $data[$type] ?? [];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get status data by type from database or fallback
 | 
						|
     */
 | 
						|
    public static function getStatusDataByType(string $type): array
 | 
						|
    {
 | 
						|
        // Cek apakah ada data di database untuk hari ini
 | 
						|
        $dbData = PerizinanStatus::getLatestByKategori($type);
 | 
						|
 | 
						|
        if ($dbData->isNotEmpty()) {
 | 
						|
            $data = [];
 | 
						|
            $colorMap = [
 | 
						|
                'ditolak' => 'danger',
 | 
						|
                'selesai' => 'success',
 | 
						|
                'proses' => 'info',
 | 
						|
                'total' => 'primary'
 | 
						|
            ];
 | 
						|
 | 
						|
            foreach ($dbData as $item) {
 | 
						|
                $data[] = [
 | 
						|
                    'id' => $item->StatusID,
 | 
						|
                    'label' => $item->Label,
 | 
						|
                    'value' => $item->Value,
 | 
						|
                    'color' => $colorMap[$item->StatusID] ?? 'secondary'
 | 
						|
                ];
 | 
						|
            }
 | 
						|
 | 
						|
            return $data;
 | 
						|
        }
 | 
						|
 | 
						|
        // Fallback ke data statis jika tidak ada data di database
 | 
						|
        return self::getFallbackDataByType($type);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Menambahkan total ke data statuses
 | 
						|
     */
 | 
						|
    public static function addTotalToStatuses(array $statuses): array
 | 
						|
    {
 | 
						|
        // Cek apakah sudah ada total di data
 | 
						|
        $hasTotal = collect($statuses)->contains('id', 'total');
 | 
						|
 | 
						|
        if (!$hasTotal) {
 | 
						|
            $total = array_sum(array_column($statuses, 'value'));
 | 
						|
            $statuses[] = [
 | 
						|
                'id' => 'total',
 | 
						|
                'label' => 'Total Pengajuan',
 | 
						|
                'value' => $total,
 | 
						|
                'color' => 'primary'
 | 
						|
            ];
 | 
						|
        }
 | 
						|
 | 
						|
        return $statuses;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Mendapatkan label untuk tipe izin
 | 
						|
     */
 | 
						|
    public static function getTypeLabel(string $type): string
 | 
						|
    {
 | 
						|
        $labels = [
 | 
						|
            'pertek' => 'PERTEK',
 | 
						|
            'rintek' => 'RINTEK',
 | 
						|
            'amdal' => 'AMDAL',
 | 
						|
            'izin_angkut' => 'IZIN ANGKUT & OLAH',
 | 
						|
            'uji_emisi' => 'IZIN TEMPAT UJI EMISI',
 | 
						|
        ];
 | 
						|
 | 
						|
        return $labels[$type] ?? strtoupper($type);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Mendapatkan icon untuk status
 | 
						|
     */
 | 
						|
    public static function getStatusIcon(string $statusId): string
 | 
						|
    {
 | 
						|
        $icons = [
 | 
						|
            'ditolak' => 'circle-x',
 | 
						|
            'selesai' => 'circle-check',
 | 
						|
            'proses' => 'refresh-cw',
 | 
						|
            'total' => 'equal',
 | 
						|
        ];
 | 
						|
 | 
						|
        return $icons[$statusId] ?? 'circle';
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Mendapatkan background color untuk card
 | 
						|
     */
 | 
						|
    public static function getCardBackground(string $statusId): string
 | 
						|
    {
 | 
						|
        $backgrounds = [
 | 
						|
            'ditolak' => 'bg-gradient-start-4',
 | 
						|
            'selesai' => 'bg-gradient-start-2',
 | 
						|
            'proses' => 'bg-gradient-start-3',
 | 
						|
            'total' => 'bg-gradient-start-1',
 | 
						|
        ];
 | 
						|
 | 
						|
        return $backgrounds[$statusId] ?? 'bg-gradient-start-1';
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Mendapatkan warna lingkaran icon
 | 
						|
     */
 | 
						|
    public static function getIconCircleColor(string $statusId): string
 | 
						|
    {
 | 
						|
        $colors = [
 | 
						|
            'ditolak' => 'bg-red',
 | 
						|
            'selesai' => 'bg-green',
 | 
						|
            'proses' => 'bg-info',
 | 
						|
            'total' => 'bg-yellow',
 | 
						|
        ];
 | 
						|
 | 
						|
        return $colors[$statusId] ?? 'bg-primary';
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Mendapatkan semua tipe izin yang tersedia
 | 
						|
     */
 | 
						|
    public static function getAllTypes(): array
 | 
						|
    {
 | 
						|
        return ['pertek', 'rintek', 'amdal', 'izin_angkut', 'uji_emisi'];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Mendapatkan statistik lengkap untuk semua tipe
 | 
						|
     */
 | 
						|
    public static function getAllStatistics(): array
 | 
						|
    {
 | 
						|
        $types = self::getAllTypes();
 | 
						|
        $allData = [];
 | 
						|
 | 
						|
        foreach ($types as $type) {
 | 
						|
            $statuses = self::getStatusDataByType($type);
 | 
						|
            $statuses = self::addTotalToStatuses($statuses);
 | 
						|
 | 
						|
            $allData[$type] = [
 | 
						|
                'type' => $type,
 | 
						|
                'label' => self::getTypeLabel($type),
 | 
						|
                'data' => $statuses
 | 
						|
            ];
 | 
						|
        }
 | 
						|
 | 
						|
        return $allData;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Format percentage dari total
 | 
						|
     */
 | 
						|
    public static function calculatePercentage(int $value, int $total): float
 | 
						|
    {
 | 
						|
        return $total > 0 ? round(($value / $total) * 100, 2) : 0;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Mendapatkan trend indicator (simulasi)
 | 
						|
     */
 | 
						|
    public static function getTrendIndicator(string $type, string $statusId): array
 | 
						|
    {
 | 
						|
        // Simulasi data trend (bisa diganti dengan data real dari database)
 | 
						|
        $trends = [
 | 
						|
            'pertek' => ['ditolak' => -2.5, 'selesai' => 5.3, 'proses' => 1.2],
 | 
						|
            'rintek' => ['ditolak' => -1.8, 'selesai' => 3.7, 'proses' => 0.5],
 | 
						|
            'amdal' => ['ditolak' => -0.9, 'selesai' => 2.1, 'proses' => -0.3],
 | 
						|
            'izin_angkut' => ['ditolak' => -3.2, 'selesai' => 7.8, 'proses' => 2.1],
 | 
						|
            'uji_emisi' => ['ditolak' => -1.5, 'selesai' => 12.4, 'proses' => 4.2],
 | 
						|
        ];
 | 
						|
 | 
						|
        $value = $trends[$type][$statusId] ?? 0;
 | 
						|
 | 
						|
        return [
 | 
						|
            'value' => $value,
 | 
						|
            'direction' => $value > 0 ? 'up' : ($value < 0 ? 'down' : 'same'),
 | 
						|
            'color' => $value > 0 ? 'success' : ($value < 0 ? 'danger' : 'secondary')
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Mendapatkan badge color untuk tipe izin
 | 
						|
     */
 | 
						|
    public static function getBadgeColor(string $type): string
 | 
						|
    {
 | 
						|
        $colors = [
 | 
						|
            'pertek' => 'primary',
 | 
						|
            'rintek' => 'success',
 | 
						|
            'amdal' => 'info',
 | 
						|
            'izin_angkut' => 'warning',
 | 
						|
            'uji_emisi' => 'secondary',
 | 
						|
        ];
 | 
						|
 | 
						|
        return $colors[$type] ?? 'primary';
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Mendapatkan data untuk chart
 | 
						|
     */
 | 
						|
    public static function getChartData(string $type): array
 | 
						|
    {
 | 
						|
        $statuses = self::getStatusDataByType($type);
 | 
						|
 | 
						|
        return [
 | 
						|
            'labels' => array_column($statuses, 'label'),
 | 
						|
            'values' => array_column($statuses, 'value'),
 | 
						|
            'colors' => array_map(function($status) {
 | 
						|
                return self::getChartColor($status['id']);
 | 
						|
            }, $statuses)
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Mendapatkan warna untuk chart
 | 
						|
     */
 | 
						|
    private static function getChartColor(string $statusId): string
 | 
						|
    {
 | 
						|
        $colors = [
 | 
						|
            'ditolak' => '#ef4444',
 | 
						|
            'selesai' => '#22c55e',
 | 
						|
            'proses' => '#3b82f6',
 | 
						|
            'total' => '#f59e0b',
 | 
						|
        ];
 | 
						|
 | 
						|
        return $colors[$statusId] ?? '#6b7280';
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get fastest permohonan data from database or fallback
 | 
						|
     */
 | 
						|
    public static function getFastestPermohonanByType(string $type): array
 | 
						|
    {
 | 
						|
        // Try to get data from database first
 | 
						|
        $dbData = FastestPermohonan::getLatestByKategori($type);
 | 
						|
 | 
						|
        if ($dbData->isNotEmpty()) {
 | 
						|
            $data = [];
 | 
						|
            $index = 1;
 | 
						|
            foreach ($dbData as $item) {
 | 
						|
                $data[] = [
 | 
						|
                    'Nama' => $item->Nama,
 | 
						|
                    'Total' => $item->Total,
 | 
						|
                    'DurasiPemohon' => $item->DurasiPemohon,
 | 
						|
                    'DurasiPetugas' => $item->DurasiPetugas,
 | 
						|
                    'rank_order' => $index++  // Generate rank_order dinamis untuk display
 | 
						|
                ];
 | 
						|
            }
 | 
						|
            return $data;
 | 
						|
        }
 | 
						|
 | 
						|
        // Fallback to static data if no database data available
 | 
						|
        return self::getFallbackFastestData($type);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Fallback static data for fastest permohonan
 | 
						|
     */
 | 
						|
    private static function getFallbackFastestData(string $type): array
 | 
						|
    {
 | 
						|
        $fallbackData = [
 | 
						|
            'pertek' => [
 | 
						|
                ['Nama' => 'Izin Pengelolaan Limbah B3', 'Total' => 45, 'DurasiPemohon' => '2 Hari 3 Jam', 'DurasiPetugas' => '5 Hari 2 Jam', 'rank_order' => 1],
 | 
						|
                ['Nama' => 'Izin Emisi Kendaraan', 'Total' => 67, 'DurasiPemohon' => '3 Hari 1 Jam', 'DurasiPetugas' => '7 Hari 4 Jam', 'rank_order' => 2],
 | 
						|
                ['Nama' => 'SPPL Industri', 'Total' => 23, 'DurasiPemohon' => '4 Hari 2 Jam', 'DurasiPetugas' => '8 Hari 1 Jam', 'rank_order' => 3],
 | 
						|
                ['Nama' => 'Izin Penyimpanan B3', 'Total' => 34, 'DurasiPemohon' => '5 Hari', 'DurasiPetugas' => '9 Hari 3 Jam', 'rank_order' => 4],
 | 
						|
                ['Nama' => 'Izin Pengolahan Limbah', 'Total' => 19, 'DurasiPemohon' => '6 Hari 4 Jam', 'DurasiPetugas' => '10 Hari 2 Jam', 'rank_order' => 5],
 | 
						|
            ],
 | 
						|
            'amdal' => [
 | 
						|
                ['Nama' => 'AMDAL Bangunan Tinggi', 'Total' => 12, 'DurasiPemohon' => '15 Hari', 'DurasiPetugas' => '30 Hari', 'rank_order' => 1],
 | 
						|
                ['Nama' => 'AMDAL Infrastruktur', 'Total' => 8, 'DurasiPemohon' => '18 Hari', 'DurasiPetugas' => '35 Hari', 'rank_order' => 2],
 | 
						|
                ['Nama' => 'AMDAL Industri', 'Total' => 15, 'DurasiPemohon' => '20 Hari', 'DurasiPetugas' => '40 Hari', 'rank_order' => 3],
 | 
						|
                ['Nama' => 'AMDAL Perumahan', 'Total' => 25, 'DurasiPemohon' => '22 Hari', 'DurasiPetugas' => '42 Hari', 'rank_order' => 4],
 | 
						|
                ['Nama' => 'AMDAL Komersial', 'Total' => 18, 'DurasiPemohon' => '25 Hari', 'DurasiPetugas' => '45 Hari', 'rank_order' => 5],
 | 
						|
            ]
 | 
						|
        ];
 | 
						|
 | 
						|
        return $fallbackData[$type] ?? [];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get fastest data for all supported types
 | 
						|
     */
 | 
						|
    public static function getAllFastestData(): array
 | 
						|
    {
 | 
						|
        $supportedTypes = ['pertek', 'amdal']; // Only types with API endpoints
 | 
						|
        $allData = [];
 | 
						|
 | 
						|
        foreach ($supportedTypes as $type) {
 | 
						|
            $allData[$type] = [
 | 
						|
                'type' => $type,
 | 
						|
                'label' => self::getTypeLabel($type),
 | 
						|
                'data' => self::getFastestPermohonanByType($type)
 | 
						|
            ];
 | 
						|
        }
 | 
						|
 | 
						|
        return $allData;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Format duration text for display
 | 
						|
     */
 | 
						|
    public static function formatDuration(string $duration): string
 | 
						|
    {
 | 
						|
        // API returns format like "03 Jam 54 Menit 13 Detik" or "2 Hari 01 Jam 02 Menit 04 Detik"
 | 
						|
        return $duration;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get rank badge color based on ranking
 | 
						|
     */
 | 
						|
    public static function getRankBadgeColor(int $rank): string
 | 
						|
    {
 | 
						|
        $colors = [
 | 
						|
            1 => 'success',
 | 
						|
            2 => 'info',
 | 
						|
            3 => 'warning',
 | 
						|
            4 => 'secondary',
 | 
						|
            5 => 'dark'
 | 
						|
        ];
 | 
						|
 | 
						|
        return $colors[$rank] ?? 'secondary';
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get terakhir terbit data from database or fallback
 | 
						|
     */
 | 
						|
    public static function getTerakhirTerbitByType(string $type): array
 | 
						|
    {
 | 
						|
        // Try to get data from database first
 | 
						|
        $dbData = TerakhirTerbit::getLatestByKategori($type);
 | 
						|
 | 
						|
        if ($dbData->isNotEmpty()) {
 | 
						|
            $data = [];
 | 
						|
            $index = 1;
 | 
						|
            foreach ($dbData as $item) {
 | 
						|
                $data[] = [
 | 
						|
                    'NamaIzin' => $item->NamaIzin,
 | 
						|
                    'Pemohon' => $item->Pemohon,
 | 
						|
                    'TanggalTerbit' => $item->TanggalTerbit,
 | 
						|
                    'rank_order' => $index++  // Generate rank_order dinamis untuk display
 | 
						|
                ];
 | 
						|
            }
 | 
						|
            return $data;
 | 
						|
        }
 | 
						|
 | 
						|
        // Fallback to static data if no database data available
 | 
						|
        return self::getFallbackTerakhirTerbitData($type);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Fallback static data for terakhir terbit
 | 
						|
     */
 | 
						|
    private static function getFallbackTerakhirTerbitData(string $type): array
 | 
						|
    {
 | 
						|
        $fallbackData = [
 | 
						|
            'pertek' => [
 | 
						|
                ['NamaIzin' => 'SERTIFIKAT LAIK OPERASI - PEMENUHAN BAKU MUTU EMISI', 'Pemohon' => 'PT. MAJU BERSAMA', 'TanggalTerbit' => Carbon::parse('2025-07-15'), 'rank_order' => 1],
 | 
						|
                ['NamaIzin' => 'PERSETUJUAN TEKNIS - PEMENUHAN BAKU MUTU AIR LIMBAH', 'Pemohon' => 'CV. KARYA MANDIRI', 'TanggalTerbit' => Carbon::parse('2025-07-14'), 'rank_order' => 2],
 | 
						|
                ['NamaIzin' => 'SERTIFIKAT LAIK OPERASI - PEMENUHAN BAKU MUTU AIR LIMBAH', 'Pemohon' => 'PT. INDUSTRI SEJAHTERA', 'TanggalTerbit' => Carbon::parse('2025-07-13'), 'rank_order' => 3],
 | 
						|
                ['NamaIzin' => 'PERSETUJUAN TEKNIS - PEMENUHAN BAKU MUTU AIR LIMBAH', 'Pemohon' => 'PT. TEKNOLOGI MODERN', 'TanggalTerbit' => Carbon::parse('2025-07-12'), 'rank_order' => 4],
 | 
						|
                ['NamaIzin' => 'SERTIFIKAT LAIK OPERASI - PEMENUHAN BAKU MUTU EMISI', 'Pemohon' => 'CV. BERKAH JAYA', 'TanggalTerbit' => Carbon::parse('2025-07-11'), 'rank_order' => 5],
 | 
						|
            ],
 | 
						|
            'amdal' => [
 | 
						|
                ['NamaIzin' => 'AMDAL BANGUNAN TINGGI', 'Pemohon' => 'PT. KONSTRUKSI PRIMA', 'TanggalTerbit' => Carbon::parse('2025-07-10'), 'rank_order' => 1],
 | 
						|
                ['NamaIzin' => 'AMDAL INFRASTRUKTUR', 'Pemohon' => 'CV. INFRATEK', 'TanggalTerbit' => Carbon::parse('2025-07-09'), 'rank_order' => 2],
 | 
						|
                ['NamaIzin' => 'AMDAL INDUSTRI', 'Pemohon' => 'PT. INDUSTRI MODERN', 'TanggalTerbit' => Carbon::parse('2025-07-08'), 'rank_order' => 3],
 | 
						|
                ['NamaIzin' => 'AMDAL PERUMAHAN', 'Pemohon' => 'PT. PROPERTI SEJAHTERA', 'TanggalTerbit' => Carbon::parse('2025-07-07'), 'rank_order' => 4],
 | 
						|
                ['NamaIzin' => 'AMDAL KOMERSIAL', 'Pemohon' => 'CV. KOMERSIAL JAYA', 'TanggalTerbit' => Carbon::parse('2025-07-06'), 'rank_order' => 5],
 | 
						|
            ]
 | 
						|
        ];
 | 
						|
 | 
						|
        return $fallbackData[$type] ?? [];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get terakhir terbit data for all supported types
 | 
						|
     */
 | 
						|
    public static function getAllTerakhirTerbitData(): array
 | 
						|
    {
 | 
						|
        $supportedTypes = ['pertek', 'amdal']; // Only types with API endpoints
 | 
						|
        $allData = [];
 | 
						|
 | 
						|
        foreach ($supportedTypes as $type) {
 | 
						|
            $allData[$type] = [
 | 
						|
                'type' => $type,
 | 
						|
                'label' => self::getTypeLabel($type),
 | 
						|
                'data' => self::getTerakhirTerbitByType($type)
 | 
						|
            ];
 | 
						|
        }
 | 
						|
 | 
						|
        return $allData;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Format tanggal terbit for display
 | 
						|
     */
 | 
						|
    public static function formatTanggalTerbit($tanggal): string
 | 
						|
    {
 | 
						|
        if ($tanggal instanceof Carbon) {
 | 
						|
            return $tanggal->format('d M Y');
 | 
						|
        }
 | 
						|
        return Carbon::parse($tanggal)->format('d M Y');
 | 
						|
    }
 | 
						|
}
 |