Cat::count(), 'total_staff' => \App\Models\User::count(), 'sick_cats' => Cat::whereNotNull('riwayat_sakit_terakhir')->count(), 'total_mating' => Matting::where('status', 'proses')->count(), ]; // 2. Birth Watch: Persalinan 7 Hari ke Depan (Rumus: H+63) $upcomingBirths = Matting::with(['dam', 'sire', 'pic']) ->where('status', 'proses') ->whereNotNull('tanggal_kawin') ->whereBetween('tanggal_kawin', [ now()->subDays(70)->toDateString(), now()->subDays(56)->toDateString() ]) ->get() ->map(function ($mating) { $mating->edd = Carbon::parse($mating->tanggal_kawin)->addDays(63); $mating->days_to_go = (int) now()->diffInDays($mating->edd, false); return $mating; }) ->filter(fn($m) => $m->days_to_go >= -2 && $m->days_to_go <= 7) ->sortBy('days_to_go'); // 3. Medical Alerts $medicalAlerts = [ 'vaccine' => Cat::whereNotNull('jadwal_vaksin')->where('jadwal_vaksin', '<=', now()->addDays(3))->count(), 'flea' => Cat::whereNotNull('jadwal_obat_kutu')->where('jadwal_obat_kutu', '<=', now()->addDays(3))->count(), 'deworming' => Cat::whereNotNull('jadwal_obat_cacing')->where('jadwal_obat_cacing', '<=', now()->addDays(3))->count(), 'grooming' => Cat::whereNotNull('jadwal_grooming')->where('jadwal_grooming', '<=', now()->addDays(3))->count(), ]; // 4. Inventory Critical (Stok < 5) $lowStock = [ 'medicines' => Medicine::where('qty', '<', 5)->get(['nama_obat as name', 'qty', 'unit']), 'foods' => Food::where('qty', '<', 5)->get(['nama_makanan as name', 'qty', 'unit']), 'supplies' => Supply::where('qty', '<', 5)->get(['nama_perlengkapan as name', 'qty', 'unit']), ]; $totalLowStock = collect($lowStock)->flatten(1)->count(); // 5. Chart Data: Sebaran Ras (Persian, British Shorthair, dll) $chartData = Cat::select('ras', DB::raw('count(*) as total'))->groupBy('ras')->get(); // 6. Weight Trends: Rata-rata Berat (6 Bulan Terakhir) $weightTrends = DB::table('weight_histories') ->select( DB::raw('AVG(berat) as avg_weight'), DB::raw("DATE_FORMAT(tanggal_timbang, '%M') as month"), DB::raw('MONTH(tanggal_timbang) as month_num') ) ->where('tanggal_timbang', '>=', now()->subMonths(6)) ->groupBy('month', 'month_num') ->orderBy('month_num') ->get(); if ($weightTrends->isEmpty()) { $weightTrends = collect([(object)['month' => now()->format('F'), 'avg_weight' => 0]]); } // 7. Recent Activity $recentTreatments = Treatment::with(['cat', 'pic'])->latest()->take(5)->get(); return view('pages.dashboard.index', compact( 'stats', 'upcomingBirths', 'medicalAlerts', 'lowStock', 'totalLowStock', 'chartData', 'weightTrends', 'recentTreatments' )); } }