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:
Jose Selesan
2026-06-04 10:48:07 -03:00
parent 53a797703e
commit 5b6ccf0fa6
81 changed files with 1565 additions and 794 deletions

View File

@@ -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>