import { Head, usePage } from '@inertiajs/react';
import {
Clock,
Moon,
Sunrise,
Sun,
TrendingDown,
TrendingUp,
UserCheck,
} from 'lucide-react';
import { useEffect, useMemo, useState } from 'react';
import { Pie, PieChart, Cell, ResponsiveContainer, Tooltip } from 'recharts';
import { AttendanceCard } from '@/components/card/attendance-card';
import { StatCard } from '@/components/card/stat-card';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { useCan } from '@/hooks/use-can';
import { formatRupiah } from '@/lib/rupiah';
type TodayAttendance = {
id: number;
attendance_date: string;
check_in_at: string | null;
check_out_at: string | null;
check_in_photo: string | null;
check_out_photo: string | null;
check_in_latitude: number;
check_in_longitude: number;
check_out_latitude: number | null;
check_out_longitude: number | null;
work_duration_minutes: number | null;
} | null;
type DashboardProps = {
attendance: {
total_employees: number;
percentage: number;
present: number;
absent: number;
on_leave: number;
};
revenueSummary: {
total_revenue: number;
total_discount: number;
total_marketplace_fees: number;
total_deduction: number;
total_orders: number;
avg_order: number;
};
expenseSummary: {
total: number;
purchase_total: number;
expense_total: number;
advance_total: number;
};
orderStats: {
by_channel: Array<{
channel: string;
label: string;
count: number;
total: number;
}>;
by_payment_type: Array<{
payment_type: string;
label: string;
count: number;
total: number;
}>;
by_marketing: Array<{
name: string;
count: number;
total: number;
}>;
by_status: Array<{
status: string;
label: string;
count: number;
}>;
};
todayAttendance: TodayAttendance;
isOnLeave: boolean;
canCheckIn: boolean;
};
const CHART_COLORS = ['#60a5fa', '#f97316', '#22c55e', '#a855f7', '#ef4444'];
type CustomTooltipProps = {
active?: boolean;
payload?: Array<{
name: string;
value: number;
payload: {
label?: string;
name?: string;
count: number;
};
}>;
};
function ChartTooltip({ active, payload }: CustomTooltipProps) {
if (!active || !payload?.length) {
return null;
}
const data = payload[0].payload;
return (
{data.label ?? data.name ?? ''}
{data.count.toLocaleString('id-ID')}
);
}
export default function Dashboard({
attendance: attendanceStats,
revenueSummary,
expenseSummary,
orderStats,
todayAttendance,
isOnLeave,
canCheckIn,
}: DashboardProps) {
const { can } = useCan();
const { auth } = usePage().props as { auth: { user?: { username?: string } } };
const [currentTime, setCurrentTime] = useState(new Date());
useEffect(() => {
const timer = setInterval(() => setCurrentTime(new Date()), 1000);
return () => clearInterval(timer);
}, []);
const greeting = useMemo(() => {
const hour = currentTime.getHours();
if (hour >= 4 && hour < 11) {
return { text: 'Selamat Pagi', icon: Sunrise };
}
if (hour >= 11 && hour < 15) {
return { text: 'Selamat Siang', icon: Sun };
}
if (hour >= 15 && hour < 18) {
return { text: 'Selamat Sore', icon: Sun };
}
return { text: 'Selamat Malam', icon: Moon };
}, [currentTime]);
const timeStr = currentTime.toLocaleTimeString('id-ID', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
});
const dateStr = currentTime.toLocaleDateString('id-ID', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
});
const visibleStatsCount = useMemo(() => {
let count = 0;
if (can('dashboard.attendance')) {
count++;
}
if (can('dashboard.revenue')) {
count++;
}
if (can('dashboard.expense')) {
count++;
}
return count;
}, [can]);
const statsGridClass = useMemo(() => {
if (visibleStatsCount === 1) {
return 'grid gap-4 grid-cols-1 md:max-w-md';
}
if (visibleStatsCount === 2) {
return 'grid gap-4 grid-cols-1 md:grid-cols-2';
}
if (visibleStatsCount === 3) {
return 'grid gap-4 grid-cols-1 md:grid-cols-3';
}
return 'grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-4';
}, [visibleStatsCount]);
const visibleChartsCount = useMemo(() => {
let count = 0;
if (can('dashboard.orders_channel')) {
count++;
}
if (can('dashboard.orders_payment')) {
count++;
}
if (can('dashboard.orders_marketing')) {
count++;
}
if (can('dashboard.orders_status')) {
count++;
}
return count;
}, [can]);
const chartsGridClass = useMemo(() => {
if (visibleChartsCount === 1) {
return 'grid gap-4 grid-cols-1 md:max-w-xl';
}
if (visibleChartsCount === 2) {
return 'grid gap-4 grid-cols-1 md:grid-cols-2';
}
if (visibleChartsCount === 3) {
return 'grid gap-4 grid-cols-1 md:grid-cols-3';
}
return 'grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-4';
}, [visibleChartsCount]);
const GreetingIcon = greeting.icon;
return (
<>