import { useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import { ArrowRight, Sparkles } from "lucide-react";
import { useQuery } from "@tanstack/react-query";
import {
getInstallmentPlans,
getMonthlyDetail,
getPensionFundSummary,
getRecentTransactions,
} from "@/lib/api";
import { formatAmount } from "@/lib/format";
import {
MONTH_NAMES_ES_SHORT,
currentBudgetCycle,
formatShortDate,
} from "@/lib/dates";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Skeleton } from "@/components/ui/skeleton";
const CYCLE = currentBudgetCycle();
function StatCardShell({
to,
ariaLabel,
children,
}: {
to: string;
ariaLabel: string;
children: React.ReactNode;
}) {
return (
{children}
);
}
function StatValue({
value,
loading,
className,
}: {
value: string | null;
loading: boolean;
className?: string;
}) {
if (loading) return ;
return (
{value ?? "—"}
);
}
function GastoDelCicloCard() {
const q = useQuery({
queryKey: ["budget", "month", CYCLE.year, CYCLE.month],
queryFn: () =>
getMonthlyDetail(CYCLE.year, CYCLE.month).then((r) => r.data),
});
const spend = q.data
? q.data.actuals_by_source.reduce((sum, a) => sum + a.net, 0)
: null;
const balance = q.data?.net_balance ?? null;
return (
Gasto del ciclo
Ciclo al 18 {MONTH_NAMES_ES_SHORT[CYCLE.month].toLowerCase()}
{balance !== null && (
Balance proyectado:{" "}
= 0 ? "text-primary" : "text-destructive",
)}
>
{balance >= 0 ? "+" : "-"}
{formatAmount(balance, "CRC")}
)}
{q.isError && (
No se pudo cargar el ciclo.
)}
);
}
function ProximasCuotasCard() {
const q = useQuery({
queryKey: ["installment-plans"],
queryFn: () => getInstallmentPlans().then((r) => r.data),
});
const active = (q.data?.plans ?? []).filter(
(p) => !p.is_completed && p.next_cuota_date,
);
const inCycle = active.filter((p) => {
const d = new Date(p.next_cuota_date!);
return d >= CYCLE.start && d < CYCLE.end;
});
const cycleTotal = inCycle.reduce((s, p) => s + p.installment_amount, 0);
const upcoming = [...active]
.sort(
(a, b) =>
new Date(a.next_cuota_date!).getTime() -
new Date(b.next_cuota_date!).getTime(),
)
.slice(0, 3);
return (
Próximas cuotas
Tasa Cero en este ciclo
{upcoming.length > 0 && (
{upcoming.map((p) => (
-
{p.merchant}
{formatShortDate(p.next_cuota_date!)} ·{" "}
{formatAmount(p.installment_amount, p.currency)}
))}
)}
{q.data && (
Restante total:{" "}
{formatAmount(q.data.total_remaining, "CRC")}
)}
);
}
function PensionCard() {
const q = useQuery({
queryKey: ["pension-fund-summary"],
queryFn: () => getPensionFundSummary().then((r) => r.data),
});
const total = q.data
? q.data.reduce((s, f) => s + f.saldo_final, 0)
: null;
return (
Pensión
Saldo total de fondos
{q.data && q.data.length > 0 && (
{q.data.map((f) => (
-
{f.fund}
{formatAmount(f.saldo_final, "CRC")}
))}
)}
);
}
function AskAssistantCard() {
const [question, setQuestion] = useState("");
const navigate = useNavigate();
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const ask = question.trim();
navigate("/asistente", ask ? { state: { ask } } : undefined);
};
return (
);
}
function RecentTransactionsCard() {
const q = useQuery({
queryKey: ["transactions", "recent"],
queryFn: () => getRecentTransactions(5).then((r) => r.data),
});
return (
Últimas transacciones
Ver todo
{q.isPending ? (
{Array.from({ length: 5 }, (_, i) => (
))}
) : q.isError ? (
No se pudieron cargar las transacciones.
) : (
{(q.data ?? []).map((tx) => (
-
{tx.merchant}
{formatShortDate(tx.date)}
{tx.transaction_type === "COMPRA" ? "-" : "+"}
{formatAmount(tx.amount, tx.currency)}
))}
)}
);
}
export default function Inicio() {
return (
Inicio
Tu panorama financiero de hoy.
);
}