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,
|
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 yesterday = subDays(today, 1);
|
||||||
const yesterdayStr = formatDate(yesterday);
|
const yesterdayStr = formatDate(yesterday);
|
||||||
const firstOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
|
const firstOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||||
@@ -91,6 +107,29 @@ export function AnalysisPage({ currency }: { currency: string }) {
|
|||||||
}));
|
}));
|
||||||
}, [daily]);
|
}, [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(() => {
|
const { yDomain, minBuyValue, maxBuyValue, avgBuyValue } = useMemo(() => {
|
||||||
if (chartData.length === 0)
|
if (chartData.length === 0)
|
||||||
return {
|
return {
|
||||||
@@ -178,7 +217,10 @@ export function AnalysisPage({ currency }: { currency: string }) {
|
|||||||
key={c}
|
key={c}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() =>
|
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 ${
|
className={`px-3 py-1 text-xs rounded-md transition-colors cursor-pointer ${
|
||||||
currency === c
|
currency === c
|
||||||
@@ -402,6 +444,119 @@ export function AnalysisPage({ currency }: { currency: string }) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user