refactor: migrate from ESLint to Biome and extract SQL queries to data.ts

- Replace ESLint with Biome for linting and formatting
- Configure Biome with tabs, double quotes, and organized imports
- Move all SQL/Drizzle queries from page.tsx files to data.ts files
- Create new data.ts files for: ajustes, dashboard, relatorios/categorias
- Update existing data.ts files: extrato, fatura (add lancamentos queries)
- Remove all drizzle-orm imports from page.tsx files
- Update README.md with new tooling info

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Felipe Coutinho
2026-01-27 13:15:37 +00:00
parent 8ffe61c59b
commit a7f63fb77a
442 changed files with 66141 additions and 69292 deletions

View File

@@ -1,86 +1,86 @@
import { PagadoresPage } from "@/components/pagadores/pagadores-page";
import type { PagadorStatus } from "@/lib/pagadores/constants";
import {
PAGADOR_STATUS_OPTIONS,
DEFAULT_PAGADOR_AVATAR,
PAGADOR_ROLE_ADMIN,
} from "@/lib/pagadores/constants";
import { getUserId } from "@/lib/auth/server";
import { fetchPagadoresWithAccess } from "@/lib/pagadores/access";
import { readdir } from "node:fs/promises";
import path from "node:path";
import { PagadoresPage } from "@/components/pagadores/pagadores-page";
import { getUserId } from "@/lib/auth/server";
import { fetchPagadoresWithAccess } from "@/lib/pagadores/access";
import type { PagadorStatus } from "@/lib/pagadores/constants";
import {
DEFAULT_PAGADOR_AVATAR,
PAGADOR_ROLE_ADMIN,
PAGADOR_STATUS_OPTIONS,
} from "@/lib/pagadores/constants";
const AVATAR_DIRECTORY = path.join(process.cwd(), "public", "avatares");
const AVATAR_EXTENSIONS = new Set([".png", ".jpg", ".jpeg", ".svg", ".webp"]);
async function loadAvatarOptions() {
try {
const files = await readdir(AVATAR_DIRECTORY, { withFileTypes: true });
try {
const files = await readdir(AVATAR_DIRECTORY, { withFileTypes: true });
const items = files
.filter((file) => file.isFile())
.map((file) => file.name)
.filter((file) => AVATAR_EXTENSIONS.has(path.extname(file).toLowerCase()))
.sort((a, b) => a.localeCompare(b, "pt-BR", { sensitivity: "base" }));
const items = files
.filter((file) => file.isFile())
.map((file) => file.name)
.filter((file) => AVATAR_EXTENSIONS.has(path.extname(file).toLowerCase()))
.sort((a, b) => a.localeCompare(b, "pt-BR", { sensitivity: "base" }));
if (items.length === 0) {
items.push(DEFAULT_PAGADOR_AVATAR);
}
if (items.length === 0) {
items.push(DEFAULT_PAGADOR_AVATAR);
}
return Array.from(new Set(items));
} catch {
return [DEFAULT_PAGADOR_AVATAR];
}
return Array.from(new Set(items));
} catch {
return [DEFAULT_PAGADOR_AVATAR];
}
}
const resolveStatus = (status: string | null): PagadorStatus => {
const normalized = status?.trim() ?? "";
const found = PAGADOR_STATUS_OPTIONS.find(
(option) => option.toLowerCase() === normalized.toLowerCase()
);
return found ?? PAGADOR_STATUS_OPTIONS[0];
const normalized = status?.trim() ?? "";
const found = PAGADOR_STATUS_OPTIONS.find(
(option) => option.toLowerCase() === normalized.toLowerCase(),
);
return found ?? PAGADOR_STATUS_OPTIONS[0];
};
export default async function Page() {
const userId = await getUserId();
const userId = await getUserId();
const [pagadorRows, avatarOptions] = await Promise.all([
fetchPagadoresWithAccess(userId),
loadAvatarOptions(),
]);
const [pagadorRows, avatarOptions] = await Promise.all([
fetchPagadoresWithAccess(userId),
loadAvatarOptions(),
]);
const pagadoresData = pagadorRows
.map((pagador) => ({
id: pagador.id,
name: pagador.name,
email: pagador.email,
avatarUrl: pagador.avatarUrl,
status: resolveStatus(pagador.status),
note: pagador.note,
role: pagador.role,
isAutoSend: pagador.isAutoSend ?? false,
createdAt: pagador.createdAt?.toISOString() ?? new Date().toISOString(),
canEdit: pagador.canEdit,
sharedByName: pagador.sharedByName ?? null,
sharedByEmail: pagador.sharedByEmail ?? null,
shareId: pagador.shareId ?? null,
shareCode: pagador.canEdit ? pagador.shareCode ?? null : null,
}))
.sort((a, b) => {
// Admin sempre primeiro
if (a.role === PAGADOR_ROLE_ADMIN && b.role !== PAGADOR_ROLE_ADMIN) {
return -1;
}
if (a.role !== PAGADOR_ROLE_ADMIN && b.role === PAGADOR_ROLE_ADMIN) {
return 1;
}
// Se ambos são admin ou ambos não são, mantém ordem original
return 0;
});
const pagadoresData = pagadorRows
.map((pagador) => ({
id: pagador.id,
name: pagador.name,
email: pagador.email,
avatarUrl: pagador.avatarUrl,
status: resolveStatus(pagador.status),
note: pagador.note,
role: pagador.role,
isAutoSend: pagador.isAutoSend ?? false,
createdAt: pagador.createdAt?.toISOString() ?? new Date().toISOString(),
canEdit: pagador.canEdit,
sharedByName: pagador.sharedByName ?? null,
sharedByEmail: pagador.sharedByEmail ?? null,
shareId: pagador.shareId ?? null,
shareCode: pagador.canEdit ? (pagador.shareCode ?? null) : null,
}))
.sort((a, b) => {
// Admin sempre primeiro
if (a.role === PAGADOR_ROLE_ADMIN && b.role !== PAGADOR_ROLE_ADMIN) {
return -1;
}
if (a.role !== PAGADOR_ROLE_ADMIN && b.role === PAGADOR_ROLE_ADMIN) {
return 1;
}
// Se ambos são admin ou ambos não são, mantém ordem original
return 0;
});
return (
<main className="flex flex-col items-start gap-6">
<PagadoresPage pagadores={pagadoresData} avatarOptions={avatarOptions} />
</main>
);
return (
<main className="flex flex-col items-start gap-6">
<PagadoresPage pagadores={pagadoresData} avatarOptions={avatarOptions} />
</main>
);
}