import { useState } from 'react'
import { Link } from 'react-router'
import { paths } from '@/components/layout/nav-items'
import { PageError } from '@/components/page'
import { Skeleton } from '@/components/skeleton'
import { Button } from '@/components/ui/button'
import { WeekSummary } from '@/features/ledger/week-summary'
import { PeriodHeading } from '@/features/planning/plan-read'
import { dailyAllowance } from '@/lib/dashboard'
import { formatDayMonth, formatMoney, toIsoDate } from '@/lib/format'
import { weekIndexFor } from '@/lib/ledger'
import { periodPath } from '@/lib/period-select'
import { useBudget, useStats, useSummary } from '@/lib/periods'
import { t } from '@/lib/strings'
import { cn } from '@/lib/utils'
import type { GroupBudget } from '@/types/GroupBudget'
import type { Period } from '@/types/Period'
import type { PeriodSummary } from '@/types/PeriodSummary'
const s = t.dashboard
/** Özet kartları: gelir, sabit gider, toplam birikim, devreden borç, anlık durum, gruplar */
export function Overview({ period, writable }: { period: Period; writable: boolean }) {
const summary = useSummary(period.id)
const budget = useBudget(period.id)
const stats = useStats()
const [today] = useState(() => toIsoDate(new Date()))
const failed = [summary, budget].find((q) => q.isError)
if (failed?.error) return
if (!summary.data || !budget.data) return
const sum = summary.data
return (
{/* Borç kartı yalnızca varsa: 3 kartta mobilde sonuncusu tam genişlik, masaüstünde 3 sütun */}
0
? 'lg:grid-cols-4'
: 'lg:grid-cols-3 [&>*:last-child]:col-span-2 lg:[&>*:last-child]:col-span-1',
)}
>
{sum.carryover_debt > 0 && (
)}
{/* Anlık durum DOM'da önce (ekran okuyucu ve mobilde ilk), masaüstünde sağ sütunda */}
)
}
function Tile({
emoji,
label,
amount,
hint,
tone,
}: {
emoji: string
label: string
/** `undefined` → yükleniyor */
amount: number | undefined
hint?: string
tone?: string
}) {
return (
{emoji} {label}
{amount === undefined ? : formatMoney(amount)}
{hint && {hint}}
)
}
/** En belirgin kart: kalan harcanabilir + günlük öneri */
function StatusCard({
period,
summary,
today,
writable,
}: {
period: Period
summary: PeriodSummary
today: string
writable: boolean
}) {
const over = summary.remaining < 0
const { daysLeft, perDay } = dailyAllowance(summary.remaining, period, today)
return (
📍 {s.statusTitle}
{over ? s.overspent : s.remaining}
{formatMoney(over ? -summary.remaining : summary.remaining)}
{s.statusDetail(formatMoney(summary.spendable), formatMoney(summary.spent_total))}
{writable &&
(daysLeft === 0 ? (
) : (
{perDay !== null ? s.perDay(daysLeft, formatMoney(perDay)) : s.daysLeft(daysLeft)}
))}
)
}
/** 4 grup: planlanan / gerçekleşen; Haftalık (bugünün haftası) ↔ Aylık (tüm dönem) */
function GroupsCard({
period,
budget,
summary,
today,
writable,
}: {
period: Period
budget: GroupBudget[]
summary: PeriodSummary
today: string
writable: boolean
}) {
const [mode, setMode] = useState<'week' | 'month'>('week')
const index = weekIndexFor(period.weeks, today)
const week = period.weeks[index - 1]
const range = (a: string, b: string) => `${formatDayMonth(a)}–${formatDayMonth(b)}`
return (
🎯 {s.groupsTitle}
{(['week', 'month'] as const).map((m) => (
))}
{mode === 'week' && week
? s.weekLabel(index, range(week.start_date, week.last_date))
: s.monthLabel(range(period.start_date, period.last_date))}
{summary.budget_total === 0 ? (
) : (
)}
{writable && summary.spent_total === 0 && summary.budget_total > 0 && (
{s.noEntries}
)}
)
}
function Empty({ text, to, action }: { text: string; to: string; action: string }) {
return (
)
}
/** Yükleniyor: kartların şeklinde yer tutucular */
export function DashboardSkeleton() {
return (
{[0, 1, 2, 3].map((i) => (
))}
)
}