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,26 @@
import type { Context } from "hono";
import { prisma } from "../../../lib/prisma";
import { PaymentStatus } from "../../../generated/prisma/client";
import { cache } from "../../../lib/cache";
import { logger } from "../../../lib/logger";
import { PaymentStatus } from "../../../generated/prisma/client";
import { prisma } from "../../../lib/prisma";
function parseAmount(raw: string): number | null {
const cleaned = raw.replace("$", "").replace(/,/g, "").trim();
if (!cleaned) return null;
const n = Number(cleaned);
return isNaN(n) ? null : n;
return Number.isNaN(n) ? null : n;
}
function parseDate(raw: string): Date | null {
const trimmed = raw.trim();
if (!trimmed) return null;
const d = new Date(trimmed);
return isNaN(d.getTime()) ? null : d;
return Number.isNaN(d.getTime()) ? null : d;
}
export async function importExpensesHandler(c: Context) {
const body = await c.req.parseBody();
const file = body["file"];
const file = body.file;
if (!file || !(file instanceof File)) {
return c.json({ error: "No se envió ningún archivo" }, 400);
@@ -30,7 +30,10 @@ export async function importExpensesHandler(c: Context) {
const lines = text.trim().split("\n");
if (lines.length < 2) {
return c.json({ error: "El archivo está vacío o solo tiene encabezados" }, 400);
return c.json(
{ error: "El archivo está vacío o solo tiene encabezados" },
400,
);
}
let imported = 0;
@@ -43,7 +46,9 @@ export async function importExpensesHandler(c: Context) {
const parts = line.split("|");
if (parts.length < 10) {
errors.push(`Línea ${i + 1}: formato inválido (${parts.length} columnas)`);
errors.push(
`Línea ${i + 1}: formato inválido (${parts.length} columnas)`,
);
continue;
}
@@ -68,7 +73,9 @@ export async function importExpensesHandler(c: Context) {
const paymentDate = parseDate(rawPaymentDate);
if (!dueDate) {
errors.push(`Línea ${i + 1} ("${description}"): fecha de vencimiento inválida`);
errors.push(
`Línea ${i + 1} ("${description}"): fecha de vencimiento inválida`,
);
continue;
}
@@ -90,7 +97,8 @@ export async function importExpensesHandler(c: Context) {
}
}
const status = rawStatus === "PAYED" ? PaymentStatus.PAYED : PaymentStatus.PENDING;
const status =
rawStatus === "PAYED" ? PaymentStatus.PAYED : PaymentStatus.PENDING;
await prisma.expense.create({
data: {