Compare commits

...

2 Commits

Author SHA1 Message Date
Jose Selesan
7c864053bb feat(belo): add daily and monthly variation quotes to analysis page 2026-06-04 11:10:37 -03:00
Jose Selesan
9ce5511ad8 feat(dashboard): add Dolar Oficial (BNA) card to panel grid 2026-06-04 11:05:38 -03:00
3 changed files with 73 additions and 8 deletions

View File

@@ -13,7 +13,7 @@ import {
YAxis,
} from "recharts";
import { DatePicker } from "@/components/ui/date-picker";
import { useDailyQuotes, useHistoricalMinMax } from "@/lib/queries";
import { useDailyQuotes, useHistoricalMinMax, useQuotes } from "@/lib/queries";
const priceFormatter = new Intl.NumberFormat("es-AR", {
minimumFractionDigits: 2,
@@ -47,12 +47,29 @@ export function BeloAnalysisPage() {
const { data: historical, isLoading: historicalLoading } =
useHistoricalMinMax("BELO");
const { data: quotes } = useQuotes();
const { data: daily, isLoading: dailyLoading } = useDailyQuotes(
"BELO",
startDateStr,
endDateStr,
);
const yesterday = subDays(today, 1);
const yesterdayStr = formatDate(yesterday);
const firstOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
const firstOfMonthStr = formatDate(firstOfMonth);
const { data: yesterdayQuote } = useDailyQuotes(
"BELO",
yesterdayStr,
yesterdayStr,
);
const { data: firstDayQuote } = useDailyQuotes(
"BELO",
firstOfMonthStr,
firstOfMonthStr,
);
const chartData = useMemo(() => {
if (!daily) return [];
return daily.map((d) => ({
@@ -86,6 +103,46 @@ export function BeloAnalysisPage() {
};
}, [chartData]);
const beloQuote = quotes?.find((q) => q.type === "BELO");
const currentBuy = beloQuote ? Number(beloQuote.buy) : 0;
const yesterdayBuy = yesterdayQuote?.[0]?.buy ?? null;
const prevDayDiff = yesterdayBuy !== null ? currentBuy - yesterdayBuy : null;
const prevDayPct =
prevDayDiff !== null && yesterdayBuy !== null && yesterdayBuy !== 0
? (prevDayDiff / yesterdayBuy) * 100
: null;
const firstMonthBuy = firstDayQuote?.[0]?.buy ?? null;
const monthDiff = firstMonthBuy !== null ? currentBuy - firstMonthBuy : null;
const monthPct =
monthDiff !== null && firstMonthBuy !== null && firstMonthBuy !== 0
? (monthDiff / firstMonthBuy) * 100
: null;
function VariationValue({
value,
pct,
}: {
value: number | null;
pct: number | null;
}) {
if (value === null || pct === null)
return <p className="text-sm text-muted-foreground">Sin datos</p>;
const isPositive = value >= 0;
const color = isPositive ? "text-emerald-500" : "text-red-500";
const sign = isPositive ? "+" : "";
return (
<p className={`text-lg font-bold tabular-nums ${color}`}>
{sign}${priceFormatter.format(Math.abs(value))}{" "}
<span className="text-sm font-normal">
({sign}
{pct.toFixed(2)}%)
</span>
</p>
);
}
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
@@ -101,7 +158,7 @@ export function BeloAnalysisPage() {
</div>
</div>
<div className="grid gap-4 md:grid-cols-2">
<div className="grid gap-4 md:grid-cols-4">
<div className="rounded-lg border p-4">
<p className="text-sm text-muted-foreground mb-2">
Mínimo histórico (compra)
@@ -140,6 +197,16 @@ export function BeloAnalysisPage() {
</>
)}
</div>
<div className="rounded-lg border p-4">
<p className="text-sm text-muted-foreground mb-2">Vs. día anterior</p>
<VariationValue value={prevDayDiff} pct={prevDayPct} />
</div>
<div className="rounded-lg border p-4">
<p className="text-sm text-muted-foreground mb-2">
Vs. primer día del mes
</p>
<VariationValue value={monthDiff} pct={monthPct} />
</div>
</div>
<div className="rounded-lg border p-4">

View File

@@ -127,6 +127,7 @@ export function DashboardPage() {
const belo = quotes?.find((q) => q.type === "BELO");
const blue = quotes?.find((q) => q.type === "BLUE");
const bna = quotes?.find((q) => q.type === "BNA");
const now = new Date();
const { data: monthlyExpenses } = useMonthlyPayedTotal(
@@ -156,7 +157,7 @@ export function DashboardPage() {
Actualizar
</button>
</div>
<div className="grid gap-4 md:grid-cols-4">
<div className="grid gap-4 md:grid-cols-4 lg:grid-cols-5">
<div className="rounded-lg border p-4">
<p className="text-sm text-muted-foreground">Pagos pendientes</p>
<p className="text-2xl font-bold">
@@ -176,6 +177,7 @@ export function DashboardPage() {
variant="minimal"
/>
<QuoteCard quote={blue} title="BLUE" variant="minimal" />
<QuoteCard quote={bna} title="Dolar Oficial" variant="minimal" />
</div>
<DashboardExpensesTable />
</div>

View File

@@ -141,11 +141,7 @@ export function ExpensesTable({
if (expense.status === "PAYED") return null;
return (
<div className="flex justify-end gap-1">
<Button
variant="ghost"
size="xs"
onClick={() => onEdit(expense)}
>
<Button variant="ghost" size="xs" onClick={() => onEdit(expense)}>
<Pencil className="size-3.5" />
Editar
</Button>