feat(analysis): add comparison chart of buy price for the 3 quotes
This commit is contained in:
@@ -67,6 +67,22 @@ export function AnalysisPage({ currency }: { currency: string }) {
|
||||
endDateStr,
|
||||
);
|
||||
|
||||
const { data: beloDaily, isLoading: beloLoading } = useDailyQuotes(
|
||||
"BELO",
|
||||
startDateStr,
|
||||
endDateStr,
|
||||
);
|
||||
const { data: blueDaily, isLoading: blueLoading } = useDailyQuotes(
|
||||
"BLUE",
|
||||
startDateStr,
|
||||
endDateStr,
|
||||
);
|
||||
const { data: bnaDaily, isLoading: bnaLoading } = useDailyQuotes(
|
||||
"BNA",
|
||||
startDateStr,
|
||||
endDateStr,
|
||||
);
|
||||
|
||||
const yesterday = subDays(today, 1);
|
||||
const yesterdayStr = formatDate(yesterday);
|
||||
const firstOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
@@ -91,6 +107,29 @@ export function AnalysisPage({ currency }: { currency: string }) {
|
||||
}));
|
||||
}, [daily]);
|
||||
|
||||
const comparisonData = useMemo(() => {
|
||||
const map = new Map<
|
||||
string,
|
||||
{ date: string; BELO?: number; BLUE?: number; BNA?: number }
|
||||
>();
|
||||
const add = (
|
||||
rows: { date: string; buy: number }[] | undefined,
|
||||
key: "BELO" | "BLUE" | "BNA",
|
||||
) => {
|
||||
rows?.forEach((d) => {
|
||||
const entry = map.get(d.date) ?? { date: d.date };
|
||||
entry[key] = d.buy;
|
||||
map.set(d.date, entry);
|
||||
});
|
||||
};
|
||||
add(beloDaily, "BELO");
|
||||
add(blueDaily, "BLUE");
|
||||
add(bnaDaily, "BNA");
|
||||
return [...map.values()]
|
||||
.sort((a, b) => a.date.localeCompare(b.date))
|
||||
.map(({ date, ...rest }) => ({ date: formatShortDate(date), ...rest }));
|
||||
}, [beloDaily, blueDaily, bnaDaily]);
|
||||
|
||||
const { yDomain, minBuyValue, maxBuyValue, avgBuyValue } = useMemo(() => {
|
||||
if (chartData.length === 0)
|
||||
return {
|
||||
@@ -178,7 +217,10 @@ export function AnalysisPage({ currency }: { currency: string }) {
|
||||
key={c}
|
||||
type="button"
|
||||
onClick={() =>
|
||||
navigate({ to: "/quotes/analysis/$currency", params: { currency: c } })
|
||||
navigate({
|
||||
to: "/quotes/analysis/$currency",
|
||||
params: { currency: c },
|
||||
})
|
||||
}
|
||||
className={`px-3 py-1 text-xs rounded-md transition-colors cursor-pointer ${
|
||||
currency === c
|
||||
@@ -402,6 +444,119 @@ export function AnalysisPage({ currency }: { currency: string }) {
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="rounded-lg border p-4">
|
||||
<h2 className="text-sm font-medium mb-4">
|
||||
Precio de compra por cotización
|
||||
</h2>
|
||||
|
||||
{beloLoading || blueLoading || bnaLoading ? (
|
||||
<div className="flex items-center justify-center h-64 text-muted-foreground">
|
||||
Cargando...
|
||||
</div>
|
||||
) : comparisonData.length === 0 ? (
|
||||
<div className="flex items-center justify-center h-64 text-muted-foreground">
|
||||
Sin datos para este período
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="h-64">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<LineChart data={comparisonData}>
|
||||
<CartesianGrid
|
||||
strokeDasharray="3 3"
|
||||
className="stroke-border"
|
||||
/>
|
||||
<XAxis
|
||||
dataKey="date"
|
||||
tick={{ fontSize: 11 }}
|
||||
className="text-muted-foreground"
|
||||
interval="preserveStartEnd"
|
||||
/>
|
||||
<YAxis
|
||||
tick={{ fontSize: 11 }}
|
||||
className="text-muted-foreground"
|
||||
tickFormatter={(v: number) =>
|
||||
`$${priceFormatter.format(v)}`
|
||||
}
|
||||
width={80}
|
||||
/>
|
||||
<Tooltip
|
||||
formatter={(value: unknown, name: unknown) => [
|
||||
`$${priceFormatter.format(Number(value))}`,
|
||||
CURRENCY_LABELS[String(name)] ?? String(name),
|
||||
]}
|
||||
labelFormatter={(label: unknown) => `Fecha: ${label}`}
|
||||
contentStyle={{
|
||||
backgroundColor: "var(--card)",
|
||||
border: "1px solid var(--border)",
|
||||
borderRadius: "var(--radius)",
|
||||
fontSize: 13,
|
||||
}}
|
||||
/>
|
||||
<Line
|
||||
type="linear"
|
||||
dataKey="BELO"
|
||||
name="BELO"
|
||||
stroke="var(--chart-1)"
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
activeDot={{ r: 4 }}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
<Line
|
||||
type="linear"
|
||||
dataKey="BLUE"
|
||||
name="BLUE"
|
||||
stroke="var(--chart-2)"
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
activeDot={{ r: 4 }}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
<Line
|
||||
type="linear"
|
||||
dataKey="BNA"
|
||||
name="BNA"
|
||||
stroke="var(--chart-4)"
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
activeDot={{ r: 4 }}
|
||||
isAnimationActive={false}
|
||||
/>
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-4 mt-3">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span
|
||||
className="size-2.5 rounded-full"
|
||||
style={{ backgroundColor: "var(--chart-1)" }}
|
||||
/>
|
||||
<span className="text-xs text-muted-foreground">BELO</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span
|
||||
className="size-2.5 rounded-full"
|
||||
style={{ backgroundColor: "var(--chart-2)" }}
|
||||
/>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
Dólar Blue
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span
|
||||
className="size-2.5 rounded-full"
|
||||
style={{ backgroundColor: "var(--chart-4)" }}
|
||||
/>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
Dólar Oficial
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user