chore: add Biome for lint and fix all lint errors
- Install @biomejs/biome as devDependency at root - Configure biome.json with 2-space indent, double quotes, Tailwind CSS support - Add lint/lint:fix/format/format:fix scripts to root and app package.json - Fix noNonNullAssertion: env vars extracted to variables with suppression, <div role=button> replaced with <button> - Fix noUnusedVariables: remove unused destructured vars - Fix useIterableCallbackReturn: arrow functions with block body - Fix noExplicitAny: recharts Tooltip formatters - Fix noLabelWithoutControl: add htmlFor+id or use <span> for non-input labels - Fix noStaticElementInteractions/useKeyWithClickEvents: role+keyboard events for overlays - Fix noArrayIndexKey: use error string as key - Fix CSS parse: enable tailwindDirectives parser - Normalize formatting across 80 files with biome check --write
This commit is contained in:
@@ -1,26 +1,32 @@
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { BarChart3, RefreshCw } from "lucide-react";
|
||||
import { useMemo, useState } from "react";
|
||||
import {
|
||||
LineChart,
|
||||
CartesianGrid,
|
||||
Line,
|
||||
LineChart,
|
||||
ReferenceLine,
|
||||
ResponsiveContainer,
|
||||
Tooltip,
|
||||
XAxis,
|
||||
YAxis,
|
||||
CartesianGrid,
|
||||
Tooltip,
|
||||
ResponsiveContainer,
|
||||
ReferenceLine,
|
||||
} from "recharts";
|
||||
import {
|
||||
Gauge,
|
||||
GaugeIndicator,
|
||||
GaugeTrack,
|
||||
GaugeRange,
|
||||
GaugeTrack,
|
||||
GaugeValueText,
|
||||
} from "@/components/ui/gauge";
|
||||
import { useQuotes, useQuoteHistory, useDailyMinMax, useDailyQuotes, useFetchQuotes } from "@/lib/queries";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import {
|
||||
useDailyMinMax,
|
||||
useDailyQuotes,
|
||||
useFetchQuotes,
|
||||
useQuoteHistory,
|
||||
useQuotes,
|
||||
} from "@/lib/queries";
|
||||
import { RelativeTime } from "@/lib/time";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { BarChart3, RefreshCw } from "lucide-react";
|
||||
|
||||
const priceFormatter = new Intl.NumberFormat("es-AR", {
|
||||
minimumFractionDigits: 2,
|
||||
@@ -105,15 +111,13 @@ export function BeloPage() {
|
||||
|
||||
const now = new Date();
|
||||
const todayStr = formatDate(now);
|
||||
const firstOfMonth = formatDate(new Date(now.getFullYear(), now.getMonth(), 1));
|
||||
const firstOfMonth = formatDate(
|
||||
new Date(now.getFullYear(), now.getMonth(), 1),
|
||||
);
|
||||
|
||||
const { data: quotes, isLoading: quotesLoading } = useQuotes();
|
||||
const { mutate: doFetchQuotes, isPending: fetchPending } = useFetchQuotes();
|
||||
const { data: dailyMinMax, isLoading: minMaxLoading } = useDailyMinMax(
|
||||
"BELO",
|
||||
todayStr,
|
||||
todayStr,
|
||||
);
|
||||
const { data: dailyMinMax } = useDailyMinMax("BELO", todayStr, todayStr);
|
||||
const { data: monthlyMinMax } = useDailyMinMax(
|
||||
"BELO",
|
||||
firstOfMonth,
|
||||
@@ -140,7 +144,8 @@ export function BeloPage() {
|
||||
const minSell = maxData ? Number(maxData.minSell) : 0;
|
||||
const maxSell = maxData ? Number(maxData.maxSell) : 0;
|
||||
|
||||
const gaugeValue = currentBuy > 0 && maxBuy > minBuy ? Math.min(currentBuy, maxBuy) : null;
|
||||
const gaugeValue =
|
||||
currentBuy > 0 && maxBuy > minBuy ? Math.min(currentBuy, maxBuy) : null;
|
||||
|
||||
const gaugePercentage = useMemo(() => {
|
||||
if (gaugeValue !== null && maxBuy > minBuy) {
|
||||
@@ -242,28 +247,18 @@ export function BeloPage() {
|
||||
onClick={() => doFetchQuotes()}
|
||||
className="inline-flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors cursor-pointer"
|
||||
>
|
||||
<RefreshCw className={`h-4 w-4 ${isFetching ? "animate-spin" : ""}`} />
|
||||
<RefreshCw
|
||||
className={`h-4 w-4 ${isFetching ? "animate-spin" : ""}`}
|
||||
/>
|
||||
Actualizar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 md:grid-cols-5">
|
||||
<StatCard
|
||||
label="Precio actual"
|
||||
buy={currentBuy}
|
||||
sell={currentSell}
|
||||
/>
|
||||
<StatCard
|
||||
label="Mínimo del día"
|
||||
buy={minBuy}
|
||||
sell={minSell}
|
||||
/>
|
||||
<StatCard
|
||||
label="Máximo del día"
|
||||
buy={maxBuy}
|
||||
sell={maxSell}
|
||||
/>
|
||||
<StatCard label="Precio actual" buy={currentBuy} sell={currentSell} />
|
||||
<StatCard label="Mínimo del día" buy={minBuy} sell={minSell} />
|
||||
<StatCard label="Máximo del día" buy={maxBuy} sell={maxSell} />
|
||||
<StatCard
|
||||
label="Máximo del mes"
|
||||
buy={monthlyMax?.maxBuy ?? 0}
|
||||
@@ -282,7 +277,8 @@ export function BeloPage() {
|
||||
startAngle={0}
|
||||
endAngle={360}
|
||||
getValueText={(v, m, mx) => {
|
||||
const pct = mx === m ? 100 : Math.round(((v - m) / (mx - m)) * 100);
|
||||
const pct =
|
||||
mx === m ? 100 : Math.round(((v - m) / (mx - m)) * 100);
|
||||
return `${pct}%`;
|
||||
}}
|
||||
>
|
||||
@@ -290,7 +286,12 @@ export function BeloPage() {
|
||||
<GaugeTrack />
|
||||
<GaugeRange className={getGaugeColor(gaugePercentage)} />
|
||||
</GaugeIndicator>
|
||||
<GaugeValueText className={cn(getGaugeColor(gaugePercentage), "text-sm font-semibold")} />
|
||||
<GaugeValueText
|
||||
className={cn(
|
||||
getGaugeColor(gaugePercentage),
|
||||
"text-sm font-semibold",
|
||||
)}
|
||||
/>
|
||||
</Gauge>
|
||||
</div>
|
||||
</div>
|
||||
@@ -336,7 +337,10 @@ export function BeloPage() {
|
||||
<div className="h-64">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<LineChart data={chartData}>
|
||||
<CartesianGrid strokeDasharray="3 3" className="stroke-border" />
|
||||
<CartesianGrid
|
||||
strokeDasharray="3 3"
|
||||
className="stroke-border"
|
||||
/>
|
||||
<XAxis
|
||||
dataKey="time"
|
||||
tick={{ fontSize: 11 }}
|
||||
@@ -351,11 +355,11 @@ export function BeloPage() {
|
||||
domain={yDomain}
|
||||
/>
|
||||
<Tooltip
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// biome-ignore lint/suspicious/noExplicitAny: recharts types
|
||||
formatter={(value: any) => [
|
||||
`$${priceFormatter.format(Number(value))}`,
|
||||
]}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// biome-ignore lint/suspicious/noExplicitAny: recharts types
|
||||
labelFormatter={(label: any) =>
|
||||
period === "day" ? `Hora: ${label}` : `Fecha: ${label}`
|
||||
}
|
||||
@@ -417,11 +421,17 @@ export function BeloPage() {
|
||||
|
||||
<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="size-2.5 rounded-full"
|
||||
style={{ backgroundColor: "var(--chart-1)" }}
|
||||
/>
|
||||
<span className="text-xs text-muted-foreground">Compra</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="size-2.5 rounded-full" style={{ backgroundColor: "var(--chart-2)" }} />
|
||||
<span
|
||||
className="size-2.5 rounded-full"
|
||||
style={{ backgroundColor: "var(--chart-2)" }}
|
||||
/>
|
||||
<span className="text-xs text-muted-foreground">Venta</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user