diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index dc0bb0f..0000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -v22.12.0 diff --git a/.vscode/settings.json b/.vscode/settings.json index 3759003..67420df 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,5 +28,8 @@ "eslint.enable": false, "prettier.enable": false, "typescript.preferences.organizeImportsCollation": "ordinal", - "editor.fontSize": 15 + "editor.fontSize": 15, + "[jsonc]": { + "editor.defaultFormatter": "vscode.json-language-features" + } } diff --git a/README.md b/README.md index 96d8ee7..4bca9bb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- OpenMonetis Logo + OpenMonetis Logo

@@ -21,7 +21,7 @@ ---

- Dashboard Preview + Dashboard Preview

--- diff --git a/app/(dashboard)/categorias/historico/page.tsx b/app/(dashboard)/categorias/historico/page.tsx deleted file mode 100644 index 4541dee..0000000 --- a/app/(dashboard)/categorias/historico/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { CategoryHistoryWidget } from "@/components/dashboard/category-history-widget"; -import { getUser } from "@/lib/auth/server"; -import { fetchCategoryHistory } from "@/lib/dashboard/categories/category-history"; -import { getCurrentPeriod } from "@/lib/utils/period"; - -export default async function HistoricoCategoriasPage() { - const user = await getUser(); - const currentPeriod = getCurrentPeriod(); - - const data = await fetchCategoryHistory(user.id, currentPeriod); - - return ( -
- -
- ); -} diff --git a/app/(dashboard)/lancamentos/data.ts b/app/(dashboard)/lancamentos/data.ts deleted file mode 100644 index 2482052..0000000 --- a/app/(dashboard)/lancamentos/data.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { and, desc, eq, isNull, ne, or, type SQL } from "drizzle-orm"; -import { - cartoes, - categorias, - contas, - lancamentos, - pagadores, -} from "@/db/schema"; -import { INITIAL_BALANCE_NOTE } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; - -export async function fetchLancamentos(filters: SQL[]) { - const lancamentoRows = await db - .select({ - lancamento: lancamentos, - pagador: pagadores, - conta: contas, - cartao: cartoes, - categoria: categorias, - }) - .from(lancamentos) - .leftJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) - .leftJoin(contas, eq(lancamentos.contaId, contas.id)) - .leftJoin(cartoes, eq(lancamentos.cartaoId, cartoes.id)) - .leftJoin(categorias, eq(lancamentos.categoriaId, categorias.id)) - .where( - and( - ...filters, - // Excluir saldos iniciais de contas que têm excludeInitialBalanceFromIncome = true - or( - ne(lancamentos.note, INITIAL_BALANCE_NOTE), - isNull(contas.excludeInitialBalanceFromIncome), - eq(contas.excludeInitialBalanceFromIncome, false), - ), - ), - ) - .orderBy(desc(lancamentos.purchaseDate), desc(lancamentos.createdAt)); - - // Transformar resultado para o formato esperado - return lancamentoRows.map((row) => ({ - ...row.lancamento, - pagador: row.pagador, - conta: row.conta, - cartao: row.cartao, - categoria: row.categoria, - })); -} diff --git a/app/(dashboard)/relatorios/analise-parcelas/page.tsx b/app/(dashboard)/relatorios/analise-parcelas/page.tsx deleted file mode 100644 index 51306d4..0000000 --- a/app/(dashboard)/relatorios/analise-parcelas/page.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { InstallmentAnalysisPage } from "@/components/dashboard/installment-analysis/installment-analysis-page"; -import { getUser } from "@/lib/auth/server"; -import { fetchInstallmentAnalysis } from "@/lib/dashboard/expenses/installment-analysis"; - -export default async function Page() { - const user = await getUser(); - const data = await fetchInstallmentAnalysis(user.id); - - return ( -
- -
- ); -} diff --git a/biome.json b/biome.json index a4a3a54..a10f1ba 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.4.4/schema.json", + "$schema": "https://biomejs.dev/schemas/2.4.6/schema.json", "vcs": { "enabled": true, "clientKind": "git", diff --git a/components/logo-picker/index.ts b/components/logo-picker/index.ts deleted file mode 100644 index fca8bff..0000000 --- a/components/logo-picker/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { LogoPickerTrigger, LogoPickerDialog } from "./logo-picker"; diff --git a/components/ui/use-mobile.ts b/components/ui/use-mobile.ts deleted file mode 100644 index 41daf28..0000000 --- a/components/ui/use-mobile.ts +++ /dev/null @@ -1 +0,0 @@ -export { useIsMobile, useMobile } from "@/lib/hooks/use-mobile"; diff --git a/drizzle/0019_parched_mephistopheles.sql b/drizzle/0019_parched_mephistopheles.sql new file mode 100644 index 0000000..2987dc0 --- /dev/null +++ b/drizzle/0019_parched_mephistopheles.sql @@ -0,0 +1,15 @@ +CREATE TABLE "recurring_series" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "user_id" text NOT NULL, + "status" text DEFAULT 'active' NOT NULL, + "day_of_month" smallint NOT NULL, + "last_generated_period" text NOT NULL, + "template_data" jsonb NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL +); +--> statement-breakpoint +ALTER TABLE "lancamentos" ADD COLUMN "recurring_series_id" uuid;--> statement-breakpoint +ALTER TABLE "recurring_series" ADD CONSTRAINT "recurring_series_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +CREATE INDEX "recurring_series_user_id_status_idx" ON "recurring_series" USING btree ("user_id","status");--> statement-breakpoint +ALTER TABLE "lancamentos" ADD CONSTRAINT "lancamentos_recurring_series_id_recurring_series_id_fk" FOREIGN KEY ("recurring_series_id") REFERENCES "public"."recurring_series"("id") ON DELETE set null ON UPDATE no action; \ No newline at end of file diff --git a/drizzle/meta/0018_snapshot.json b/drizzle/meta/0018_snapshot.json index 66ec7d6..6eb4649 100644 --- a/drizzle/meta/0018_snapshot.json +++ b/drizzle/meta/0018_snapshot.json @@ -1,2416 +1,2286 @@ { - "id": "853b7f42-7b0e-43a6-8665-918ec5ec6608", - "prevId": "ad4a0401-4eb8-47ab-a18d-a85643544d73", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.account": { - "name": "account", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "accountId": { - "name": "accountId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "providerId": { - "name": "providerId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "accessToken": { - "name": "accessToken", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "refreshToken": { - "name": "refreshToken", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "idToken": { - "name": "idToken", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "accessTokenExpiresAt": { - "name": "accessTokenExpiresAt", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "refreshTokenExpiresAt": { - "name": "refreshTokenExpiresAt", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "scope": { - "name": "scope", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "createdAt": { - "name": "createdAt", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - }, - "updatedAt": { - "name": "updatedAt", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "account_userId_user_id_fk": { - "name": "account_userId_user_id_fk", - "tableFrom": "account", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.anotacoes": { - "name": "anotacoes", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "titulo": { - "name": "titulo", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "descricao": { - "name": "descricao", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "tipo": { - "name": "tipo", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'nota'" - }, - "tasks": { - "name": "tasks", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "arquivada": { - "name": "arquivada", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "anotacoes_user_id_user_id_fk": { - "name": "anotacoes_user_id_user_id_fk", - "tableFrom": "anotacoes", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.antecipacoes_parcelas": { - "name": "antecipacoes_parcelas", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "series_id": { - "name": "series_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "periodo_antecipacao": { - "name": "periodo_antecipacao", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "data_antecipacao": { - "name": "data_antecipacao", - "type": "date", - "primaryKey": false, - "notNull": true - }, - "parcelas_antecipadas": { - "name": "parcelas_antecipadas", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "valor_total": { - "name": "valor_total", - "type": "numeric(12, 2)", - "primaryKey": false, - "notNull": true - }, - "qtde_parcelas": { - "name": "qtde_parcelas", - "type": "smallint", - "primaryKey": false, - "notNull": true - }, - "desconto": { - "name": "desconto", - "type": "numeric(12, 2)", - "primaryKey": false, - "notNull": true, - "default": "'0'" - }, - "lancamento_id": { - "name": "lancamento_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "pagador_id": { - "name": "pagador_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "categoria_id": { - "name": "categoria_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "anotacao": { - "name": "anotacao", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "antecipacoes_parcelas_series_id_idx": { - "name": "antecipacoes_parcelas_series_id_idx", - "columns": [ - { - "expression": "series_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "antecipacoes_parcelas_user_id_idx": { - "name": "antecipacoes_parcelas_user_id_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "antecipacoes_parcelas_lancamento_id_lancamentos_id_fk": { - "name": "antecipacoes_parcelas_lancamento_id_lancamentos_id_fk", - "tableFrom": "antecipacoes_parcelas", - "tableTo": "lancamentos", - "columnsFrom": [ - "lancamento_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "antecipacoes_parcelas_pagador_id_pagadores_id_fk": { - "name": "antecipacoes_parcelas_pagador_id_pagadores_id_fk", - "tableFrom": "antecipacoes_parcelas", - "tableTo": "pagadores", - "columnsFrom": [ - "pagador_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "antecipacoes_parcelas_categoria_id_categorias_id_fk": { - "name": "antecipacoes_parcelas_categoria_id_categorias_id_fk", - "tableFrom": "antecipacoes_parcelas", - "tableTo": "categorias", - "columnsFrom": [ - "categoria_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "antecipacoes_parcelas_user_id_user_id_fk": { - "name": "antecipacoes_parcelas_user_id_user_id_fk", - "tableFrom": "antecipacoes_parcelas", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.cartoes": { - "name": "cartoes", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "nome": { - "name": "nome", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "dt_fechamento": { - "name": "dt_fechamento", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "dt_vencimento": { - "name": "dt_vencimento", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "anotacao": { - "name": "anotacao", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "limite": { - "name": "limite", - "type": "numeric(10, 2)", - "primaryKey": false, - "notNull": false - }, - "bandeira": { - "name": "bandeira", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "logo": { - "name": "logo", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "conta_id": { - "name": "conta_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "cartoes_user_id_status_idx": { - "name": "cartoes_user_id_status_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "status", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "cartoes_user_id_user_id_fk": { - "name": "cartoes_user_id_user_id_fk", - "tableFrom": "cartoes", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "cartoes_conta_id_contas_id_fk": { - "name": "cartoes_conta_id_contas_id_fk", - "tableFrom": "cartoes", - "tableTo": "contas", - "columnsFrom": [ - "conta_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "cascade" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.categorias": { - "name": "categorias", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "nome": { - "name": "nome", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "tipo": { - "name": "tipo", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "icone": { - "name": "icone", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "categorias_user_id_type_idx": { - "name": "categorias_user_id_type_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "tipo", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "categorias_user_id_user_id_fk": { - "name": "categorias_user_id_user_id_fk", - "tableFrom": "categorias", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.compartilhamentos_pagador": { - "name": "compartilhamentos_pagador", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "pagador_id": { - "name": "pagador_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "shared_with_user_id": { - "name": "shared_with_user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "permission": { - "name": "permission", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'read'" - }, - "created_by_user_id": { - "name": "created_by_user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "compartilhamentos_pagador_unique": { - "name": "compartilhamentos_pagador_unique", - "columns": [ - { - "expression": "pagador_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "shared_with_user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "compartilhamentos_pagador_pagador_id_pagadores_id_fk": { - "name": "compartilhamentos_pagador_pagador_id_pagadores_id_fk", - "tableFrom": "compartilhamentos_pagador", - "tableTo": "pagadores", - "columnsFrom": [ - "pagador_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "compartilhamentos_pagador_shared_with_user_id_user_id_fk": { - "name": "compartilhamentos_pagador_shared_with_user_id_user_id_fk", - "tableFrom": "compartilhamentos_pagador", - "tableTo": "user", - "columnsFrom": [ - "shared_with_user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "compartilhamentos_pagador_created_by_user_id_user_id_fk": { - "name": "compartilhamentos_pagador_created_by_user_id_user_id_fk", - "tableFrom": "compartilhamentos_pagador", - "tableTo": "user", - "columnsFrom": [ - "created_by_user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.contas": { - "name": "contas", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "nome": { - "name": "nome", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "tipo_conta": { - "name": "tipo_conta", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "anotacao": { - "name": "anotacao", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "logo": { - "name": "logo", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "saldo_inicial": { - "name": "saldo_inicial", - "type": "numeric(12, 2)", - "primaryKey": false, - "notNull": true, - "default": "'0'" - }, - "excluir_do_saldo": { - "name": "excluir_do_saldo", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "excluir_saldo_inicial_receitas": { - "name": "excluir_saldo_inicial_receitas", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "contas_user_id_status_idx": { - "name": "contas_user_id_status_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "status", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "contas_user_id_user_id_fk": { - "name": "contas_user_id_user_id_fk", - "tableFrom": "contas", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.faturas": { - "name": "faturas", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "status_pagamento": { - "name": "status_pagamento", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "periodo": { - "name": "periodo", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "cartao_id": { - "name": "cartao_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "faturas_user_id_period_idx": { - "name": "faturas_user_id_period_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "periodo", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "faturas_cartao_id_period_idx": { - "name": "faturas_cartao_id_period_idx", - "columns": [ - { - "expression": "cartao_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "periodo", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "faturas_user_id_user_id_fk": { - "name": "faturas_user_id_user_id_fk", - "tableFrom": "faturas", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "faturas_cartao_id_cartoes_id_fk": { - "name": "faturas_cartao_id_cartoes_id_fk", - "tableFrom": "faturas", - "tableTo": "cartoes", - "columnsFrom": [ - "cartao_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "cascade" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.insights_salvos": { - "name": "insights_salvos", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "period": { - "name": "period", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "model_id": { - "name": "model_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "data": { - "name": "data", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "insights_salvos_user_period_idx": { - "name": "insights_salvos_user_period_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "period", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "insights_salvos_user_id_user_id_fk": { - "name": "insights_salvos_user_id_user_id_fk", - "tableFrom": "insights_salvos", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.lancamentos": { - "name": "lancamentos", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "condicao": { - "name": "condicao", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "nome": { - "name": "nome", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "forma_pagamento": { - "name": "forma_pagamento", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "anotacao": { - "name": "anotacao", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "valor": { - "name": "valor", - "type": "numeric(12, 2)", - "primaryKey": false, - "notNull": true - }, - "data_compra": { - "name": "data_compra", - "type": "date", - "primaryKey": false, - "notNull": true - }, - "tipo_transacao": { - "name": "tipo_transacao", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "qtde_parcela": { - "name": "qtde_parcela", - "type": "smallint", - "primaryKey": false, - "notNull": false - }, - "periodo": { - "name": "periodo", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "parcela_atual": { - "name": "parcela_atual", - "type": "smallint", - "primaryKey": false, - "notNull": false - }, - "qtde_recorrencia": { - "name": "qtde_recorrencia", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "data_vencimento": { - "name": "data_vencimento", - "type": "date", - "primaryKey": false, - "notNull": false - }, - "dt_pagamento_boleto": { - "name": "dt_pagamento_boleto", - "type": "date", - "primaryKey": false, - "notNull": false - }, - "realizado": { - "name": "realizado", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "dividido": { - "name": "dividido", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "antecipado": { - "name": "antecipado", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "antecipacao_id": { - "name": "antecipacao_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "cartao_id": { - "name": "cartao_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "conta_id": { - "name": "conta_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "categoria_id": { - "name": "categoria_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "pagador_id": { - "name": "pagador_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "series_id": { - "name": "series_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "transfer_id": { - "name": "transfer_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "lancamentos_user_id_period_idx": { - "name": "lancamentos_user_id_period_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "periodo", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "lancamentos_user_id_period_type_idx": { - "name": "lancamentos_user_id_period_type_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "periodo", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "tipo_transacao", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "lancamentos_pagador_id_period_idx": { - "name": "lancamentos_pagador_id_period_idx", - "columns": [ - { - "expression": "pagador_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "periodo", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "lancamentos_user_id_purchase_date_idx": { - "name": "lancamentos_user_id_purchase_date_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "data_compra", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "lancamentos_series_id_idx": { - "name": "lancamentos_series_id_idx", - "columns": [ - { - "expression": "series_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "lancamentos_transfer_id_idx": { - "name": "lancamentos_transfer_id_idx", - "columns": [ - { - "expression": "transfer_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "lancamentos_user_id_condition_idx": { - "name": "lancamentos_user_id_condition_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "condicao", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "lancamentos_cartao_id_period_idx": { - "name": "lancamentos_cartao_id_period_idx", - "columns": [ - { - "expression": "cartao_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "periodo", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "lancamentos_antecipacao_id_antecipacoes_parcelas_id_fk": { - "name": "lancamentos_antecipacao_id_antecipacoes_parcelas_id_fk", - "tableFrom": "lancamentos", - "tableTo": "antecipacoes_parcelas", - "columnsFrom": [ - "antecipacao_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "lancamentos_user_id_user_id_fk": { - "name": "lancamentos_user_id_user_id_fk", - "tableFrom": "lancamentos", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "lancamentos_cartao_id_cartoes_id_fk": { - "name": "lancamentos_cartao_id_cartoes_id_fk", - "tableFrom": "lancamentos", - "tableTo": "cartoes", - "columnsFrom": [ - "cartao_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "cascade" - }, - "lancamentos_conta_id_contas_id_fk": { - "name": "lancamentos_conta_id_contas_id_fk", - "tableFrom": "lancamentos", - "tableTo": "contas", - "columnsFrom": [ - "conta_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "cascade" - }, - "lancamentos_categoria_id_categorias_id_fk": { - "name": "lancamentos_categoria_id_categorias_id_fk", - "tableFrom": "lancamentos", - "tableTo": "categorias", - "columnsFrom": [ - "categoria_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "cascade" - }, - "lancamentos_pagador_id_pagadores_id_fk": { - "name": "lancamentos_pagador_id_pagadores_id_fk", - "tableFrom": "lancamentos", - "tableTo": "pagadores", - "columnsFrom": [ - "pagador_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "cascade" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.orcamentos": { - "name": "orcamentos", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "valor": { - "name": "valor", - "type": "numeric(10, 2)", - "primaryKey": false, - "notNull": true - }, - "periodo": { - "name": "periodo", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "categoria_id": { - "name": "categoria_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "orcamentos_user_id_period_idx": { - "name": "orcamentos_user_id_period_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "periodo", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "orcamentos_user_id_user_id_fk": { - "name": "orcamentos_user_id_user_id_fk", - "tableFrom": "orcamentos", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "orcamentos_categoria_id_categorias_id_fk": { - "name": "orcamentos_categoria_id_categorias_id_fk", - "tableFrom": "orcamentos", - "tableTo": "categorias", - "columnsFrom": [ - "categoria_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "cascade" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.pagadores": { - "name": "pagadores", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "nome": { - "name": "nome", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "avatar_url": { - "name": "avatar_url", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "anotacao": { - "name": "anotacao", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "role": { - "name": "role", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "is_auto_send": { - "name": "is_auto_send", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "share_code": { - "name": "share_code", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "substr(encode(gen_random_bytes(24), 'base64'), 1, 24)" - }, - "last_mail": { - "name": "last_mail", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "pagadores_share_code_key": { - "name": "pagadores_share_code_key", - "columns": [ - { - "expression": "share_code", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "pagadores_user_id_status_idx": { - "name": "pagadores_user_id_status_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "status", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "pagadores_user_id_role_idx": { - "name": "pagadores_user_id_role_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "role", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "pagadores_user_id_user_id_fk": { - "name": "pagadores_user_id_user_id_fk", - "tableFrom": "pagadores", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.passkey": { - "name": "passkey", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "publicKey": { - "name": "publicKey", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "credentialID": { - "name": "credentialID", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "counter": { - "name": "counter", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "deviceType": { - "name": "deviceType", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "backedUp": { - "name": "backedUp", - "type": "boolean", - "primaryKey": false, - "notNull": true - }, - "transports": { - "name": "transports", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "aaguid": { - "name": "aaguid", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "createdAt": { - "name": "createdAt", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "passkey_userId_user_id_fk": { - "name": "passkey_userId_user_id_fk", - "tableFrom": "passkey", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.pre_lancamentos": { - "name": "pre_lancamentos", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "source_app": { - "name": "source_app", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "source_app_name": { - "name": "source_app_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "original_title": { - "name": "original_title", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "original_text": { - "name": "original_text", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "notification_timestamp": { - "name": "notification_timestamp", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - }, - "parsed_name": { - "name": "parsed_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "parsed_amount": { - "name": "parsed_amount", - "type": "numeric(12, 2)", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'pending'" - }, - "lancamento_id": { - "name": "lancamento_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "processed_at": { - "name": "processed_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "discarded_at": { - "name": "discarded_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "pre_lancamentos_user_id_status_idx": { - "name": "pre_lancamentos_user_id_status_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "status", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "pre_lancamentos_user_id_created_at_idx": { - "name": "pre_lancamentos_user_id_created_at_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "pre_lancamentos_user_id_user_id_fk": { - "name": "pre_lancamentos_user_id_user_id_fk", - "tableFrom": "pre_lancamentos", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "pre_lancamentos_lancamento_id_lancamentos_id_fk": { - "name": "pre_lancamentos_lancamento_id_lancamentos_id_fk", - "tableFrom": "pre_lancamentos", - "tableTo": "lancamentos", - "columnsFrom": [ - "lancamento_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.preferencias_usuario": { - "name": "preferencias_usuario", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "extrato_note_as_column": { - "name": "extrato_note_as_column", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "system_font": { - "name": "system_font", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'ai-sans'" - }, - "money_font": { - "name": "money_font", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'ai-sans'" - }, - "lancamentos_column_order": { - "name": "lancamentos_column_order", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "dashboard_widgets": { - "name": "dashboard_widgets", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "preferencias_usuario_user_id_user_id_fk": { - "name": "preferencias_usuario_user_id_user_id_fk", - "tableFrom": "preferencias_usuario", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "preferencias_usuario_user_id_unique": { - "name": "preferencias_usuario_user_id_unique", - "nullsNotDistinct": false, - "columns": [ - "user_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.session": { - "name": "session", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "expiresAt": { - "name": "expiresAt", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "createdAt": { - "name": "createdAt", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - }, - "updatedAt": { - "name": "updatedAt", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - }, - "ipAddress": { - "name": "ipAddress", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "userAgent": { - "name": "userAgent", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "session_userId_user_id_fk": { - "name": "session_userId_user_id_fk", - "tableFrom": "session", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "session_token_unique": { - "name": "session_token_unique", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.tokens_api": { - "name": "tokens_api", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "token_hash": { - "name": "token_hash", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "token_prefix": { - "name": "token_prefix", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "last_used_at": { - "name": "last_used_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "last_used_ip": { - "name": "last_used_ip", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "revoked_at": { - "name": "revoked_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "tokens_api_user_id_idx": { - "name": "tokens_api_user_id_idx", - "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "tokens_api_token_hash_idx": { - "name": "tokens_api_token_hash_idx", - "columns": [ - { - "expression": "token_hash", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "tokens_api_user_id_user_id_fk": { - "name": "tokens_api_user_id_user_id_fk", - "tableFrom": "tokens_api", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user": { - "name": "user", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "emailVerified": { - "name": "emailVerified", - "type": "boolean", - "primaryKey": false, - "notNull": true - }, - "image": { - "name": "image", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "createdAt": { - "name": "createdAt", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - }, - "updatedAt": { - "name": "updatedAt", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_email_unique": { - "name": "user_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.verification": { - "name": "verification", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "identifier": { - "name": "identifier", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "value": { - "name": "value", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "expiresAt": { - "name": "expiresAt", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - }, - "createdAt": { - "name": "createdAt", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - }, - "updatedAt": { - "name": "updatedAt", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": {}, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file + "id": "853b7f42-7b0e-43a6-8665-918ec5ec6608", + "prevId": "ad4a0401-4eb8-47ab-a18d-a85643544d73", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "accountId": { + "name": "accountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerId": { + "name": "providerId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "accessToken": { + "name": "accessToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "idToken": { + "name": "idToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessTokenExpiresAt": { + "name": "accessTokenExpiresAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "refreshTokenExpiresAt": { + "name": "refreshTokenExpiresAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.anotacoes": { + "name": "anotacoes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "titulo": { + "name": "titulo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "descricao": { + "name": "descricao", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tipo": { + "name": "tipo", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'nota'" + }, + "tasks": { + "name": "tasks", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "arquivada": { + "name": "arquivada", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "anotacoes_user_id_user_id_fk": { + "name": "anotacoes_user_id_user_id_fk", + "tableFrom": "anotacoes", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.antecipacoes_parcelas": { + "name": "antecipacoes_parcelas", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "series_id": { + "name": "series_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "periodo_antecipacao": { + "name": "periodo_antecipacao", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data_antecipacao": { + "name": "data_antecipacao", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "parcelas_antecipadas": { + "name": "parcelas_antecipadas", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "valor_total": { + "name": "valor_total", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true + }, + "qtde_parcelas": { + "name": "qtde_parcelas", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "desconto": { + "name": "desconto", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "lancamento_id": { + "name": "lancamento_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "pagador_id": { + "name": "pagador_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "categoria_id": { + "name": "categoria_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "anotacao": { + "name": "anotacao", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "antecipacoes_parcelas_series_id_idx": { + "name": "antecipacoes_parcelas_series_id_idx", + "columns": [ + { + "expression": "series_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "antecipacoes_parcelas_user_id_idx": { + "name": "antecipacoes_parcelas_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "antecipacoes_parcelas_lancamento_id_lancamentos_id_fk": { + "name": "antecipacoes_parcelas_lancamento_id_lancamentos_id_fk", + "tableFrom": "antecipacoes_parcelas", + "tableTo": "lancamentos", + "columnsFrom": ["lancamento_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "antecipacoes_parcelas_pagador_id_pagadores_id_fk": { + "name": "antecipacoes_parcelas_pagador_id_pagadores_id_fk", + "tableFrom": "antecipacoes_parcelas", + "tableTo": "pagadores", + "columnsFrom": ["pagador_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "antecipacoes_parcelas_categoria_id_categorias_id_fk": { + "name": "antecipacoes_parcelas_categoria_id_categorias_id_fk", + "tableFrom": "antecipacoes_parcelas", + "tableTo": "categorias", + "columnsFrom": ["categoria_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "antecipacoes_parcelas_user_id_user_id_fk": { + "name": "antecipacoes_parcelas_user_id_user_id_fk", + "tableFrom": "antecipacoes_parcelas", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.cartoes": { + "name": "cartoes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "nome": { + "name": "nome", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dt_fechamento": { + "name": "dt_fechamento", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dt_vencimento": { + "name": "dt_vencimento", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "anotacao": { + "name": "anotacao", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "limite": { + "name": "limite", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "bandeira": { + "name": "bandeira", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "conta_id": { + "name": "conta_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "cartoes_user_id_status_idx": { + "name": "cartoes_user_id_status_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "cartoes_user_id_user_id_fk": { + "name": "cartoes_user_id_user_id_fk", + "tableFrom": "cartoes", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "cartoes_conta_id_contas_id_fk": { + "name": "cartoes_conta_id_contas_id_fk", + "tableFrom": "cartoes", + "tableTo": "contas", + "columnsFrom": ["conta_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.categorias": { + "name": "categorias", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "nome": { + "name": "nome", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tipo": { + "name": "tipo", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "icone": { + "name": "icone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "categorias_user_id_type_idx": { + "name": "categorias_user_id_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tipo", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "categorias_user_id_user_id_fk": { + "name": "categorias_user_id_user_id_fk", + "tableFrom": "categorias", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compartilhamentos_pagador": { + "name": "compartilhamentos_pagador", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "pagador_id": { + "name": "pagador_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "shared_with_user_id": { + "name": "shared_with_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'read'" + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "compartilhamentos_pagador_unique": { + "name": "compartilhamentos_pagador_unique", + "columns": [ + { + "expression": "pagador_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "shared_with_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "compartilhamentos_pagador_pagador_id_pagadores_id_fk": { + "name": "compartilhamentos_pagador_pagador_id_pagadores_id_fk", + "tableFrom": "compartilhamentos_pagador", + "tableTo": "pagadores", + "columnsFrom": ["pagador_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compartilhamentos_pagador_shared_with_user_id_user_id_fk": { + "name": "compartilhamentos_pagador_shared_with_user_id_user_id_fk", + "tableFrom": "compartilhamentos_pagador", + "tableTo": "user", + "columnsFrom": ["shared_with_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compartilhamentos_pagador_created_by_user_id_user_id_fk": { + "name": "compartilhamentos_pagador_created_by_user_id_user_id_fk", + "tableFrom": "compartilhamentos_pagador", + "tableTo": "user", + "columnsFrom": ["created_by_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.contas": { + "name": "contas", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "nome": { + "name": "nome", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tipo_conta": { + "name": "tipo_conta", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "anotacao": { + "name": "anotacao", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "saldo_inicial": { + "name": "saldo_inicial", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "excluir_do_saldo": { + "name": "excluir_do_saldo", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "excluir_saldo_inicial_receitas": { + "name": "excluir_saldo_inicial_receitas", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "contas_user_id_status_idx": { + "name": "contas_user_id_status_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "contas_user_id_user_id_fk": { + "name": "contas_user_id_user_id_fk", + "tableFrom": "contas", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.faturas": { + "name": "faturas", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "status_pagamento": { + "name": "status_pagamento", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "periodo": { + "name": "periodo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cartao_id": { + "name": "cartao_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "faturas_user_id_period_idx": { + "name": "faturas_user_id_period_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "periodo", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "faturas_cartao_id_period_idx": { + "name": "faturas_cartao_id_period_idx", + "columns": [ + { + "expression": "cartao_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "periodo", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "faturas_user_id_user_id_fk": { + "name": "faturas_user_id_user_id_fk", + "tableFrom": "faturas", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "faturas_cartao_id_cartoes_id_fk": { + "name": "faturas_cartao_id_cartoes_id_fk", + "tableFrom": "faturas", + "tableTo": "cartoes", + "columnsFrom": ["cartao_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.insights_salvos": { + "name": "insights_salvos", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "period": { + "name": "period", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "insights_salvos_user_period_idx": { + "name": "insights_salvos_user_period_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "period", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "insights_salvos_user_id_user_id_fk": { + "name": "insights_salvos_user_id_user_id_fk", + "tableFrom": "insights_salvos", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lancamentos": { + "name": "lancamentos", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "condicao": { + "name": "condicao", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "nome": { + "name": "nome", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "forma_pagamento": { + "name": "forma_pagamento", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "anotacao": { + "name": "anotacao", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "valor": { + "name": "valor", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true + }, + "data_compra": { + "name": "data_compra", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "tipo_transacao": { + "name": "tipo_transacao", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "qtde_parcela": { + "name": "qtde_parcela", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "periodo": { + "name": "periodo", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parcela_atual": { + "name": "parcela_atual", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "qtde_recorrencia": { + "name": "qtde_recorrencia", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "data_vencimento": { + "name": "data_vencimento", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "dt_pagamento_boleto": { + "name": "dt_pagamento_boleto", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "realizado": { + "name": "realizado", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "dividido": { + "name": "dividido", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "antecipado": { + "name": "antecipado", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "antecipacao_id": { + "name": "antecipacao_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cartao_id": { + "name": "cartao_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "conta_id": { + "name": "conta_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "categoria_id": { + "name": "categoria_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "pagador_id": { + "name": "pagador_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "series_id": { + "name": "series_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "transfer_id": { + "name": "transfer_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "lancamentos_user_id_period_idx": { + "name": "lancamentos_user_id_period_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "periodo", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "lancamentos_user_id_period_type_idx": { + "name": "lancamentos_user_id_period_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "periodo", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tipo_transacao", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "lancamentos_pagador_id_period_idx": { + "name": "lancamentos_pagador_id_period_idx", + "columns": [ + { + "expression": "pagador_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "periodo", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "lancamentos_user_id_purchase_date_idx": { + "name": "lancamentos_user_id_purchase_date_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "data_compra", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "lancamentos_series_id_idx": { + "name": "lancamentos_series_id_idx", + "columns": [ + { + "expression": "series_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "lancamentos_transfer_id_idx": { + "name": "lancamentos_transfer_id_idx", + "columns": [ + { + "expression": "transfer_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "lancamentos_user_id_condition_idx": { + "name": "lancamentos_user_id_condition_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "condicao", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "lancamentos_cartao_id_period_idx": { + "name": "lancamentos_cartao_id_period_idx", + "columns": [ + { + "expression": "cartao_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "periodo", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "lancamentos_antecipacao_id_antecipacoes_parcelas_id_fk": { + "name": "lancamentos_antecipacao_id_antecipacoes_parcelas_id_fk", + "tableFrom": "lancamentos", + "tableTo": "antecipacoes_parcelas", + "columnsFrom": ["antecipacao_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "lancamentos_user_id_user_id_fk": { + "name": "lancamentos_user_id_user_id_fk", + "tableFrom": "lancamentos", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "lancamentos_cartao_id_cartoes_id_fk": { + "name": "lancamentos_cartao_id_cartoes_id_fk", + "tableFrom": "lancamentos", + "tableTo": "cartoes", + "columnsFrom": ["cartao_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "lancamentos_conta_id_contas_id_fk": { + "name": "lancamentos_conta_id_contas_id_fk", + "tableFrom": "lancamentos", + "tableTo": "contas", + "columnsFrom": ["conta_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "lancamentos_categoria_id_categorias_id_fk": { + "name": "lancamentos_categoria_id_categorias_id_fk", + "tableFrom": "lancamentos", + "tableTo": "categorias", + "columnsFrom": ["categoria_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "lancamentos_pagador_id_pagadores_id_fk": { + "name": "lancamentos_pagador_id_pagadores_id_fk", + "tableFrom": "lancamentos", + "tableTo": "pagadores", + "columnsFrom": ["pagador_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.orcamentos": { + "name": "orcamentos", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "valor": { + "name": "valor", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true + }, + "periodo": { + "name": "periodo", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "categoria_id": { + "name": "categoria_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "orcamentos_user_id_period_idx": { + "name": "orcamentos_user_id_period_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "periodo", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "orcamentos_user_id_user_id_fk": { + "name": "orcamentos_user_id_user_id_fk", + "tableFrom": "orcamentos", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "orcamentos_categoria_id_categorias_id_fk": { + "name": "orcamentos_categoria_id_categorias_id_fk", + "tableFrom": "orcamentos", + "tableTo": "categorias", + "columnsFrom": ["categoria_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pagadores": { + "name": "pagadores", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "nome": { + "name": "nome", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "anotacao": { + "name": "anotacao", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_auto_send": { + "name": "is_auto_send", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "share_code": { + "name": "share_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "substr(encode(gen_random_bytes(24), 'base64'), 1, 24)" + }, + "last_mail": { + "name": "last_mail", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "pagadores_share_code_key": { + "name": "pagadores_share_code_key", + "columns": [ + { + "expression": "share_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pagadores_user_id_status_idx": { + "name": "pagadores_user_id_status_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pagadores_user_id_role_idx": { + "name": "pagadores_user_id_role_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "role", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pagadores_user_id_user_id_fk": { + "name": "pagadores_user_id_user_id_fk", + "tableFrom": "pagadores", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.passkey": { + "name": "passkey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "publicKey": { + "name": "publicKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credentialID": { + "name": "credentialID", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "counter": { + "name": "counter", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "deviceType": { + "name": "deviceType", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "backedUp": { + "name": "backedUp", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "transports": { + "name": "transports", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "aaguid": { + "name": "aaguid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "passkey_userId_user_id_fk": { + "name": "passkey_userId_user_id_fk", + "tableFrom": "passkey", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pre_lancamentos": { + "name": "pre_lancamentos", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_app": { + "name": "source_app", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_app_name": { + "name": "source_app_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "original_title": { + "name": "original_title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "original_text": { + "name": "original_text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "notification_timestamp": { + "name": "notification_timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "parsed_name": { + "name": "parsed_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "parsed_amount": { + "name": "parsed_amount", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "lancamento_id": { + "name": "lancamento_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "processed_at": { + "name": "processed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "discarded_at": { + "name": "discarded_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pre_lancamentos_user_id_status_idx": { + "name": "pre_lancamentos_user_id_status_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pre_lancamentos_user_id_created_at_idx": { + "name": "pre_lancamentos_user_id_created_at_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pre_lancamentos_user_id_user_id_fk": { + "name": "pre_lancamentos_user_id_user_id_fk", + "tableFrom": "pre_lancamentos", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pre_lancamentos_lancamento_id_lancamentos_id_fk": { + "name": "pre_lancamentos_lancamento_id_lancamentos_id_fk", + "tableFrom": "pre_lancamentos", + "tableTo": "lancamentos", + "columnsFrom": ["lancamento_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.preferencias_usuario": { + "name": "preferencias_usuario", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "extrato_note_as_column": { + "name": "extrato_note_as_column", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "system_font": { + "name": "system_font", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'ai-sans'" + }, + "money_font": { + "name": "money_font", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'ai-sans'" + }, + "lancamentos_column_order": { + "name": "lancamentos_column_order", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "dashboard_widgets": { + "name": "dashboard_widgets", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "preferencias_usuario_user_id_user_id_fk": { + "name": "preferencias_usuario_user_id_user_id_fk", + "tableFrom": "preferencias_usuario", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "preferencias_usuario_user_id_unique": { + "name": "preferencias_usuario_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "ipAddress": { + "name": "ipAddress", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userAgent": { + "name": "userAgent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tokens_api": { + "name": "tokens_api", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_prefix": { + "name": "token_prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "last_used_ip": { + "name": "last_used_ip", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "tokens_api_user_id_idx": { + "name": "tokens_api_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tokens_api_token_hash_idx": { + "name": "tokens_api_token_hash_idx", + "columns": [ + { + "expression": "token_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "tokens_api_user_id_user_id_fk": { + "name": "tokens_api_user_id_user_id_fk", + "tableFrom": "tokens_api", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/drizzle/meta/0019_snapshot.json b/drizzle/meta/0019_snapshot.json new file mode 100644 index 0000000..e49e0c1 --- /dev/null +++ b/drizzle/meta/0019_snapshot.json @@ -0,0 +1,2398 @@ +{ + "id": "0d4a9f38-7438-418e-956f-a8d1cf8e8993", + "prevId": "853b7f42-7b0e-43a6-8665-918ec5ec6608", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "accountId": { + "name": "accountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerId": { + "name": "providerId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "accessToken": { + "name": "accessToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "idToken": { + "name": "idToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessTokenExpiresAt": { + "name": "accessTokenExpiresAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "refreshTokenExpiresAt": { + "name": "refreshTokenExpiresAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.anotacoes": { + "name": "anotacoes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "titulo": { + "name": "titulo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "descricao": { + "name": "descricao", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tipo": { + "name": "tipo", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'nota'" + }, + "tasks": { + "name": "tasks", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "arquivada": { + "name": "arquivada", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "anotacoes_user_id_user_id_fk": { + "name": "anotacoes_user_id_user_id_fk", + "tableFrom": "anotacoes", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.antecipacoes_parcelas": { + "name": "antecipacoes_parcelas", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "series_id": { + "name": "series_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "periodo_antecipacao": { + "name": "periodo_antecipacao", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data_antecipacao": { + "name": "data_antecipacao", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "parcelas_antecipadas": { + "name": "parcelas_antecipadas", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "valor_total": { + "name": "valor_total", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true + }, + "qtde_parcelas": { + "name": "qtde_parcelas", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "desconto": { + "name": "desconto", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "lancamento_id": { + "name": "lancamento_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "pagador_id": { + "name": "pagador_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "categoria_id": { + "name": "categoria_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "anotacao": { + "name": "anotacao", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "antecipacoes_parcelas_series_id_idx": { + "name": "antecipacoes_parcelas_series_id_idx", + "columns": [ + { + "expression": "series_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "antecipacoes_parcelas_user_id_idx": { + "name": "antecipacoes_parcelas_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "antecipacoes_parcelas_lancamento_id_lancamentos_id_fk": { + "name": "antecipacoes_parcelas_lancamento_id_lancamentos_id_fk", + "tableFrom": "antecipacoes_parcelas", + "tableTo": "lancamentos", + "columnsFrom": ["lancamento_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "antecipacoes_parcelas_pagador_id_pagadores_id_fk": { + "name": "antecipacoes_parcelas_pagador_id_pagadores_id_fk", + "tableFrom": "antecipacoes_parcelas", + "tableTo": "pagadores", + "columnsFrom": ["pagador_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "antecipacoes_parcelas_categoria_id_categorias_id_fk": { + "name": "antecipacoes_parcelas_categoria_id_categorias_id_fk", + "tableFrom": "antecipacoes_parcelas", + "tableTo": "categorias", + "columnsFrom": ["categoria_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "antecipacoes_parcelas_user_id_user_id_fk": { + "name": "antecipacoes_parcelas_user_id_user_id_fk", + "tableFrom": "antecipacoes_parcelas", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.cartoes": { + "name": "cartoes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "nome": { + "name": "nome", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dt_fechamento": { + "name": "dt_fechamento", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dt_vencimento": { + "name": "dt_vencimento", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "anotacao": { + "name": "anotacao", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "limite": { + "name": "limite", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "bandeira": { + "name": "bandeira", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "conta_id": { + "name": "conta_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "cartoes_user_id_status_idx": { + "name": "cartoes_user_id_status_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "cartoes_user_id_user_id_fk": { + "name": "cartoes_user_id_user_id_fk", + "tableFrom": "cartoes", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "cartoes_conta_id_contas_id_fk": { + "name": "cartoes_conta_id_contas_id_fk", + "tableFrom": "cartoes", + "tableTo": "contas", + "columnsFrom": ["conta_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.categorias": { + "name": "categorias", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "nome": { + "name": "nome", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tipo": { + "name": "tipo", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "icone": { + "name": "icone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "categorias_user_id_type_idx": { + "name": "categorias_user_id_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tipo", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "categorias_user_id_user_id_fk": { + "name": "categorias_user_id_user_id_fk", + "tableFrom": "categorias", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compartilhamentos_pagador": { + "name": "compartilhamentos_pagador", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "pagador_id": { + "name": "pagador_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "shared_with_user_id": { + "name": "shared_with_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'read'" + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "compartilhamentos_pagador_unique": { + "name": "compartilhamentos_pagador_unique", + "columns": [ + { + "expression": "pagador_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "shared_with_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "compartilhamentos_pagador_pagador_id_pagadores_id_fk": { + "name": "compartilhamentos_pagador_pagador_id_pagadores_id_fk", + "tableFrom": "compartilhamentos_pagador", + "tableTo": "pagadores", + "columnsFrom": ["pagador_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compartilhamentos_pagador_shared_with_user_id_user_id_fk": { + "name": "compartilhamentos_pagador_shared_with_user_id_user_id_fk", + "tableFrom": "compartilhamentos_pagador", + "tableTo": "user", + "columnsFrom": ["shared_with_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compartilhamentos_pagador_created_by_user_id_user_id_fk": { + "name": "compartilhamentos_pagador_created_by_user_id_user_id_fk", + "tableFrom": "compartilhamentos_pagador", + "tableTo": "user", + "columnsFrom": ["created_by_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.contas": { + "name": "contas", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "nome": { + "name": "nome", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tipo_conta": { + "name": "tipo_conta", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "anotacao": { + "name": "anotacao", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "saldo_inicial": { + "name": "saldo_inicial", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "excluir_do_saldo": { + "name": "excluir_do_saldo", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "excluir_saldo_inicial_receitas": { + "name": "excluir_saldo_inicial_receitas", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "contas_user_id_status_idx": { + "name": "contas_user_id_status_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "contas_user_id_user_id_fk": { + "name": "contas_user_id_user_id_fk", + "tableFrom": "contas", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.faturas": { + "name": "faturas", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "status_pagamento": { + "name": "status_pagamento", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "periodo": { + "name": "periodo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cartao_id": { + "name": "cartao_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "faturas_user_id_period_idx": { + "name": "faturas_user_id_period_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "periodo", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "faturas_cartao_id_period_idx": { + "name": "faturas_cartao_id_period_idx", + "columns": [ + { + "expression": "cartao_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "periodo", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "faturas_user_id_user_id_fk": { + "name": "faturas_user_id_user_id_fk", + "tableFrom": "faturas", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "faturas_cartao_id_cartoes_id_fk": { + "name": "faturas_cartao_id_cartoes_id_fk", + "tableFrom": "faturas", + "tableTo": "cartoes", + "columnsFrom": ["cartao_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.insights_salvos": { + "name": "insights_salvos", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "period": { + "name": "period", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "insights_salvos_user_period_idx": { + "name": "insights_salvos_user_period_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "period", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "insights_salvos_user_id_user_id_fk": { + "name": "insights_salvos_user_id_user_id_fk", + "tableFrom": "insights_salvos", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lancamentos": { + "name": "lancamentos", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "condicao": { + "name": "condicao", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "nome": { + "name": "nome", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "forma_pagamento": { + "name": "forma_pagamento", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "anotacao": { + "name": "anotacao", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "valor": { + "name": "valor", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true + }, + "data_compra": { + "name": "data_compra", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "tipo_transacao": { + "name": "tipo_transacao", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "qtde_parcela": { + "name": "qtde_parcela", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "periodo": { + "name": "periodo", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parcela_atual": { + "name": "parcela_atual", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "qtde_recorrencia": { + "name": "qtde_recorrencia", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "data_vencimento": { + "name": "data_vencimento", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "dt_pagamento_boleto": { + "name": "dt_pagamento_boleto", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "realizado": { + "name": "realizado", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "dividido": { + "name": "dividido", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "antecipado": { + "name": "antecipado", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "antecipacao_id": { + "name": "antecipacao_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cartao_id": { + "name": "cartao_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "conta_id": { + "name": "conta_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "categoria_id": { + "name": "categoria_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "pagador_id": { + "name": "pagador_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "series_id": { + "name": "series_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "transfer_id": { + "name": "transfer_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "recurring_series_id": { + "name": "recurring_series_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "lancamentos_user_id_period_idx": { + "name": "lancamentos_user_id_period_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "periodo", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "lancamentos_user_id_period_type_idx": { + "name": "lancamentos_user_id_period_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "periodo", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tipo_transacao", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "lancamentos_pagador_id_period_idx": { + "name": "lancamentos_pagador_id_period_idx", + "columns": [ + { + "expression": "pagador_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "periodo", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "lancamentos_user_id_purchase_date_idx": { + "name": "lancamentos_user_id_purchase_date_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "data_compra", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "lancamentos_series_id_idx": { + "name": "lancamentos_series_id_idx", + "columns": [ + { + "expression": "series_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "lancamentos_transfer_id_idx": { + "name": "lancamentos_transfer_id_idx", + "columns": [ + { + "expression": "transfer_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "lancamentos_user_id_condition_idx": { + "name": "lancamentos_user_id_condition_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "condicao", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "lancamentos_cartao_id_period_idx": { + "name": "lancamentos_cartao_id_period_idx", + "columns": [ + { + "expression": "cartao_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "periodo", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "lancamentos_antecipacao_id_antecipacoes_parcelas_id_fk": { + "name": "lancamentos_antecipacao_id_antecipacoes_parcelas_id_fk", + "tableFrom": "lancamentos", + "tableTo": "antecipacoes_parcelas", + "columnsFrom": ["antecipacao_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "lancamentos_user_id_user_id_fk": { + "name": "lancamentos_user_id_user_id_fk", + "tableFrom": "lancamentos", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "lancamentos_cartao_id_cartoes_id_fk": { + "name": "lancamentos_cartao_id_cartoes_id_fk", + "tableFrom": "lancamentos", + "tableTo": "cartoes", + "columnsFrom": ["cartao_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "lancamentos_conta_id_contas_id_fk": { + "name": "lancamentos_conta_id_contas_id_fk", + "tableFrom": "lancamentos", + "tableTo": "contas", + "columnsFrom": ["conta_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "lancamentos_categoria_id_categorias_id_fk": { + "name": "lancamentos_categoria_id_categorias_id_fk", + "tableFrom": "lancamentos", + "tableTo": "categorias", + "columnsFrom": ["categoria_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "lancamentos_pagador_id_pagadores_id_fk": { + "name": "lancamentos_pagador_id_pagadores_id_fk", + "tableFrom": "lancamentos", + "tableTo": "pagadores", + "columnsFrom": ["pagador_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "lancamentos_recurring_series_id_recurring_series_id_fk": { + "name": "lancamentos_recurring_series_id_recurring_series_id_fk", + "tableFrom": "lancamentos", + "tableTo": "recurring_series", + "columnsFrom": ["recurring_series_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.orcamentos": { + "name": "orcamentos", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "valor": { + "name": "valor", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true + }, + "periodo": { + "name": "periodo", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "categoria_id": { + "name": "categoria_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "orcamentos_user_id_period_idx": { + "name": "orcamentos_user_id_period_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "periodo", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "orcamentos_user_id_user_id_fk": { + "name": "orcamentos_user_id_user_id_fk", + "tableFrom": "orcamentos", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "orcamentos_categoria_id_categorias_id_fk": { + "name": "orcamentos_categoria_id_categorias_id_fk", + "tableFrom": "orcamentos", + "tableTo": "categorias", + "columnsFrom": ["categoria_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pagadores": { + "name": "pagadores", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "nome": { + "name": "nome", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "anotacao": { + "name": "anotacao", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_auto_send": { + "name": "is_auto_send", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "share_code": { + "name": "share_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "substr(encode(gen_random_bytes(24), 'base64'), 1, 24)" + }, + "last_mail": { + "name": "last_mail", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "pagadores_share_code_key": { + "name": "pagadores_share_code_key", + "columns": [ + { + "expression": "share_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pagadores_user_id_status_idx": { + "name": "pagadores_user_id_status_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pagadores_user_id_role_idx": { + "name": "pagadores_user_id_role_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "role", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pagadores_user_id_user_id_fk": { + "name": "pagadores_user_id_user_id_fk", + "tableFrom": "pagadores", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.passkey": { + "name": "passkey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "publicKey": { + "name": "publicKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credentialID": { + "name": "credentialID", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "counter": { + "name": "counter", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "deviceType": { + "name": "deviceType", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "backedUp": { + "name": "backedUp", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "transports": { + "name": "transports", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "aaguid": { + "name": "aaguid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "passkey_userId_user_id_fk": { + "name": "passkey_userId_user_id_fk", + "tableFrom": "passkey", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pre_lancamentos": { + "name": "pre_lancamentos", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_app": { + "name": "source_app", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_app_name": { + "name": "source_app_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "original_title": { + "name": "original_title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "original_text": { + "name": "original_text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "notification_timestamp": { + "name": "notification_timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "parsed_name": { + "name": "parsed_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "parsed_amount": { + "name": "parsed_amount", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "lancamento_id": { + "name": "lancamento_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "processed_at": { + "name": "processed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "discarded_at": { + "name": "discarded_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pre_lancamentos_user_id_status_idx": { + "name": "pre_lancamentos_user_id_status_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pre_lancamentos_user_id_created_at_idx": { + "name": "pre_lancamentos_user_id_created_at_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pre_lancamentos_user_id_user_id_fk": { + "name": "pre_lancamentos_user_id_user_id_fk", + "tableFrom": "pre_lancamentos", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pre_lancamentos_lancamento_id_lancamentos_id_fk": { + "name": "pre_lancamentos_lancamento_id_lancamentos_id_fk", + "tableFrom": "pre_lancamentos", + "tableTo": "lancamentos", + "columnsFrom": ["lancamento_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.preferencias_usuario": { + "name": "preferencias_usuario", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "extrato_note_as_column": { + "name": "extrato_note_as_column", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "system_font": { + "name": "system_font", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'ai-sans'" + }, + "money_font": { + "name": "money_font", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'ai-sans'" + }, + "lancamentos_column_order": { + "name": "lancamentos_column_order", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "dashboard_widgets": { + "name": "dashboard_widgets", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "preferencias_usuario_user_id_user_id_fk": { + "name": "preferencias_usuario_user_id_user_id_fk", + "tableFrom": "preferencias_usuario", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "preferencias_usuario_user_id_unique": { + "name": "preferencias_usuario_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.recurring_series": { + "name": "recurring_series", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "day_of_month": { + "name": "day_of_month", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "last_generated_period": { + "name": "last_generated_period", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "template_data": { + "name": "template_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "recurring_series_user_id_status_idx": { + "name": "recurring_series_user_id_status_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "recurring_series_user_id_user_id_fk": { + "name": "recurring_series_user_id_user_id_fk", + "tableFrom": "recurring_series", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "ipAddress": { + "name": "ipAddress", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userAgent": { + "name": "userAgent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tokens_api": { + "name": "tokens_api", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_prefix": { + "name": "token_prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "last_used_ip": { + "name": "last_used_ip", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "tokens_api_user_id_idx": { + "name": "tokens_api_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tokens_api_token_hash_idx": { + "name": "tokens_api_token_hash_idx", + "columns": [ + { + "expression": "token_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "tokens_api_user_id_user_id_fk": { + "name": "tokens_api_user_id_user_id_fk", + "tableFrom": "tokens_api", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 49c3512..35983b6 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -1,139 +1,146 @@ { - "version": "7", - "dialect": "postgresql", - "entries": [ - { - "idx": 0, - "version": "7", - "when": 1762993507299, - "tag": "0000_flashy_manta", - "breakpoints": true - }, - { - "idx": 1, - "version": "7", - "when": 1765199006435, - "tag": "0001_young_mister_fear", - "breakpoints": true - }, - { - "idx": 2, - "version": "7", - "when": 1765200545692, - "tag": "0002_slimy_flatman", - "breakpoints": true - }, - { - "idx": 3, - "version": "7", - "when": 1767102605526, - "tag": "0003_green_korg", - "breakpoints": true - }, - { - "idx": 4, - "version": "7", - "when": 1767104066872, - "tag": "0004_acoustic_mach_iv", - "breakpoints": true - }, - { - "idx": 5, - "version": "7", - "when": 1767106121811, - "tag": "0005_adorable_bruce_banner", - "breakpoints": true - }, - { - "idx": 6, - "version": "7", - "when": 1767107487318, - "tag": "0006_youthful_mister_fear", - "breakpoints": true - }, - { - "idx": 7, - "version": "7", - "when": 1767118780033, - "tag": "0007_sturdy_kate_bishop", - "breakpoints": true - }, - { - "idx": 8, - "version": "7", - "when": 1767125796314, - "tag": "0008_fat_stick", - "breakpoints": true - }, - { - "idx": 9, - "version": "7", - "when": 1768925100873, - "tag": "0009_add_dashboard_widgets", - "breakpoints": true - }, - { - "idx": 10, - "version": "7", - "when": 1769369834242, - "tag": "0010_lame_psynapse", - "breakpoints": true - }, - { - "idx": 11, - "version": "7", - "when": 1769447087678, - "tag": "0011_remove_unused_inbox_columns", - "breakpoints": true - }, - { - "idx": 12, - "version": "7", - "when": 1769533200000, - "tag": "0012_rename_tables_to_portuguese", - "breakpoints": true - }, - { - "idx": 13, - "version": "7", - "when": 1769523352777, - "tag": "0013_fancy_rick_jones", - "breakpoints": true - }, - { - "idx": 14, - "version": "7", - "when": 1769619226903, - "tag": "0014_yielding_jack_flag", - "breakpoints": true - }, - { - "idx": 15, - "version": "7", - "when": 1770332054481, - "tag": "0015_concerned_kat_farrell", - "breakpoints": true - }, - { - "idx": 16, - "version": "7", - "when": 1771166328908, - "tag": "0016_complete_randall", - "breakpoints": true - }, - { - "idx": 17, - "version": "7", - "when": 1772400510326, - "tag": "0017_previous_warstar", - "breakpoints": true - }, - { - "idx": 18, - "version": "7", - "when": 1773020417482, - "tag": "0018_rainy_epoch", - "breakpoints": true - } - ] -} \ No newline at end of file + "version": "7", + "dialect": "postgresql", + "entries": [ + { + "idx": 0, + "version": "7", + "when": 1762993507299, + "tag": "0000_flashy_manta", + "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1765199006435, + "tag": "0001_young_mister_fear", + "breakpoints": true + }, + { + "idx": 2, + "version": "7", + "when": 1765200545692, + "tag": "0002_slimy_flatman", + "breakpoints": true + }, + { + "idx": 3, + "version": "7", + "when": 1767102605526, + "tag": "0003_green_korg", + "breakpoints": true + }, + { + "idx": 4, + "version": "7", + "when": 1767104066872, + "tag": "0004_acoustic_mach_iv", + "breakpoints": true + }, + { + "idx": 5, + "version": "7", + "when": 1767106121811, + "tag": "0005_adorable_bruce_banner", + "breakpoints": true + }, + { + "idx": 6, + "version": "7", + "when": 1767107487318, + "tag": "0006_youthful_mister_fear", + "breakpoints": true + }, + { + "idx": 7, + "version": "7", + "when": 1767118780033, + "tag": "0007_sturdy_kate_bishop", + "breakpoints": true + }, + { + "idx": 8, + "version": "7", + "when": 1767125796314, + "tag": "0008_fat_stick", + "breakpoints": true + }, + { + "idx": 9, + "version": "7", + "when": 1768925100873, + "tag": "0009_add_dashboard_widgets", + "breakpoints": true + }, + { + "idx": 10, + "version": "7", + "when": 1769369834242, + "tag": "0010_lame_psynapse", + "breakpoints": true + }, + { + "idx": 11, + "version": "7", + "when": 1769447087678, + "tag": "0011_remove_unused_inbox_columns", + "breakpoints": true + }, + { + "idx": 12, + "version": "7", + "when": 1769533200000, + "tag": "0012_rename_tables_to_portuguese", + "breakpoints": true + }, + { + "idx": 13, + "version": "7", + "when": 1769523352777, + "tag": "0013_fancy_rick_jones", + "breakpoints": true + }, + { + "idx": 14, + "version": "7", + "when": 1769619226903, + "tag": "0014_yielding_jack_flag", + "breakpoints": true + }, + { + "idx": 15, + "version": "7", + "when": 1770332054481, + "tag": "0015_concerned_kat_farrell", + "breakpoints": true + }, + { + "idx": 16, + "version": "7", + "when": 1771166328908, + "tag": "0016_complete_randall", + "breakpoints": true + }, + { + "idx": 17, + "version": "7", + "when": 1772400510326, + "tag": "0017_previous_warstar", + "breakpoints": true + }, + { + "idx": 18, + "version": "7", + "when": 1773020417482, + "tag": "0018_rainy_epoch", + "breakpoints": true + }, + { + "idx": 19, + "version": "7", + "when": 1773265586360, + "tag": "0019_parched_mephistopheles", + "breakpoints": true + } + ] +} diff --git a/lib/types/index.ts b/lib/types/index.ts deleted file mode 100644 index 9baf5ee..0000000 --- a/lib/types/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./actions"; -export * from "./calendario"; -export * from "./relatorios"; diff --git a/next.config.ts b/next.config.ts index f360909..34c8e03 100644 --- a/next.config.ts +++ b/next.config.ts @@ -19,6 +19,85 @@ const nextConfig: NextConfig = { devIndicators: { position: "bottom-right", }, + async redirects() { + return [ + { source: "/ajustes", destination: "/settings", permanent: true }, + { source: "/anotacoes", destination: "/notes", permanent: true }, + { source: "/calendario", destination: "/calendar", permanent: true }, + { source: "/cartoes", destination: "/cards", permanent: true }, + { + source: "/accounts/:accountId/extrato", + destination: "/accounts/:accountId/statement", + permanent: true, + }, + { + source: "/cartoes/:cartaoId/fatura", + destination: "/cards/:cartaoId/invoice", + permanent: true, + }, + { + source: "/cards/:cardId/fatura", + destination: "/cards/:cardId/invoice", + permanent: true, + }, + { + source: "/categorias/historico", + destination: "/categories/history", + permanent: true, + }, + { + source: "/categorias/:categoryId", + destination: "/categories/:categoryId", + permanent: true, + }, + { source: "/categorias", destination: "/categories", permanent: true }, + { source: "/contas", destination: "/accounts", permanent: true }, + { + source: "/contas/:contaId/extrato", + destination: "/accounts/:contaId/statement", + permanent: true, + }, + { source: "/lancamentos", destination: "/transactions", permanent: true }, + { source: "/orcamentos", destination: "/budgets", permanent: true }, + { source: "/pagadores", destination: "/payers", permanent: true }, + { + source: "/pagadores/:pagadorId", + destination: "/payers/:pagadorId", + permanent: true, + }, + { source: "/pre-lancamentos", destination: "/inbox", permanent: true }, + { + source: "/relatorios", + destination: "/reports/category-trends", + permanent: true, + }, + { + source: "/relatorios/analise-parcelas", + destination: "/reports/installment-analysis", + permanent: true, + }, + { + source: "/relatorios/estabelecimentos", + destination: "/reports/establishments", + permanent: true, + }, + { + source: "/relatorios/tendencias", + destination: "/reports/category-trends", + permanent: true, + }, + { + source: "/relatorios/uso-cartoes", + destination: "/reports/card-usage", + permanent: true, + }, + { + source: "/changelog", + destination: "/settings/changelog", + permanent: true, + }, + ]; + }, // Headers for Safari compatibility async headers() { return [ diff --git a/package.json b/package.json index d0370f5..5fee50c 100644 --- a/package.json +++ b/package.json @@ -27,14 +27,14 @@ "docker:rebuild": "docker compose up --build --force-recreate" }, "dependencies": { - "@ai-sdk/anthropic": "^3.0.58", - "@ai-sdk/google": "^3.0.43", - "@ai-sdk/openai": "^3.0.41", + "@ai-sdk/anthropic": "^3.0.60", + "@ai-sdk/google": "^3.0.47", + "@ai-sdk/openai": "^3.0.45", "@better-auth/passkey": "^1.5.4", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@openrouter/ai-sdk-provider": "^2.2.3", + "@openrouter/ai-sdk-provider": "^2.2.5", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-avatar": "1.1.11", "@radix-ui/react-checkbox": "1.3.3", @@ -58,8 +58,8 @@ "@tanstack/react-table": "8.21.3", "@vercel/analytics": "^1.6.1", "@vercel/speed-insights": "^1.3.1", - "ai": "^6.0.116", - "better-auth": "1.4.19", + "ai": "^6.0.124", + "better-auth": "1.5.4", "class-variance-authority": "0.7.1", "clsx": "2.1.1", "cmdk": "^1.1.1", @@ -69,12 +69,12 @@ "jspdf-autotable": "^5.0.7", "next": "16.1.6", "next-themes": "0.4.6", - "pg": "8.19.0", + "pg": "8.20.0", "radix-ui": "^1.4.3", "react": "19.2.4", "react-day-picker": "^9.14.0", "react-dom": "19.2.4", - "recharts": "3.7.0", + "recharts": "3.8.0", "resend": "^6.9.3", "sonner": "2.0.7", "tailwind-merge": "3.5.0", @@ -83,9 +83,9 @@ "zod": "4.3.6" }, "devDependencies": { - "@biomejs/biome": "2.4.4", + "@biomejs/biome": "2.4.6", "@tailwindcss/postcss": "4.2.1", - "@types/node": "25.3.2", + "@types/node": "25.4.0", "@types/pg": "^8.18.0", "@types/react": "19.2.14", "@types/react-dom": "19.2.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 18cefd4..91ae335 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,17 +9,17 @@ importers: .: dependencies: '@ai-sdk/anthropic': - specifier: ^3.0.58 - version: 3.0.58(zod@4.3.6) + specifier: ^3.0.60 + version: 3.0.60(zod@4.3.6) '@ai-sdk/google': - specifier: ^3.0.43 - version: 3.0.43(zod@4.3.6) + specifier: ^3.0.47 + version: 3.0.47(zod@4.3.6) '@ai-sdk/openai': - specifier: ^3.0.41 - version: 3.0.41(zod@4.3.6) + specifier: ^3.0.45 + version: 3.0.45(zod@4.3.6) '@better-auth/passkey': specifier: ^1.5.4 - version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-auth@1.4.19(drizzle-kit@0.31.9)(drizzle-orm@0.45.1(@opentelemetry/api@1.9.0)(@types/pg@8.18.0)(kysely@0.28.11)(pg@8.19.0))(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.19.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(better-call@1.3.2(zod@4.3.6))(nanostores@1.1.1) + version: 1.5.4(2e7374db8e52ce6228485ece3f2c95d2) '@dnd-kit/core': specifier: ^6.3.1 version: 6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -30,8 +30,8 @@ importers: specifier: ^3.2.2 version: 3.2.2(react@19.2.4) '@openrouter/ai-sdk-provider': - specifier: ^2.2.3 - version: 2.2.3(ai@6.0.116(zod@4.3.6))(zod@4.3.6) + specifier: ^2.2.5 + version: 2.2.5(ai@6.0.124(zod@4.3.6))(zod@4.3.6) '@radix-ui/react-alert-dialog': specifier: 1.1.15 version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -102,11 +102,11 @@ importers: specifier: ^1.3.1 version: 1.3.1(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) ai: - specifier: ^6.0.116 - version: 6.0.116(zod@4.3.6) + specifier: ^6.0.124 + version: 6.0.124(zod@4.3.6) better-auth: - specifier: 1.4.19 - version: 1.4.19(drizzle-kit@0.31.9)(drizzle-orm@0.45.1(@opentelemetry/api@1.9.0)(@types/pg@8.18.0)(kysely@0.28.11)(pg@8.19.0))(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.19.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: 1.5.4 + version: 1.5.4(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.9)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) class-variance-authority: specifier: 0.7.1 version: 0.7.1 @@ -121,7 +121,7 @@ importers: version: 4.1.0 drizzle-orm: specifier: 0.45.1 - version: 0.45.1(@opentelemetry/api@1.9.0)(@types/pg@8.18.0)(kysely@0.28.11)(pg@8.19.0) + version: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) jspdf: specifier: ^4.2.0 version: 4.2.0 @@ -135,8 +135,8 @@ importers: specifier: 0.4.6 version: 0.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) pg: - specifier: 8.19.0 - version: 8.19.0 + specifier: 8.20.0 + version: 8.20.0 radix-ui: specifier: ^1.4.3 version: 1.4.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -150,8 +150,8 @@ importers: specifier: 19.2.4 version: 19.2.4(react@19.2.4) recharts: - specifier: 3.7.0 - version: 3.7.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@16.13.1)(react@19.2.4)(redux@5.0.1) + specifier: 3.8.0 + version: 3.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@16.13.1)(react@19.2.4)(redux@5.0.1) resend: specifier: ^6.9.3 version: 6.9.3 @@ -172,14 +172,14 @@ importers: version: 4.3.6 devDependencies: '@biomejs/biome': - specifier: 2.4.4 - version: 2.4.4 + specifier: 2.4.6 + version: 2.4.6 '@tailwindcss/postcss': specifier: 4.2.1 version: 4.2.1 '@types/node': - specifier: 25.3.2 - version: 25.3.2 + specifier: 25.4.0 + version: 25.4.0 '@types/pg': specifier: ^8.18.0 version: 8.18.0 @@ -207,32 +207,32 @@ importers: packages: - '@ai-sdk/anthropic@3.0.58': - resolution: {integrity: sha512-/53SACgmVukO4bkms4dpxpRlYhW8Ct6QZRe6sj1Pi5H00hYhxIrqfiLbZBGxkdRvjsBQeP/4TVGsXgH5rQeb8Q==} + '@ai-sdk/anthropic@3.0.60': + resolution: {integrity: sha512-CoSexBeEEkdMVxUbikH4mqIzC3hhxZr2TcisaCmVqozsh+cNmMa0d3J2wJxDw2onBQU33t3YGW1n/RhN83Yk4g==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/gateway@3.0.66': - resolution: {integrity: sha512-SIQ0YY0iMuv+07HLsZ+bB990zUJ6S4ujORAh+Jv1V2KGNn73qQKnGO0JBk+w+Res8YqOFSycwDoWcFlQrVxS4A==} + '@ai-sdk/gateway@3.0.71': + resolution: {integrity: sha512-JAsSAiDoV1c/EHKpQu5WSFD9B/U5dB6vmNczZ02nvz4y/0xjIEzV6pLXpqpbA/LWzJ+/YnJz0JSHAoAooYBxFQ==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/google@3.0.43': - resolution: {integrity: sha512-NGCgP5g8HBxrNdxvF8Dhww+UKfqAkZAmyYBvbu9YLoBkzAmGKDBGhVptN/oXPB5Vm0jggMdoLycZ8JReQM8Zqg==} + '@ai-sdk/google@3.0.47': + resolution: {integrity: sha512-lt8KdVwa4jTj82dgI8wsWDUQeVcLmgUcbKYEuHkGFnGDLQSbeHW1MWVFbm9x1278YJkGBJviVj4yDRg4pEUAOQ==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai@3.0.41': - resolution: {integrity: sha512-IZ42A+FO+vuEQCVNqlnAPYQnnUpUfdJIwn1BEDOBywiEHa23fw7PahxVtlX9zm3/zMvTW4JKPzWyvAgDu+SQ2A==} + '@ai-sdk/openai@3.0.45': + resolution: {integrity: sha512-bHOw3E73pxo4D/dZUXk7zwmlofq2nURYlK1dSAy/CI+t6btVhr/BXbElAR7yst6P8Ukqy5GfFlFfsru5p6YSig==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider-utils@4.0.19': - resolution: {integrity: sha512-3eG55CrSWCu2SXlqq2QCsFjo3+E7+Gmg7i/oRVoSZzIodTuDSfLb3MRje67xE9RFea73Zao7Lm4mADIfUETKGg==} + '@ai-sdk/provider-utils@4.0.20': + resolution: {integrity: sha512-gpUIj9uDhIGbuo9afKEgQ074BWmhvK4THJAAeBjRnroTy2yQYo6rbtGD7pQDMZM8ouXPYmT/SCdkWVJ0KcpX8A==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -261,16 +261,6 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@better-auth/core@1.4.19': - resolution: {integrity: sha512-uADLHG1jc5BnEJi7f6ijUN5DmPPRSj++7m/G19z3UqA3MVCo4Y4t1MMa4IIxLCqGDFv22drdfxescgW+HnIowA==} - peerDependencies: - '@better-auth/utils': 0.3.0 - '@better-fetch/fetch': 1.1.21 - better-call: 1.1.8 - jose: ^6.1.0 - kysely: ^0.28.5 - nanostores: ^1.0.1 - '@better-auth/core@1.5.4': resolution: {integrity: sha512-k5AdwPRQETZn0vdB60EB9CDxxfllpJXKqVxTjyXIUSRz7delNGlU0cR/iRP3VfVJwvYR1NbekphBDNo+KGoEzQ==} peerDependencies: @@ -285,6 +275,33 @@ packages: '@cloudflare/workers-types': optional: true + '@better-auth/drizzle-adapter@1.5.4': + resolution: {integrity: sha512-4M4nMAWrDd3TmpV6dONkJjybBVKRZghe5Oj0NNyDEoXubxastQdO7Sb5B54I1rTx5yoMgsqaB+kbJnu/9UgjQg==} + peerDependencies: + '@better-auth/core': 1.5.4 + '@better-auth/utils': ^0.3.0 + drizzle-orm: '>=0.41.0' + + '@better-auth/kysely-adapter@1.5.4': + resolution: {integrity: sha512-DPww7rIfz6Ed7dZlJSW9xMQ42VKaJLB5Cs+pPqd+UHKRyighKjf3VgvMIcAdFPc4olQ0qRHo3+ZJhFlBCxRhxA==} + peerDependencies: + '@better-auth/core': 1.5.4 + '@better-auth/utils': ^0.3.0 + kysely: ^0.27.0 || ^0.28.0 + + '@better-auth/memory-adapter@1.5.4': + resolution: {integrity: sha512-iiWYut9rbQqiAsgRBtj6+nxanwjapxRgpIJbiS2o81h7b9iclE0AiDA0Foes590gdFQvskNauZcCpuF8ytxthg==} + peerDependencies: + '@better-auth/core': 1.5.4 + '@better-auth/utils': ^0.3.0 + + '@better-auth/mongo-adapter@1.5.4': + resolution: {integrity: sha512-ArzJN5Obk6i6+vLK1HpPzLIcsjxZYXPPUvxVU8eyU5HyoUT2MlswWfPQ8UJAKPn0iq/T4PVp/wZcQMhWk1tuNA==} + peerDependencies: + '@better-auth/core': 1.5.4 + '@better-auth/utils': ^0.3.0 + mongodb: ^6.0.0 || ^7.0.0 + '@better-auth/passkey@1.5.4': resolution: {integrity: sha512-S6MRo8TNz7d77H4EoQxaY7EdlQUOeQb02dxqj0xXlA5Jzyb75QrkDghebFasxVRzq7N6INuFbFoxawrlGa4UmQ==} peerDependencies: @@ -295,13 +312,18 @@ packages: better-call: 1.3.2 nanostores: ^1.0.1 - '@better-auth/telemetry@1.4.19': - resolution: {integrity: sha512-ApGNS7olCTtDpKF8Ow3Z+jvFAirOj7c4RyFUpu8axklh3mH57ndpfUAUjhgA8UVoaaH/mnm/Tl884BlqiewLyw==} + '@better-auth/prisma-adapter@1.5.4': + resolution: {integrity: sha512-ZQTbcBopw/ezjjbNFsfR3CRp0QciC4tJCarAnB5G9fZtUYbDjfY0vZOxIRmU4kI3x755CXQpGqTrkwmXaMRa3w==} peerDependencies: - '@better-auth/core': 1.4.19 + '@better-auth/core': 1.5.4 + '@better-auth/utils': ^0.3.0 + '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 + prisma: ^5.0.0 || ^6.0.0 || ^7.0.0 - '@better-auth/utils@0.3.0': - resolution: {integrity: sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw==} + '@better-auth/telemetry@1.5.4': + resolution: {integrity: sha512-mGXTY7Ecxo7uvlMr6TFCBUvlH0NUMOeE9LKgPhG4HyhBN6VfCEg/DD9PG0Z2IatmMWQbckkt7ox5A0eBpG9m5w==} + peerDependencies: + '@better-auth/core': 1.5.4 '@better-auth/utils@0.3.1': resolution: {integrity: sha512-+CGp4UmZSUrHHnpHhLPYu6cV+wSUSvVbZbNykxhUDocpVNTo9uFFxw/NqJlh1iC4wQ9HKKWGCKuZ5wUgS0v6Kg==} @@ -309,63 +331,75 @@ packages: '@better-fetch/fetch@1.1.21': resolution: {integrity: sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A==} - '@biomejs/biome@2.4.4': - resolution: {integrity: sha512-tigwWS5KfJf0cABVd52NVaXyAVv4qpUXOWJ1rxFL8xF1RVoeS2q/LK+FHgYoKMclJCuRoCWAPy1IXaN9/mS61Q==} + '@biomejs/biome@2.4.6': + resolution: {integrity: sha512-QnHe81PMslpy3mnpL8DnO2M4S4ZnYPkjlGCLWBZT/3R9M6b5daArWMMtEfP52/n174RKnwRIf3oT8+wc9ihSfQ==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.4.4': - resolution: {integrity: sha512-jZ+Xc6qvD6tTH5jM6eKX44dcbyNqJHssfl2nnwT6vma6B1sj7ZLTGIk6N5QwVBs5xGN52r3trk5fgd3sQ9We9A==} + '@biomejs/cli-darwin-arm64@2.4.6': + resolution: {integrity: sha512-NW18GSyxr+8sJIqgoGwVp5Zqm4SALH4b4gftIA0n62PTuBs6G2tHlwNAOj0Vq0KKSs7Sf88VjjmHh0O36EnzrQ==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.4.4': - resolution: {integrity: sha512-Dh1a/+W+SUCXhEdL7TiX3ArPTFCQKJTI1mGncZNWfO+6suk+gYA4lNyJcBB+pwvF49uw0pEbUS49BgYOY4hzUg==} + '@biomejs/cli-darwin-x64@2.4.6': + resolution: {integrity: sha512-4uiE/9tuI7cnjtY9b07RgS7gGyYOAfIAGeVJWEfeCnAarOAS7qVmuRyX6d7JTKw28/mt+rUzMasYeZ+0R/U1Mw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.4.4': - resolution: {integrity: sha512-+sPAXq3bxmFwhVFJnSwkSF5Rw2ZAJMH3MF6C9IveAEOdSpgajPhoQhbbAK12SehN9j2QrHpk4J/cHsa/HqWaYQ==} + '@biomejs/cli-linux-arm64-musl@2.4.6': + resolution: {integrity: sha512-F/JdB7eN22txiTqHM5KhIVt0jVkzZwVYrdTR1O3Y4auBOQcXxHK4dxULf4z43QyZI5tsnQJrRBHZy7wwtL+B3A==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] libc: [musl] - '@biomejs/cli-linux-arm64@2.4.4': - resolution: {integrity: sha512-V/NFfbWhsUU6w+m5WYbBenlEAz8eYnSqRMDMAW3K+3v0tYVkNyZn8VU0XPxk/lOqNXLSCCrV7FmV/u3SjCBShg==} + '@biomejs/cli-linux-arm64@2.4.6': + resolution: {integrity: sha512-kMLaI7OF5GN1Q8Doymjro1P8rVEoy7BKQALNz6fiR8IC1WKduoNyteBtJlHT7ASIL0Cx2jR6VUOBIbcB1B8pew==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] libc: [glibc] - '@biomejs/cli-linux-x64-musl@2.4.4': - resolution: {integrity: sha512-gGvFTGpOIQDb5CQ2VC0n9Z2UEqlP46c4aNgHmAMytYieTGEcfqhfCFnhs6xjt0S3igE6q5GLuIXtdQt3Izok+g==} + '@biomejs/cli-linux-x64-musl@2.4.6': + resolution: {integrity: sha512-C9s98IPDu7DYarjlZNuzJKTjVHN03RUnmHV5htvqsx6vEUXCDSJ59DNwjKVD5XYoSS4N+BYhq3RTBAL8X6svEg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] libc: [musl] - '@biomejs/cli-linux-x64@2.4.4': - resolution: {integrity: sha512-R4+ZCDtG9kHArasyBO+UBD6jr/FcFCTH8QkNTOCu0pRJzCWyWC4EtZa2AmUZB5h3e0jD7bRV2KvrENcf8rndBg==} + '@biomejs/cli-linux-x64@2.4.6': + resolution: {integrity: sha512-oHXmUFEoH8Lql1xfc3QkFLiC1hGR7qedv5eKNlC185or+o4/4HiaU7vYODAH3peRCfsuLr1g6v2fK9dFFOYdyw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] libc: [glibc] - '@biomejs/cli-win32-arm64@2.4.4': - resolution: {integrity: sha512-trzCqM7x+Gn832zZHgr28JoYagQNX4CZkUZhMUac2YxvvyDRLJDrb5m9IA7CaZLlX6lTQmADVfLEKP1et1Ma4Q==} + '@biomejs/cli-win32-arm64@2.4.6': + resolution: {integrity: sha512-xzThn87Pf3YrOGTEODFGONmqXpTwUNxovQb72iaUOdcw8sBSY3+3WD8Hm9IhMYLnPi0n32s3L3NWU6+eSjfqFg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.4.4': - resolution: {integrity: sha512-gnOHKVPFAAPrpoPt2t+Q6FZ7RPry/FDV3GcpU53P3PtLNnQjBmKyN2Vh/JtqXet+H4pme8CC76rScwdjDcT1/A==} + '@biomejs/cli-win32-x64@2.4.6': + resolution: {integrity: sha512-7++XhnsPlr1HDbor5amovPjOH6vsrFOCdp93iKXhFn6bcMUI6soodj3WWKfgEO6JosKU1W5n3uky3WW9RlRjTg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] + '@chevrotain/cst-dts-gen@10.5.0': + resolution: {integrity: sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==} + + '@chevrotain/gast@10.5.0': + resolution: {integrity: sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A==} + + '@chevrotain/types@10.5.0': + resolution: {integrity: sha512-f1MAia0x/pAVPWH/T73BJVyO2XU5tI4/iE7cnxb7tqdNTNhQI3Uq3XkqcoteTmD4t1aM0LbHCJOhgIDn07kl2A==} + + '@chevrotain/utils@10.5.0': + resolution: {integrity: sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==} + '@date-fns/tz@1.4.1': resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==} @@ -394,6 +428,20 @@ packages: '@drizzle-team/brocli@0.10.2': resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} + '@electric-sql/pglite-socket@0.0.20': + resolution: {integrity: sha512-J5nLGsicnD9wJHnno9r+DGxfcZWh+YJMCe0q/aCgtG6XOm9Z7fKeite8IZSNXgZeGltSigM9U/vAWZQWdgcSFg==} + hasBin: true + peerDependencies: + '@electric-sql/pglite': 0.3.15 + + '@electric-sql/pglite-tools@0.2.20': + resolution: {integrity: sha512-BK50ZnYa3IG7ztXhtgYf0Q7zijV32Iw1cYS8C+ThdQlwx12V5VZ9KRJ42y82Hyb4PkTxZQklVQA9JHyUlex33A==} + peerDependencies: + '@electric-sql/pglite': 0.3.15 + + '@electric-sql/pglite@0.3.15': + resolution: {integrity: sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==} + '@emnapi/runtime@1.8.1': resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} @@ -867,6 +915,12 @@ packages: '@hexagon/base64@1.1.28': resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==} + '@hono/node-server@1.19.9': + resolution: {integrity: sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@img/colour@1.1.0': resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} @@ -1039,6 +1093,13 @@ packages: '@levischuck/tiny-cbor@0.2.11': resolution: {integrity: sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==} + '@mongodb-js/saslprep@1.4.6': + resolution: {integrity: sha512-y+x3H1xBZd38n10NZF/rEBlvDOOMQ6LKUTHqr8R9VkJ+mmQOYtJFxIlkkK8fZrtOiL6VixbOBWMbZGBdal3Z1g==} + + '@mrleebo/prisma-ast@0.13.1': + resolution: {integrity: sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw==} + engines: {node: '>=16'} + '@next/env@16.1.6': resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==} @@ -1102,8 +1163,8 @@ packages: resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} engines: {node: '>= 20.19.0'} - '@openrouter/ai-sdk-provider@2.2.3': - resolution: {integrity: sha512-NovC+BaCfEeJwhToDrs8JeDYXXlJdEyz7lcxkjtyePSE4eoAKik872SyDK0MzXKcz8MRkv7XlNhPI6zz4TQp0g==} + '@openrouter/ai-sdk-provider@2.2.5': + resolution: {integrity: sha512-IgM96gPvpxMZYYJQSIuXqvHX0mUXHEvsa/AtIlfb1VK4ek584ydAzc/wf3IuKxNof15o38WZMpCwfsOFHv96Jg==} engines: {node: '>=18'} peerDependencies: ai: ^6.0.0 @@ -1150,6 +1211,58 @@ packages: resolution: {integrity: sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==} engines: {node: '>=20.0.0'} + '@prisma/client-runtime-utils@7.4.2': + resolution: {integrity: sha512-cID+rzOEb38VyMsx5LwJMEY4NGIrWCNpKu/0ImbeooQ2Px7TI+kOt7cm0NelxUzF2V41UVVXAmYjANZQtCu1/Q==} + + '@prisma/client@7.4.2': + resolution: {integrity: sha512-ts2mu+cQHriAhSxngO3StcYubBGTWDtu/4juZhXCUKOwgh26l+s4KD3vT2kMUzFyrYnll9u/3qWrtzRv9CGWzA==} + engines: {node: ^20.19 || ^22.12 || >=24.0} + peerDependencies: + prisma: '*' + typescript: '>=5.4.0' + peerDependenciesMeta: + prisma: + optional: true + typescript: + optional: true + + '@prisma/config@7.4.2': + resolution: {integrity: sha512-CftBjWxav99lzY1Z4oDgomdb1gh9BJFAOmWF6P2v1xRfXqQb56DfBub+QKcERRdNoAzCb3HXy3Zii8Vb4AsXhg==} + + '@prisma/debug@7.2.0': + resolution: {integrity: sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==} + + '@prisma/debug@7.4.2': + resolution: {integrity: sha512-aP7qzu+g/JnbF6U69LMwHoUkELiserKmWsE2shYuEpNUJ4GrtxBCvZwCyCBHFSH2kLTF2l1goBlBh4wuvRq62w==} + + '@prisma/dev@0.20.0': + resolution: {integrity: sha512-ovlBYwWor0OzG+yH4J3Ot+AneD818BttLA+Ii7wjbcLHUrnC4tbUPVGyNd3c/+71KETPKZfjhkTSpdS15dmXNQ==} + + '@prisma/engines-version@7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919': + resolution: {integrity: sha512-5FIKY3KoYQlBuZC2yc16EXfVRQ8HY+fLqgxkYfWCtKhRb3ajCRzP/rPeoSx11+NueJDANdh4hjY36mdmrTcGSg==} + + '@prisma/engines@7.4.2': + resolution: {integrity: sha512-B+ZZhI4rXlzjVqRw/93AothEKOU5/x4oVyJFGo9RpHPnBwaPwk4Pi0Q4iGXipKxeXPs/dqljgNBjK0m8nocOJA==} + + '@prisma/fetch-engine@7.4.2': + resolution: {integrity: sha512-f/c/MwYpdJO7taLETU8rahEstLeXfYgQGlz5fycG7Fbmva3iPdzGmjiSWHeSWIgNnlXnelUdCJqyZnFocurZuA==} + + '@prisma/get-platform@7.2.0': + resolution: {integrity: sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==} + + '@prisma/get-platform@7.4.2': + resolution: {integrity: sha512-UTnChXRwiauzl/8wT4hhe7Xmixja9WE28oCnGpBtRejaHhvekx5kudr3R4Y9mLSA0kqGnAMeyTiKwDVMjaEVsw==} + + '@prisma/query-plan-executor@7.2.0': + resolution: {integrity: sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==} + + '@prisma/studio-core@0.13.1': + resolution: {integrity: sha512-agdqaPEePRHcQ7CexEfkX1RvSH9uWDb6pXrZnhCRykhDFAV0/0P3d07WtfiY8hZWb7oRU4v+NkT4cGFHkQJIPg==} + peerDependencies: + '@types/react': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + '@radix-ui/number@1.1.1': resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} @@ -2092,8 +2205,8 @@ packages: '@types/d3-timer@3.0.2': resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} - '@types/node@25.3.2': - resolution: {integrity: sha512-RpV6r/ij22zRRdyBPcxDeKAzH43phWVKEjL2iksqo1Vz3CuBUrgmPpPhALKiRfU7OMCmeeO9vECBMsV0hMTG8Q==} + '@types/node@25.4.0': + resolution: {integrity: sha512-9wLpoeWuBlcbBpOY3XmzSTG3oscB6xjBEEtn+pYXTfhyXhIxC5FsBer2KTopBlvKEiW9l13po9fq+SJY/5lkhw==} '@types/pako@2.0.4': resolution: {integrity: sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==} @@ -2118,6 +2231,12 @@ packages: '@types/use-sync-external-store@0.0.6': resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} + '@types/webidl-conversions@7.0.3': + resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + + '@types/whatwg-url@13.0.0': + resolution: {integrity: sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==} + '@vercel/analytics@1.6.1': resolution: {integrity: sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==} peerDependencies: @@ -2175,8 +2294,8 @@ packages: resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==} engines: {node: '>=0.8'} - ai@6.0.116: - resolution: {integrity: sha512-7yM+cTmyRLeNIXwt4Vj+mrrJgVQ9RMIW5WO0ydoLoYkewIvsMcvUmqS4j2RJTUXaF1HphwmSKUMQ/HypNRGOmA==} + ai@6.0.124: + resolution: {integrity: sha512-YsWyB6BcxKMUAWkWHuF33xxem2dN9W/EDnvai/hr1yPXVdTKVYLHBjijMf1z+ocA66CXsXb2rcakW28I5UCIQg==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -2189,6 +2308,10 @@ packages: resolution: {integrity: sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==} engines: {node: '>=12.0.0'} + aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} + engines: {node: '>= 6.0.0'} + babel-plugin-react-compiler@1.0.0: resolution: {integrity: sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==} @@ -2201,8 +2324,8 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - better-auth@1.4.19: - resolution: {integrity: sha512-3RlZJcA0+NH25wYD85vpIGwW9oSTuEmLIaGbT8zg41w/Pa2hVWHKedjoUHHJtnzkBXzDb+CShkLnSw7IThDdqQ==} + better-auth@1.5.4: + resolution: {integrity: sha512-ReykcEKx6Kp9560jG1wtlDBnftA7L7xb3ZZdDWm5yGXKKe2pUf+oBjH0fqekrkRII0m4XBVQbQ0mOrFv+3FdYg==} peerDependencies: '@lynx-js/react': '*' '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 @@ -2263,14 +2386,6 @@ packages: vue: optional: true - better-call@1.1.8: - resolution: {integrity: sha512-XMQ2rs6FNXasGNfMjzbyroSwKwYbZ/T3IxruSS6U2MJRsSYh3wYtG3o6H00ZlKZ/C/UPOAD97tqgQJNsxyeTXw==} - peerDependencies: - zod: ^4.0.0 - peerDependenciesMeta: - zod: - optional: true - better-call@1.3.2: resolution: {integrity: sha512-4cZIfrerDsNTn3cm+MhLbUePN0gdwkhSXEuG7r/zuQ8c/H7iU0/jSK5TD3FW7U0MgKHce/8jGpPYNO4Ve+4NBw==} peerDependencies: @@ -2279,9 +2394,21 @@ packages: zod: optional: true + bson@7.2.0: + resolution: {integrity: sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==} + engines: {node: '>=20.19.0'} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + c12@3.1.0: + resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==} + peerDependencies: + magicast: ^0.3.5 + peerDependenciesMeta: + magicast: + optional: true + caniuse-lite@1.0.30001777: resolution: {integrity: sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==} @@ -2293,6 +2420,19 @@ packages: resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==} engines: {node: '>=0.8'} + chevrotain@10.5.0: + resolution: {integrity: sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A==} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + + citty@0.2.1: + resolution: {integrity: sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==} + class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} @@ -2313,6 +2453,13 @@ packages: resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==} engines: {node: '>=0.8'} + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + core-js@3.48.0: resolution: {integrity: sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==} @@ -2321,6 +2468,10 @@ packages: engines: {node: '>=0.8'} hasBin: true + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + css-line-break@2.1.0: resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==} @@ -2389,9 +2540,20 @@ packages: decimal.js-light@2.5.1: resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + deepmerge-ts@7.1.5: + resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} + engines: {node: '>=16.0.0'} + defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -2403,6 +2565,10 @@ packages: resolution: {integrity: sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==} engines: {node: '>=20'} + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + dotenv@17.3.1: resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} engines: {node: '>=12'} @@ -2503,6 +2669,13 @@ packages: sqlite3: optional: true + effect@3.18.4: + resolution: {integrity: sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==} + + empathic@2.0.0: + resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} + engines: {node: '>=14'} + enhanced-resolve@5.20.0: resolution: {integrity: sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==} engines: {node: '>=10.13.0'} @@ -2537,6 +2710,13 @@ packages: resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} engines: {node: '>=18.0.0'} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + + fast-check@3.23.2: + resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} + engines: {node: '>=8.0.0'} + fast-png@6.4.0: resolution: {integrity: sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==} @@ -2546,6 +2726,10 @@ packages: fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + frac@1.1.2: resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==} engines: {node: '>=0.8'} @@ -2555,20 +2739,47 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} + get-port-please@3.2.0: + resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} + get-tsconfig@4.13.6: resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} + giget@2.0.0: + resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + hasBin: true + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + grammex@3.1.12: + resolution: {integrity: sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==} + + graphmatch@1.1.1: + resolution: {integrity: sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==} + + hono@4.11.4: + resolution: {integrity: sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==} + engines: {node: '>=16.9.0'} + html2canvas@1.4.1: resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==} engines: {node: '>=8.0.0'} + http-status-codes@2.3.0: + resolution: {integrity: sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==} + + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + immer@10.2.0: resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==} @@ -2582,12 +2793,18 @@ packages: iobuffer@5.4.0: resolution: {integrity: sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==} + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true - jose@6.2.0: - resolution: {integrity: sha512-xsfE1TcSCbUdo6U07tR0mvhg0flGxU8tPLbF03mirl2ukGQENhUg4ubGYQnhVH0b5stLlPM+WOqDkEl1R1y5sQ==} + jose@6.2.1: + resolution: {integrity: sha512-jUaKr1yrbfaImV7R2TN/b3IcZzsw38/chqMpo2XJ7i2F8AfM/lA4G1goC3JVEwg0H7UldTmSt3P68nt31W7/mw==} json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} @@ -2678,12 +2895,68 @@ packages: resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} engines: {node: '>= 12.0.0'} + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + lru.min@1.1.4: + resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + memory-pager@1.5.0: + resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + + mongodb-connection-string-url@7.0.1: + resolution: {integrity: sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==} + engines: {node: '>=20.19.0'} + + mongodb@7.1.0: + resolution: {integrity: sha512-kMfnKunbolQYwCIyrkxNJFB4Ypy91pYqua5NargS/f8ODNSJxT03ZU3n1JqL4mCzbSih8tvmMEMLpKTT7x5gCg==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@aws-sdk/credential-providers': ^3.806.0 + '@mongodb-js/zstd': ^7.0.0 + gcp-metadata: ^7.0.1 + kerberos: ^7.0.0 + mongodb-client-encryption: '>=7.0.0 <7.1.0' + snappy: ^7.3.2 + socks: ^2.8.6 + peerDependenciesMeta: + '@aws-sdk/credential-providers': + optional: true + '@mongodb-js/zstd': + optional: true + gcp-metadata: + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + snappy: + optional: true + socks: + optional: true + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mysql2@3.15.3: + resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==} + engines: {node: '>= 8.0'} + + named-placeholders@1.1.6: + resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} + engines: {node: '>=8.0.0'} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -2720,9 +2993,30 @@ packages: sass: optional: true + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + + nypm@0.6.5: + resolution: {integrity: sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==} + engines: {node: '>=18'} + hasBin: true + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + pako@2.1.0: resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + performance-now@2.1.0: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} @@ -2748,8 +3042,8 @@ packages: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} - pg@8.19.0: - resolution: {integrity: sha512-QIcLGi508BAHkQ3pJNptsFz5WQMlpGbuBGBaIaXsWK8mel2kQ/rThYI+DbgjUvZrIr7MiuEuc9LcChJoEZK1xQ==} + pg@8.20.0: + resolution: {integrity: sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==} engines: {node: '>= 16.0.0'} peerDependencies: pg-native: '>=3.0.1' @@ -2763,6 +3057,9 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + postal-mime@2.7.3: resolution: {integrity: sha512-MjhXadAJaWgYzevi46+3kLak8y6gbg0ku14O1gO/LNOuay8dO+1PtcSGvAdgDR0DoIsSaiIA8y/Ddw6MnrO0Tw==} @@ -2790,6 +3087,33 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} + postgres@3.4.7: + resolution: {integrity: sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==} + engines: {node: '>=12'} + + prisma@7.4.2: + resolution: {integrity: sha512-2bP8Ruww3Q95Z2eH4Yqh4KAENRsj/SxbdknIVBfd6DmjPwmpsC4OVFMLOeHt6tM3Amh8ebjvstrUz3V/hOe1dA==} + engines: {node: ^20.19 || ^22.12 || >=24.0} + hasBin: true + peerDependencies: + better-sqlite3: '>=9.0.0' + typescript: '>=5.4.0' + peerDependenciesMeta: + better-sqlite3: + optional: true + typescript: + optional: true + + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + pvtsutils@1.3.6: resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} @@ -2813,6 +3137,9 @@ packages: raf@3.4.1: resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==} + rc9@2.1.2: + resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + react-day-picker@9.14.0: resolution: {integrity: sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA==} engines: {node: '>=18'} @@ -2873,8 +3200,12 @@ packages: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} - recharts@3.7.0: - resolution: {integrity: sha512-l2VCsy3XXeraxIID9fx23eCb6iCBsxUQDnE8tWm6DFdszVAO7WVY/ChAD9wVit01y6B2PMupYiMmQwhgPHc9Ew==} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + recharts@3.8.0: + resolution: {integrity: sha512-Z/m38DX3L73ExO4Tpc9/iZWHmHnlzWG4njQbxsF5aSjwqmHNDDIm0rdEBArkwsBvR8U6EirlEHiQNYWCVh9sGQ==} engines: {node: '>=18'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -2895,6 +3226,12 @@ packages: regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + regexp-to-ast@0.5.0: + resolution: {integrity: sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==} + + remeda@2.33.4: + resolution: {integrity: sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==} + reselect@5.1.1: resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} @@ -2910,6 +3247,10 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + rgbcolor@1.0.1: resolution: {integrity: sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==} engines: {node: '>= 0.8.15'} @@ -2917,6 +3258,9 @@ packages: rou3@0.7.12: resolution: {integrity: sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -2925,8 +3269,8 @@ packages: engines: {node: '>=10'} hasBin: true - set-cookie-parser@2.7.2: - resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} set-cookie-parser@3.0.1: resolution: {integrity: sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==} @@ -2935,6 +3279,21 @@ packages: resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + sonner@2.0.7: resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} peerDependencies: @@ -2952,10 +3311,17 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + sparse-bitfield@3.0.3: + resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + ssf@0.11.2: resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==} engines: {node: '>=0.8'} @@ -2967,6 +3333,9 @@ packages: standardwebhooks@1.0.0: resolution: {integrity: sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==} + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + styled-jsx@5.1.6: resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} engines: {node: '>= 12.0.0'} @@ -3003,6 +3372,14 @@ packages: tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -3058,6 +3435,14 @@ packages: resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} hasBin: true + valibot@1.2.0: + resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + vaul@1.1.2: resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} peerDependencies: @@ -3067,6 +3452,19 @@ packages: victory-vendor@37.3.6: resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + wmf@1.0.2: resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==} engines: {node: '>=0.8'} @@ -3084,37 +3482,40 @@ packages: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} + zeptomatch@2.1.0: + resolution: {integrity: sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==} + zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} snapshots: - '@ai-sdk/anthropic@3.0.58(zod@4.3.6)': + '@ai-sdk/anthropic@3.0.60(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.19(zod@4.3.6) + '@ai-sdk/provider-utils': 4.0.20(zod@4.3.6) zod: 4.3.6 - '@ai-sdk/gateway@3.0.66(zod@4.3.6)': + '@ai-sdk/gateway@3.0.71(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.19(zod@4.3.6) + '@ai-sdk/provider-utils': 4.0.20(zod@4.3.6) '@vercel/oidc': 3.1.0 zod: 4.3.6 - '@ai-sdk/google@3.0.43(zod@4.3.6)': + '@ai-sdk/google@3.0.47(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.19(zod@4.3.6) + '@ai-sdk/provider-utils': 4.0.20(zod@4.3.6) zod: 4.3.6 - '@ai-sdk/openai@3.0.41(zod@4.3.6)': + '@ai-sdk/openai@3.0.45(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.19(zod@4.3.6) + '@ai-sdk/provider-utils': 4.0.20(zod@4.3.6) zod: 4.3.6 - '@ai-sdk/provider-utils@4.0.19(zod@4.3.6)': + '@ai-sdk/provider-utils@4.0.20(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 '@standard-schema/spec': 1.1.0 @@ -3141,87 +3542,119 @@ snapshots: '@babel/helper-validator-identifier': 7.28.5 optional: true - '@better-auth/core@1.4.19(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1)': - dependencies: - '@better-auth/utils': 0.3.0 - '@better-fetch/fetch': 1.1.21 - '@standard-schema/spec': 1.1.0 - better-call: 1.1.8(zod@4.3.6) - jose: 6.2.0 - kysely: 0.28.11 - nanostores: 1.1.1 - zod: 4.3.6 - - '@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1)': + '@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1)': dependencies: '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 '@standard-schema/spec': 1.1.0 better-call: 1.3.2(zod@4.3.6) - jose: 6.2.0 + jose: 6.2.1 kysely: 0.28.11 nanostores: 1.1.1 zod: 4.3.6 - '@better-auth/passkey@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-auth@1.4.19(drizzle-kit@0.31.9)(drizzle-orm@0.45.1(@opentelemetry/api@1.9.0)(@types/pg@8.18.0)(kysely@0.28.11)(pg@8.19.0))(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.19.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(better-call@1.3.2(zod@4.3.6))(nanostores@1.1.1)': + '@better-auth/drizzle-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))': dependencies: - '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/utils': 0.3.1 + drizzle-orm: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) + + '@better-auth/kysely-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(kysely@0.28.11)': + dependencies: + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/utils': 0.3.1 + kysely: 0.28.11 + + '@better-auth/memory-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)': + dependencies: + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/utils': 0.3.1 + + '@better-auth/mongo-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(mongodb@7.1.0)': + dependencies: + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/utils': 0.3.1 + mongodb: 7.1.0 + + '@better-auth/passkey@1.5.4(2e7374db8e52ce6228485ece3f2c95d2)': + dependencies: + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 '@simplewebauthn/browser': 13.2.2 '@simplewebauthn/server': 13.2.3 - better-auth: 1.4.19(drizzle-kit@0.31.9)(drizzle-orm@0.45.1(@opentelemetry/api@1.9.0)(@types/pg@8.18.0)(kysely@0.28.11)(pg@8.19.0))(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.19.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + better-auth: 1.5.4(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.9)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) better-call: 1.3.2(zod@4.3.6) nanostores: 1.1.1 zod: 4.3.6 - '@better-auth/telemetry@1.4.19(@better-auth/core@1.4.19(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1))': + '@better-auth/prisma-adapter@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))': dependencies: - '@better-auth/core': 1.4.19(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) - '@better-auth/utils': 0.3.0 - '@better-fetch/fetch': 1.1.21 + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/utils': 0.3.1 + '@prisma/client': 7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3) + prisma: 7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) - '@better-auth/utils@0.3.0': {} + '@better-auth/telemetry@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))': + dependencies: + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/utils': 0.3.1 + '@better-fetch/fetch': 1.1.21 '@better-auth/utils@0.3.1': {} '@better-fetch/fetch@1.1.21': {} - '@biomejs/biome@2.4.4': + '@biomejs/biome@2.4.6': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.4.4 - '@biomejs/cli-darwin-x64': 2.4.4 - '@biomejs/cli-linux-arm64': 2.4.4 - '@biomejs/cli-linux-arm64-musl': 2.4.4 - '@biomejs/cli-linux-x64': 2.4.4 - '@biomejs/cli-linux-x64-musl': 2.4.4 - '@biomejs/cli-win32-arm64': 2.4.4 - '@biomejs/cli-win32-x64': 2.4.4 + '@biomejs/cli-darwin-arm64': 2.4.6 + '@biomejs/cli-darwin-x64': 2.4.6 + '@biomejs/cli-linux-arm64': 2.4.6 + '@biomejs/cli-linux-arm64-musl': 2.4.6 + '@biomejs/cli-linux-x64': 2.4.6 + '@biomejs/cli-linux-x64-musl': 2.4.6 + '@biomejs/cli-win32-arm64': 2.4.6 + '@biomejs/cli-win32-x64': 2.4.6 - '@biomejs/cli-darwin-arm64@2.4.4': + '@biomejs/cli-darwin-arm64@2.4.6': optional: true - '@biomejs/cli-darwin-x64@2.4.4': + '@biomejs/cli-darwin-x64@2.4.6': optional: true - '@biomejs/cli-linux-arm64-musl@2.4.4': + '@biomejs/cli-linux-arm64-musl@2.4.6': optional: true - '@biomejs/cli-linux-arm64@2.4.4': + '@biomejs/cli-linux-arm64@2.4.6': optional: true - '@biomejs/cli-linux-x64-musl@2.4.4': + '@biomejs/cli-linux-x64-musl@2.4.6': optional: true - '@biomejs/cli-linux-x64@2.4.4': + '@biomejs/cli-linux-x64@2.4.6': optional: true - '@biomejs/cli-win32-arm64@2.4.4': + '@biomejs/cli-win32-arm64@2.4.6': optional: true - '@biomejs/cli-win32-x64@2.4.4': + '@biomejs/cli-win32-x64@2.4.6': optional: true + '@chevrotain/cst-dts-gen@10.5.0': + dependencies: + '@chevrotain/gast': 10.5.0 + '@chevrotain/types': 10.5.0 + lodash: 4.17.21 + + '@chevrotain/gast@10.5.0': + dependencies: + '@chevrotain/types': 10.5.0 + lodash: 4.17.21 + + '@chevrotain/types@10.5.0': {} + + '@chevrotain/utils@10.5.0': {} + '@date-fns/tz@1.4.1': {} '@dnd-kit/accessibility@3.1.1(react@19.2.4)': @@ -3251,6 +3684,16 @@ snapshots: '@drizzle-team/brocli@0.10.2': {} + '@electric-sql/pglite-socket@0.0.20(@electric-sql/pglite@0.3.15)': + dependencies: + '@electric-sql/pglite': 0.3.15 + + '@electric-sql/pglite-tools@0.2.20(@electric-sql/pglite@0.3.15)': + dependencies: + '@electric-sql/pglite': 0.3.15 + + '@electric-sql/pglite@0.3.15': {} + '@emnapi/runtime@1.8.1': dependencies: tslib: 2.8.1 @@ -3507,6 +3950,10 @@ snapshots: '@hexagon/base64@1.1.28': {} + '@hono/node-server@1.19.9(hono@4.11.4)': + dependencies: + hono: 4.11.4 + '@img/colour@1.1.0': optional: true @@ -3625,6 +4072,15 @@ snapshots: '@levischuck/tiny-cbor@0.2.11': {} + '@mongodb-js/saslprep@1.4.6': + dependencies: + sparse-bitfield: 3.0.3 + + '@mrleebo/prisma-ast@0.13.1': + dependencies: + chevrotain: 10.5.0 + lilconfig: 2.1.0 + '@next/env@16.1.6': {} '@next/swc-darwin-arm64@16.1.6': @@ -3655,9 +4111,9 @@ snapshots: '@noble/hashes@2.0.1': {} - '@openrouter/ai-sdk-provider@2.2.3(ai@6.0.116(zod@4.3.6))(zod@4.3.6)': + '@openrouter/ai-sdk-provider@2.2.5(ai@6.0.124(zod@4.3.6))(zod@4.3.6)': dependencies: - ai: 6.0.116(zod@4.3.6) + ai: 6.0.124(zod@4.3.6) zod: 4.3.6 '@opentelemetry/api@1.9.0': {} @@ -3758,6 +4214,81 @@ snapshots: tslib: 2.8.1 tsyringe: 4.10.0 + '@prisma/client-runtime-utils@7.4.2': {} + + '@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3)': + dependencies: + '@prisma/client-runtime-utils': 7.4.2 + optionalDependencies: + prisma: 7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + typescript: 5.9.3 + + '@prisma/config@7.4.2': + dependencies: + c12: 3.1.0 + deepmerge-ts: 7.1.5 + effect: 3.18.4 + empathic: 2.0.0 + transitivePeerDependencies: + - magicast + + '@prisma/debug@7.2.0': {} + + '@prisma/debug@7.4.2': {} + + '@prisma/dev@0.20.0(typescript@5.9.3)': + dependencies: + '@electric-sql/pglite': 0.3.15 + '@electric-sql/pglite-socket': 0.0.20(@electric-sql/pglite@0.3.15) + '@electric-sql/pglite-tools': 0.2.20(@electric-sql/pglite@0.3.15) + '@hono/node-server': 1.19.9(hono@4.11.4) + '@mrleebo/prisma-ast': 0.13.1 + '@prisma/get-platform': 7.2.0 + '@prisma/query-plan-executor': 7.2.0 + foreground-child: 3.3.1 + get-port-please: 3.2.0 + hono: 4.11.4 + http-status-codes: 2.3.0 + pathe: 2.0.3 + proper-lockfile: 4.1.2 + remeda: 2.33.4 + std-env: 3.10.0 + valibot: 1.2.0(typescript@5.9.3) + zeptomatch: 2.1.0 + transitivePeerDependencies: + - typescript + + '@prisma/engines-version@7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919': {} + + '@prisma/engines@7.4.2': + dependencies: + '@prisma/debug': 7.4.2 + '@prisma/engines-version': 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 + '@prisma/fetch-engine': 7.4.2 + '@prisma/get-platform': 7.4.2 + + '@prisma/fetch-engine@7.4.2': + dependencies: + '@prisma/debug': 7.4.2 + '@prisma/engines-version': 7.5.0-10.94a226be1cf2967af2541cca5529f0f7ba866919 + '@prisma/get-platform': 7.4.2 + + '@prisma/get-platform@7.2.0': + dependencies: + '@prisma/debug': 7.2.0 + + '@prisma/get-platform@7.4.2': + dependencies: + '@prisma/debug': 7.4.2 + + '@prisma/query-plan-executor@7.2.0': {} + + '@prisma/studio-core@0.13.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@types/react': 19.2.14 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + '@radix-ui/number@1.1.1': {} '@radix-ui/primitive@1.1.3': {} @@ -4710,7 +5241,7 @@ snapshots: '@types/d3-timer@3.0.2': {} - '@types/node@25.3.2': + '@types/node@25.4.0': dependencies: undici-types: 7.18.2 @@ -4718,7 +5249,7 @@ snapshots: '@types/pg@8.18.0': dependencies: - '@types/node': 25.3.2 + '@types/node': 25.4.0 pg-protocol: 1.13.0 pg-types: 2.2.0 @@ -4738,6 +5269,12 @@ snapshots: '@types/use-sync-external-store@0.0.6': {} + '@types/webidl-conversions@7.0.3': {} + + '@types/whatwg-url@13.0.0': + dependencies: + '@types/webidl-conversions': 7.0.3 + '@vercel/analytics@1.6.1(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': optionalDependencies: next: 16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -4752,11 +5289,11 @@ snapshots: adler-32@1.3.1: {} - ai@6.0.116(zod@4.3.6): + ai@6.0.124(zod@4.3.6): dependencies: - '@ai-sdk/gateway': 3.0.66(zod@4.3.6) + '@ai-sdk/gateway': 3.0.71(zod@4.3.6) '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.19(zod@4.3.6) + '@ai-sdk/provider-utils': 4.0.20(zod@4.3.6) '@opentelemetry/api': 1.9.0 zod: 4.3.6 @@ -4770,6 +5307,8 @@ snapshots: pvutils: 1.1.5 tslib: 2.8.1 + aws-ssl-profiles@1.1.2: {} + babel-plugin-react-compiler@1.0.0: dependencies: '@babel/types': 7.29.0 @@ -4780,36 +5319,38 @@ snapshots: baseline-browser-mapping@2.10.0: {} - better-auth@1.4.19(drizzle-kit@0.31.9)(drizzle-orm@0.45.1(@opentelemetry/api@1.9.0)(@types/pg@8.18.0)(kysely@0.28.11)(pg@8.19.0))(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.19.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + better-auth@1.5.4(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.9)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: - '@better-auth/core': 1.4.19(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1) - '@better-auth/telemetry': 1.4.19(@better-auth/core@1.4.19(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.0)(kysely@0.28.11)(nanostores@1.1.1)) - '@better-auth/utils': 0.3.0 + '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1) + '@better-auth/drizzle-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))) + '@better-auth/kysely-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(kysely@0.28.11) + '@better-auth/memory-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1) + '@better-auth/mongo-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(mongodb@7.1.0) + '@better-auth/prisma-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) + '@better-auth/telemetry': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1)) + '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 '@noble/ciphers': 2.1.1 '@noble/hashes': 2.0.1 - better-call: 1.1.8(zod@4.3.6) + better-call: 1.3.2(zod@4.3.6) defu: 6.1.4 - jose: 6.2.0 + jose: 6.2.1 kysely: 0.28.11 nanostores: 1.1.1 zod: 4.3.6 optionalDependencies: + '@prisma/client': 7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3) drizzle-kit: 0.31.9 - drizzle-orm: 0.45.1(@opentelemetry/api@1.9.0)(@types/pg@8.18.0)(kysely@0.28.11)(pg@8.19.0) + drizzle-orm: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)) + mongodb: 7.1.0 + mysql2: 3.15.3 next: 16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - pg: 8.19.0 + pg: 8.20.0 + prisma: 7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - - better-call@1.1.8(zod@4.3.6): - dependencies: - '@better-auth/utils': 0.3.0 - '@better-fetch/fetch': 1.1.21 - rou3: 0.7.12 - set-cookie-parser: 2.7.2 - optionalDependencies: - zod: 4.3.6 + transitivePeerDependencies: + - '@cloudflare/workers-types' better-call@1.3.2(zod@4.3.6): dependencies: @@ -4820,8 +5361,25 @@ snapshots: optionalDependencies: zod: 4.3.6 + bson@7.2.0: {} + buffer-from@1.1.2: {} + c12@3.1.0: + dependencies: + chokidar: 4.0.3 + confbox: 0.2.4 + defu: 6.1.4 + dotenv: 16.6.1 + exsolve: 1.0.8 + giget: 2.0.0 + jiti: 2.6.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 1.0.0 + pkg-types: 2.3.0 + rc9: 2.1.2 + caniuse-lite@1.0.30001777: {} canvg@3.0.11: @@ -4841,6 +5399,25 @@ snapshots: adler-32: 1.3.1 crc-32: 1.2.2 + chevrotain@10.5.0: + dependencies: + '@chevrotain/cst-dts-gen': 10.5.0 + '@chevrotain/gast': 10.5.0 + '@chevrotain/types': 10.5.0 + '@chevrotain/utils': 10.5.0 + lodash: 4.17.21 + regexp-to-ast: 0.5.0 + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + citty@0.1.6: + dependencies: + consola: 3.4.2 + + citty@0.2.1: {} + class-variance-authority@0.7.1: dependencies: clsx: 2.1.1 @@ -4863,11 +5440,21 @@ snapshots: codepage@1.15.0: {} + confbox@0.2.4: {} + + consola@3.4.2: {} + core-js@3.48.0: optional: true crc-32@1.2.2: {} + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + css-line-break@2.1.0: dependencies: utrie: 1.0.2 @@ -4923,8 +5510,14 @@ snapshots: decimal.js-light@2.5.1: {} + deepmerge-ts@7.1.5: {} + defu@6.1.4: {} + denque@2.1.0: {} + + destr@2.0.5: {} + detect-libc@2.1.2: {} detect-node-es@1.1.0: {} @@ -4934,6 +5527,8 @@ snapshots: '@types/trusted-types': 2.0.7 optional: true + dotenv@16.6.1: {} + dotenv@17.3.1: {} drizzle-kit@0.31.9: @@ -4945,12 +5540,24 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.45.1(@opentelemetry/api@1.9.0)(@types/pg@8.18.0)(kysely@0.28.11)(pg@8.19.0): + drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)): optionalDependencies: + '@electric-sql/pglite': 0.3.15 '@opentelemetry/api': 1.9.0 + '@prisma/client': 7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3) '@types/pg': 8.18.0 kysely: 0.28.11 - pg: 8.19.0 + mysql2: 3.15.3 + pg: 8.20.0 + postgres: 3.4.7 + prisma: 7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + + effect@3.18.4: + dependencies: + '@standard-schema/spec': 1.1.0 + fast-check: 3.23.2 + + empathic@2.0.0: {} enhanced-resolve@5.20.0: dependencies: @@ -5053,6 +5660,12 @@ snapshots: eventsource-parser@3.0.6: {} + exsolve@1.0.8: {} + + fast-check@3.23.2: + dependencies: + pure-rand: 6.1.0 + fast-png@6.4.0: dependencies: '@types/pako': 2.0.4 @@ -5063,25 +5676,57 @@ snapshots: fflate@0.8.2: {} + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + frac@1.1.2: {} fsevents@2.3.3: optional: true + generate-function@2.3.1: + dependencies: + is-property: 1.0.2 + get-nonce@1.0.1: {} + get-port-please@3.2.0: {} + get-tsconfig@4.13.6: dependencies: resolve-pkg-maps: 1.0.0 + giget@2.0.0: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + defu: 6.1.4 + node-fetch-native: 1.6.7 + nypm: 0.6.5 + pathe: 2.0.3 + graceful-fs@4.2.11: {} + grammex@3.1.12: {} + + graphmatch@1.1.1: {} + + hono@4.11.4: {} + html2canvas@1.4.1: dependencies: css-line-break: 2.1.0 text-segmentation: 1.0.3 optional: true + http-status-codes@2.3.0: {} + + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + immer@10.2.0: {} immer@11.1.4: {} @@ -5090,9 +5735,13 @@ snapshots: iobuffer@5.4.0: {} + is-property@1.0.2: {} + + isexe@2.0.0: {} + jiti@2.6.1: {} - jose@6.2.0: {} + jose@6.2.1: {} json-schema@0.4.0: {} @@ -5162,12 +5811,49 @@ snapshots: lightningcss-win32-arm64-msvc: 1.31.1 lightningcss-win32-x64-msvc: 1.31.1 + lilconfig@2.1.0: {} + + lodash@4.17.21: {} + + long@5.3.2: {} + + lru.min@1.1.4: {} + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + memory-pager@1.5.0: {} + + mongodb-connection-string-url@7.0.1: + dependencies: + '@types/whatwg-url': 13.0.0 + whatwg-url: 14.2.0 + + mongodb@7.1.0: + dependencies: + '@mongodb-js/saslprep': 1.4.6 + bson: 7.2.0 + mongodb-connection-string-url: 7.0.1 + ms@2.1.3: {} + mysql2@3.15.3: + dependencies: + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.7.2 + long: 5.3.2 + lru.min: 1.1.4 + named-placeholders: 1.1.6 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + + named-placeholders@1.1.6: + dependencies: + lru.min: 1.1.4 + nanoid@3.3.11: {} nanostores@1.1.1: {} @@ -5203,8 +5889,24 @@ snapshots: - '@babel/core' - babel-plugin-macros + node-fetch-native@1.6.7: {} + + nypm@0.6.5: + dependencies: + citty: 0.2.1 + pathe: 2.0.3 + tinyexec: 1.0.2 + + ohash@2.0.11: {} + pako@2.1.0: {} + path-key@3.1.1: {} + + pathe@2.0.3: {} + + perfect-debounce@1.0.0: {} + performance-now@2.1.0: optional: true @@ -5215,9 +5917,9 @@ snapshots: pg-int8@1.0.1: {} - pg-pool@3.13.0(pg@8.19.0): + pg-pool@3.13.0(pg@8.20.0): dependencies: - pg: 8.19.0 + pg: 8.20.0 pg-protocol@1.13.0: {} @@ -5229,10 +5931,10 @@ snapshots: postgres-date: 1.0.7 postgres-interval: 1.2.0 - pg@8.19.0: + pg@8.20.0: dependencies: pg-connection-string: 2.12.0 - pg-pool: 3.13.0(pg@8.19.0) + pg-pool: 3.13.0(pg@8.20.0) pg-protocol: 1.13.0 pg-types: 2.2.0 pgpass: 1.0.5 @@ -5245,6 +5947,12 @@ snapshots: picocolors@1.1.1: {} + pkg-types@2.3.0: + dependencies: + confbox: 0.2.4 + exsolve: 1.0.8 + pathe: 2.0.3 + postal-mime@2.7.3: {} postcss@8.4.31: @@ -5269,6 +5977,34 @@ snapshots: dependencies: xtend: 4.0.2 + postgres@3.4.7: {} + + prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3): + dependencies: + '@prisma/config': 7.4.2 + '@prisma/dev': 0.20.0(typescript@5.9.3) + '@prisma/engines': 7.4.2 + '@prisma/studio-core': 0.13.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + mysql2: 3.15.3 + postgres: 3.4.7 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/react' + - magicast + - react + - react-dom + + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + + punycode@2.3.1: {} + + pure-rand@6.1.0: {} + pvtsutils@1.3.6: dependencies: tslib: 2.8.1 @@ -5343,6 +6079,11 @@ snapshots: performance-now: 2.1.0 optional: true + rc9@2.1.2: + dependencies: + defu: 6.1.4 + destr: 2.0.5 + react-day-picker@9.14.0(react@19.2.4): dependencies: '@date-fns/tz': 1.4.1 @@ -5396,7 +6137,9 @@ snapshots: react@19.2.4: {} - recharts@3.7.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@16.13.1)(react@19.2.4)(redux@5.0.1): + readdirp@4.1.2: {} + + recharts@3.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@16.13.1)(react@19.2.4)(redux@5.0.1): dependencies: '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1))(react@19.2.4) clsx: 2.1.1 @@ -5427,6 +6170,10 @@ snapshots: regenerator-runtime@0.13.11: optional: true + regexp-to-ast@0.5.0: {} + + remeda@2.33.4: {} + reselect@5.1.1: {} resend@6.9.3: @@ -5436,17 +6183,21 @@ snapshots: resolve-pkg-maps@1.0.0: {} + retry@0.12.0: {} + rgbcolor@1.0.1: optional: true rou3@0.7.12: {} + safer-buffer@2.1.2: {} + scheduler@0.27.0: {} semver@7.7.4: optional: true - set-cookie-parser@2.7.2: {} + seq-queue@0.0.5: {} set-cookie-parser@3.0.1: {} @@ -5482,6 +6233,16 @@ snapshots: '@img/sharp-win32-x64': 0.34.5 optional: true + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + sonner@2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: react: 19.2.4 @@ -5496,8 +6257,14 @@ snapshots: source-map@0.6.1: {} + sparse-bitfield@3.0.3: + dependencies: + memory-pager: 1.5.0 + split2@4.2.0: {} + sqlstring@2.3.3: {} + ssf@0.11.2: dependencies: frac: 1.1.2 @@ -5510,6 +6277,8 @@ snapshots: '@stablelib/base64': 1.0.1 fast-sha256: 1.3.0 + std-env@3.10.0: {} + styled-jsx@5.1.6(react@19.2.4): dependencies: client-only: 0.0.1 @@ -5536,6 +6305,12 @@ snapshots: tiny-invariant@1.3.3: {} + tinyexec@1.0.2: {} + + tr46@5.1.1: + dependencies: + punycode: 2.3.1 + tslib@1.14.1: {} tslib@2.8.1: {} @@ -5581,6 +6356,10 @@ snapshots: uuid@10.0.0: {} + valibot@1.2.0(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -5607,6 +6386,17 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 + webidl-conversions@7.0.0: {} + + whatwg-url@14.2.0: + dependencies: + tr46: 5.1.1 + webidl-conversions: 7.0.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + wmf@1.0.2: {} word@0.3.0: {} @@ -5623,4 +6413,9 @@ snapshots: xtend@4.0.2: {} + zeptomatch@2.1.0: + dependencies: + grammex: 3.1.12 + graphmatch: 1.1.1 + zod@4.3.6: {} diff --git a/proxy.ts b/proxy.ts index 85235ef..349f547 100644 --- a/proxy.ts +++ b/proxy.ts @@ -1,5 +1,5 @@ import { type NextRequest, NextResponse } from "next/server"; -import { auth } from "@/lib/auth/config"; +import { auth } from "@/shared/lib/auth/config"; // Rotas protegidas que requerem autenticação const PROTECTED_ROUTES = [ diff --git a/public/avatares/4825015.png b/public/avatars/4825015.png similarity index 100% rename from public/avatares/4825015.png rename to public/avatars/4825015.png diff --git a/public/avatares/4825021.png b/public/avatars/4825021.png similarity index 100% rename from public/avatares/4825021.png rename to public/avatars/4825021.png diff --git a/public/avatares/4825027.png b/public/avatars/4825027.png similarity index 100% rename from public/avatares/4825027.png rename to public/avatars/4825027.png diff --git a/public/avatares/4825031.png b/public/avatars/4825031.png similarity index 100% rename from public/avatares/4825031.png rename to public/avatars/4825031.png diff --git a/public/avatares/4825035.png b/public/avatars/4825035.png similarity index 100% rename from public/avatares/4825035.png rename to public/avatars/4825035.png diff --git a/public/avatares/4825038.png b/public/avatars/4825038.png similarity index 100% rename from public/avatares/4825038.png rename to public/avatars/4825038.png diff --git a/public/avatares/4825044.png b/public/avatars/4825044.png similarity index 100% rename from public/avatares/4825044.png rename to public/avatars/4825044.png diff --git a/public/avatares/4825047.png b/public/avatars/4825047.png similarity index 100% rename from public/avatares/4825047.png rename to public/avatars/4825047.png diff --git a/public/avatares/4825051.png b/public/avatars/4825051.png similarity index 100% rename from public/avatares/4825051.png rename to public/avatars/4825051.png diff --git a/public/avatares/4825057.png b/public/avatars/4825057.png similarity index 100% rename from public/avatares/4825057.png rename to public/avatars/4825057.png diff --git a/public/avatares/4825062.png b/public/avatars/4825062.png similarity index 100% rename from public/avatares/4825062.png rename to public/avatars/4825062.png diff --git a/public/avatares/4825066.png b/public/avatars/4825066.png similarity index 100% rename from public/avatares/4825066.png rename to public/avatars/4825066.png diff --git a/public/avatares/4825072.png b/public/avatars/4825072.png similarity index 100% rename from public/avatares/4825072.png rename to public/avatars/4825072.png diff --git a/public/avatares/4825076.png b/public/avatars/4825076.png similarity index 100% rename from public/avatares/4825076.png rename to public/avatars/4825076.png diff --git a/public/avatares/4825082.png b/public/avatars/4825082.png similarity index 100% rename from public/avatares/4825082.png rename to public/avatars/4825082.png diff --git a/public/avatares/4825087.png b/public/avatars/4825087.png similarity index 100% rename from public/avatares/4825087.png rename to public/avatars/4825087.png diff --git a/public/avatares/4825096.png b/public/avatars/4825096.png similarity index 100% rename from public/avatares/4825096.png rename to public/avatars/4825096.png diff --git a/public/avatares/4825108.png b/public/avatars/4825108.png similarity index 100% rename from public/avatares/4825108.png rename to public/avatars/4825108.png diff --git a/public/avatares/4825112.png b/public/avatars/4825112.png similarity index 100% rename from public/avatares/4825112.png rename to public/avatars/4825112.png diff --git a/public/avatares/4825123.png b/public/avatars/4825123.png similarity index 100% rename from public/avatares/4825123.png rename to public/avatars/4825123.png diff --git a/public/avatares/default_icon.png b/public/avatars/default_icon.png similarity index 100% rename from public/avatares/default_icon.png rename to public/avatars/default_icon.png diff --git a/public/bandeiras/amex.svg b/public/flags/amex.svg similarity index 100% rename from public/bandeiras/amex.svg rename to public/flags/amex.svg diff --git a/public/bandeiras/elo.svg b/public/flags/elo.svg similarity index 100% rename from public/bandeiras/elo.svg rename to public/flags/elo.svg diff --git a/public/bandeiras/hipercard.svg b/public/flags/hipercard.svg similarity index 100% rename from public/bandeiras/hipercard.svg rename to public/flags/hipercard.svg diff --git a/public/bandeiras/mastercard.svg b/public/flags/mastercard.svg similarity index 100% rename from public/bandeiras/mastercard.svg rename to public/flags/mastercard.svg diff --git a/public/bandeiras/visa.svg b/public/flags/visa.svg similarity index 100% rename from public/bandeiras/visa.svg rename to public/flags/visa.svg diff --git a/public/icones/party.svg b/public/icons/party.svg similarity index 100% rename from public/icones/party.svg rename to public/icons/party.svg diff --git a/public/imagens/dashboard-preview-dark.webp b/public/images/dashboard-preview-dark.webp similarity index 100% rename from public/imagens/dashboard-preview-dark.webp rename to public/images/dashboard-preview-dark.webp diff --git a/public/imagens/dashboard-preview-light.webp b/public/images/dashboard-preview-light.webp similarity index 100% rename from public/imagens/dashboard-preview-light.webp rename to public/images/dashboard-preview-light.webp diff --git a/public/imagens/logo_small.png b/public/images/logo_small.png similarity index 100% rename from public/imagens/logo_small.png rename to public/images/logo_small.png diff --git a/public/imagens/logo_text.png b/public/images/logo_text.png similarity index 100% rename from public/imagens/logo_text.png rename to public/images/logo_text.png diff --git a/public/imagens/openmonetis_companion.webp b/public/images/openmonetis_companion.webp similarity index 100% rename from public/imagens/openmonetis_companion.webp rename to public/images/openmonetis_companion.webp diff --git a/public/imagens/preview-calendario-dark.webp b/public/images/preview-calendario-dark.webp similarity index 100% rename from public/imagens/preview-calendario-dark.webp rename to public/images/preview-calendario-dark.webp diff --git a/public/imagens/preview-calendario-light.webp b/public/images/preview-calendario-light.webp similarity index 100% rename from public/imagens/preview-calendario-light.webp rename to public/images/preview-calendario-light.webp diff --git a/public/imagens/preview-cartao-dark.webp b/public/images/preview-cartao-dark.webp similarity index 100% rename from public/imagens/preview-cartao-dark.webp rename to public/images/preview-cartao-dark.webp diff --git a/public/imagens/preview-cartao-light.webp b/public/images/preview-cartao-light.webp similarity index 100% rename from public/imagens/preview-cartao-light.webp rename to public/images/preview-cartao-light.webp diff --git a/public/imagens/preview-lancamentos-dark.webp b/public/images/preview-lancamentos-dark.webp similarity index 100% rename from public/imagens/preview-lancamentos-dark.webp rename to public/images/preview-lancamentos-dark.webp diff --git a/public/imagens/preview-lancamentos-light.webp b/public/images/preview-lancamentos-light.webp similarity index 100% rename from public/imagens/preview-lancamentos-light.webp rename to public/images/preview-lancamentos-light.webp diff --git a/public/imagens/web-app-manifest-192x192.png b/public/images/web-app-manifest-192x192.png similarity index 100% rename from public/imagens/web-app-manifest-192x192.png rename to public/images/web-app-manifest-192x192.png diff --git a/public/imagens/web-app-manifest-512x512.png b/public/images/web-app-manifest-512x512.png similarity index 100% rename from public/imagens/web-app-manifest-512x512.png rename to public/images/web-app-manifest-512x512.png diff --git a/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx similarity index 77% rename from app/(auth)/login/page.tsx rename to src/app/(auth)/login/page.tsx index a2235ca..2b83529 100644 --- a/app/(auth)/login/page.tsx +++ b/src/app/(auth)/login/page.tsx @@ -1,4 +1,4 @@ -import { LoginForm } from "@/components/auth/login-form"; +import { LoginForm } from "@/features/auth/components/login-form"; export default function LoginPage() { return ( diff --git a/app/(auth)/signup/page.tsx b/src/app/(auth)/signup/page.tsx similarity index 76% rename from app/(auth)/signup/page.tsx rename to src/app/(auth)/signup/page.tsx index dd81e6e..fcbc345 100644 --- a/app/(auth)/signup/page.tsx +++ b/src/app/(auth)/signup/page.tsx @@ -1,4 +1,4 @@ -import { SignupForm } from "@/components/auth/signup-form"; +import { SignupForm } from "@/features/auth/components/signup-form"; export default function Page() { return ( diff --git a/app/(dashboard)/contas/[contaId]/extrato/loading.tsx b/src/app/(dashboard)/accounts/[accountId]/statement/loading.tsx similarity index 90% rename from app/(dashboard)/contas/[contaId]/extrato/loading.tsx rename to src/app/(dashboard)/accounts/[accountId]/statement/loading.tsx index 8d83f4c..9fe7bd7 100644 --- a/app/(dashboard)/contas/[contaId]/extrato/loading.tsx +++ b/src/app/(dashboard)/accounts/[accountId]/statement/loading.tsx @@ -2,8 +2,8 @@ import { AccountStatementCardSkeleton, FilterSkeleton, TransactionsTableSkeleton, -} from "@/components/shared/skeletons"; -import { Skeleton } from "@/components/ui/skeleton"; +} from "@/shared/components/skeletons"; +import { Skeleton } from "@/shared/components/ui/skeleton"; /** * Loading state para a página de extrato de conta diff --git a/app/(dashboard)/contas/[contaId]/extrato/page.tsx b/src/app/(dashboard)/accounts/[accountId]/statement/page.tsx similarity index 80% rename from app/(dashboard)/contas/[contaId]/extrato/page.tsx rename to src/app/(dashboard)/accounts/[accountId]/statement/page.tsx index bb928dd..bddd877 100644 --- a/app/(dashboard)/contas/[contaId]/extrato/page.tsx +++ b/src/app/(dashboard)/accounts/[accountId]/statement/page.tsx @@ -1,37 +1,39 @@ import { RiPencilLine } from "@remixicon/react"; import { notFound } from "next/navigation"; -import { fetchUserPreferences } from "@/app/(dashboard)/ajustes/data"; -import { getRecentEstablishmentsAction } from "@/app/(dashboard)/lancamentos/actions"; -import { AccountDialog } from "@/components/contas/account-dialog"; -import { AccountStatementCard } from "@/components/contas/account-statement-card"; -import type { Account } from "@/components/contas/types"; -import { LancamentosPage as LancamentosSection } from "@/components/lancamentos/page/lancamentos-page"; -import MonthNavigation from "@/components/month-picker/month-navigation"; -import { Button } from "@/components/ui/button"; -import { getUserId } from "@/lib/auth/server"; +import { AccountDialog } from "@/features/accounts/components/account-dialog"; +import { AccountStatementCard } from "@/features/accounts/components/account-statement-card"; +import type { Account } from "@/features/accounts/components/types"; +import { + fetchAccountData, + fetchAccountLancamentos, + fetchAccountSummary, +} from "@/features/accounts/statement-queries"; +import { fetchUserPreferences } from "@/features/settings/queries"; +import { LancamentosPage as LancamentosSection } from "@/features/transactions/components/page/transactions-page"; import { buildLancamentoWhere, buildOptionSets, buildSluggedFilters, buildSlugMaps, extractLancamentoSearchFilters, - fetchLancamentoFilterSources, getSingleParam, mapLancamentosData, type ResolvedSearchParams, -} from "@/lib/lancamentos/page-helpers"; -import { loadLogoOptions } from "@/lib/logo/options"; -import { parsePeriodParam } from "@/lib/utils/period"; +} from "@/features/transactions/page-helpers"; import { - fetchAccountData, - fetchAccountLancamentos, - fetchAccountSummary, -} from "./data"; + fetchLancamentoFilterSources, + fetchRecentEstablishments, +} from "@/features/transactions/queries"; +import MonthNavigation from "@/shared/components/month-picker/month-navigation"; +import { Button } from "@/shared/components/ui/button"; +import { getUserId } from "@/shared/lib/auth/server"; +import { loadLogoOptions } from "@/shared/lib/logo/options"; +import { parsePeriodParam } from "@/shared/utils/period"; type PageSearchParams = Promise; type PageProps = { - params: Promise<{ contaId: string }>; + params: Promise<{ accountId: string }>; searchParams?: PageSearchParams; }; @@ -39,7 +41,7 @@ const capitalize = (value: string) => value.length > 0 ? value[0]?.toUpperCase().concat(value.slice(1)) : value; export default async function Page({ params, searchParams }: PageProps) { - const { contaId } = await params; + const { accountId: contaId } = await params; const userId = await getUserId(); const resolvedSearchParams = searchParams ? await searchParams : undefined; @@ -68,7 +70,7 @@ export default async function Page({ params, searchParams }: PageProps) { fetchLancamentoFilterSources(userId), loadLogoOptions(), fetchAccountSummary(userId, contaId, selectedPeriod), - getRecentEstablishmentsAction(), + fetchRecentEstablishments(userId), fetchUserPreferences(userId), ]); const sluggedFilters = buildSluggedFilters(filterSources); diff --git a/app/(dashboard)/contas/layout.tsx b/src/app/(dashboard)/accounts/layout.tsx similarity index 90% rename from app/(dashboard)/contas/layout.tsx rename to src/app/(dashboard)/accounts/layout.tsx index 7c80448..6fd6c2a 100644 --- a/app/(dashboard)/contas/layout.tsx +++ b/src/app/(dashboard)/accounts/layout.tsx @@ -1,5 +1,5 @@ import { RiBankLine } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Contas | OpenMonetis", diff --git a/app/(dashboard)/contas/loading.tsx b/src/app/(dashboard)/accounts/loading.tsx similarity index 95% rename from app/(dashboard)/contas/loading.tsx rename to src/app/(dashboard)/accounts/loading.tsx index 334b496..8d41920 100644 --- a/app/(dashboard)/contas/loading.tsx +++ b/src/app/(dashboard)/accounts/loading.tsx @@ -1,4 +1,4 @@ -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/shared/components/ui/skeleton"; export default function ContasLoading() { return ( diff --git a/app/(dashboard)/contas/page.tsx b/src/app/(dashboard)/accounts/page.tsx similarity index 65% rename from app/(dashboard)/contas/page.tsx rename to src/app/(dashboard)/accounts/page.tsx index 972ff5a..ce80001 100644 --- a/app/(dashboard)/contas/page.tsx +++ b/src/app/(dashboard)/accounts/page.tsx @@ -1,6 +1,6 @@ -import { AccountsPage } from "@/components/contas/accounts-page"; -import { getUserId } from "@/lib/auth/server"; -import { fetchAllAccountsForUser } from "./data"; +import { AccountsPage } from "@/features/accounts/components/accounts-page"; +import { fetchAllAccountsForUser } from "@/features/accounts/queries"; +import { getUserId } from "@/shared/lib/auth/server"; export default async function Page() { const userId = await getUserId(); diff --git a/app/(dashboard)/orcamentos/layout.tsx b/src/app/(dashboard)/budgets/layout.tsx similarity index 88% rename from app/(dashboard)/orcamentos/layout.tsx rename to src/app/(dashboard)/budgets/layout.tsx index 3c8f7cd..d8377e7 100644 --- a/app/(dashboard)/orcamentos/layout.tsx +++ b/src/app/(dashboard)/budgets/layout.tsx @@ -1,5 +1,5 @@ import { RiBarChart2Line } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Orçamentos | OpenMonetis", diff --git a/app/(dashboard)/orcamentos/loading.tsx b/src/app/(dashboard)/budgets/loading.tsx similarity index 97% rename from app/(dashboard)/orcamentos/loading.tsx rename to src/app/(dashboard)/budgets/loading.tsx index 9789786..0f72aad 100644 --- a/app/(dashboard)/orcamentos/loading.tsx +++ b/src/app/(dashboard)/budgets/loading.tsx @@ -1,4 +1,4 @@ -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/shared/components/ui/skeleton"; /** * Loading state para a página de orçamentos diff --git a/app/(dashboard)/orcamentos/page.tsx b/src/app/(dashboard)/budgets/page.tsx similarity index 78% rename from app/(dashboard)/orcamentos/page.tsx rename to src/app/(dashboard)/budgets/page.tsx index 5b0c1d5..85a0d4d 100644 --- a/app/(dashboard)/orcamentos/page.tsx +++ b/src/app/(dashboard)/budgets/page.tsx @@ -1,8 +1,8 @@ -import MonthNavigation from "@/components/month-picker/month-navigation"; -import { BudgetsPage } from "@/components/orcamentos/budgets-page"; -import { getUserId } from "@/lib/auth/server"; -import { parsePeriodParam } from "@/lib/utils/period"; -import { fetchBudgetsForUser } from "./data"; +import { BudgetsPage } from "@/features/budgets/components/budgets-page"; +import { fetchBudgetsForUser } from "@/features/budgets/queries"; +import MonthNavigation from "@/shared/components/month-picker/month-navigation"; +import { getUserId } from "@/shared/lib/auth/server"; +import { parsePeriodParam } from "@/shared/utils/period"; type PageSearchParams = Promise>; diff --git a/app/(dashboard)/calendario/layout.tsx b/src/app/(dashboard)/calendar/layout.tsx similarity index 89% rename from app/(dashboard)/calendario/layout.tsx rename to src/app/(dashboard)/calendar/layout.tsx index 6c8195a..63701d2 100644 --- a/app/(dashboard)/calendario/layout.tsx +++ b/src/app/(dashboard)/calendar/layout.tsx @@ -1,5 +1,5 @@ import { RiCalendarEventLine } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Calendário | OpenMonetis", diff --git a/app/(dashboard)/calendario/loading.tsx b/src/app/(dashboard)/calendar/loading.tsx similarity index 96% rename from app/(dashboard)/calendario/loading.tsx rename to src/app/(dashboard)/calendar/loading.tsx index fdb3579..1234798 100644 --- a/app/(dashboard)/calendario/loading.tsx +++ b/src/app/(dashboard)/calendar/loading.tsx @@ -1,4 +1,4 @@ -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/shared/components/ui/skeleton"; /** * Loading state para a página de calendário diff --git a/app/(dashboard)/calendario/page.tsx b/src/app/(dashboard)/calendar/page.tsx similarity index 65% rename from app/(dashboard)/calendario/page.tsx rename to src/app/(dashboard)/calendar/page.tsx index c332fdd..42f5901 100644 --- a/app/(dashboard)/calendario/page.tsx +++ b/src/app/(dashboard)/calendar/page.tsx @@ -1,13 +1,13 @@ -import { MonthlyCalendar } from "@/components/calendario/monthly-calendar"; -import MonthNavigation from "@/components/month-picker/month-navigation"; -import { getUserId } from "@/lib/auth/server"; +import { MonthlyCalendar } from "@/features/calendar/components/monthly-calendar"; +import { fetchCalendarData } from "@/features/calendar/queries"; import { getSingleParam, type ResolvedSearchParams, -} from "@/lib/lancamentos/page-helpers"; -import type { CalendarPeriod } from "@/lib/types/calendario"; -import { parsePeriodParam } from "@/lib/utils/period"; -import { fetchCalendarData } from "./data"; +} from "@/features/transactions/page-helpers"; +import MonthNavigation from "@/shared/components/month-picker/month-navigation"; +import { getUserId } from "@/shared/lib/auth/server"; +import type { CalendarPeriod } from "@/shared/lib/types/calendar"; +import { parsePeriodParam } from "@/shared/utils/period"; type PageSearchParams = Promise; diff --git a/app/(dashboard)/cartoes/[cartaoId]/fatura/loading.tsx b/src/app/(dashboard)/cards/[cardId]/invoice/loading.tsx similarity index 91% rename from app/(dashboard)/cartoes/[cartaoId]/fatura/loading.tsx rename to src/app/(dashboard)/cards/[cardId]/invoice/loading.tsx index 2e99a3c..5aed886 100644 --- a/app/(dashboard)/cartoes/[cartaoId]/fatura/loading.tsx +++ b/src/app/(dashboard)/cards/[cardId]/invoice/loading.tsx @@ -2,8 +2,8 @@ import { FilterSkeleton, InvoiceSummaryCardSkeleton, TransactionsTableSkeleton, -} from "@/components/shared/skeletons"; -import { Skeleton } from "@/components/ui/skeleton"; +} from "@/shared/components/skeletons"; +import { Skeleton } from "@/shared/components/ui/skeleton"; /** * Loading state para a página de fatura de cartão diff --git a/app/(dashboard)/cartoes/[cartaoId]/fatura/page.tsx b/src/app/(dashboard)/cards/[cardId]/invoice/page.tsx similarity index 81% rename from app/(dashboard)/cartoes/[cartaoId]/fatura/page.tsx rename to src/app/(dashboard)/cards/[cardId]/invoice/page.tsx index b108dba..6a6ebb1 100644 --- a/app/(dashboard)/cartoes/[cartaoId]/fatura/page.tsx +++ b/src/app/(dashboard)/cards/[cardId]/invoice/page.tsx @@ -1,39 +1,45 @@ import { RiPencilLine } from "@remixicon/react"; import { notFound } from "next/navigation"; -import { fetchUserPreferences } from "@/app/(dashboard)/ajustes/data"; -import { getRecentEstablishmentsAction } from "@/app/(dashboard)/lancamentos/actions"; -import { CardDialog } from "@/components/cartoes/card-dialog"; -import type { Card } from "@/components/cartoes/types"; -import { InvoiceSummaryCard } from "@/components/faturas/invoice-summary-card"; -import { LancamentosPage as LancamentosSection } from "@/components/lancamentos/page/lancamentos-page"; -import MonthNavigation from "@/components/month-picker/month-navigation"; -import { Button } from "@/components/ui/button"; import type { Conta } from "@/db/schema"; -import { getUserId } from "@/lib/auth/server"; +import { CardDialog } from "@/features/cards/components/card-dialog"; +import type { Card } from "@/features/cards/components/types"; +import { InvoiceSummaryCard } from "@/features/invoices/components/invoice-summary-card"; +import { + fetchCardData, + fetchCardLancamentos, + fetchInvoiceData, +} from "@/features/invoices/queries"; +import { fetchUserPreferences } from "@/features/settings/queries"; +import { LancamentosPage as LancamentosSection } from "@/features/transactions/components/page/transactions-page"; import { buildLancamentoWhere, buildOptionSets, buildSluggedFilters, buildSlugMaps, extractLancamentoSearchFilters, - fetchLancamentoFilterSources, getSingleParam, mapLancamentosData, type ResolvedSearchParams, -} from "@/lib/lancamentos/page-helpers"; -import { loadLogoOptions } from "@/lib/logo/options"; -import { parsePeriodParam } from "@/lib/utils/period"; -import { fetchCardData, fetchCardLancamentos, fetchInvoiceData } from "./data"; +} from "@/features/transactions/page-helpers"; +import { + fetchLancamentoFilterSources, + fetchRecentEstablishments, +} from "@/features/transactions/queries"; +import MonthNavigation from "@/shared/components/month-picker/month-navigation"; +import { Button } from "@/shared/components/ui/button"; +import { getUserId } from "@/shared/lib/auth/server"; +import { loadLogoOptions } from "@/shared/lib/logo/options"; +import { parsePeriodParam } from "@/shared/utils/period"; type PageSearchParams = Promise; type PageProps = { - params: Promise<{ cartaoId: string }>; + params: Promise<{ cardId: string }>; searchParams?: PageSearchParams; }; export default async function Page({ params, searchParams }: PageProps) { - const { cartaoId } = await params; + const { cardId: cartaoId } = await params; const userId = await getUserId(); const resolvedSearchParams = searchParams ? await searchParams : undefined; @@ -62,7 +68,7 @@ export default async function Page({ params, searchParams }: PageProps) { fetchLancamentoFilterSources(userId), loadLogoOptions(), fetchInvoiceData(userId, cartaoId, selectedPeriod), - getRecentEstablishmentsAction(), + fetchRecentEstablishments(userId), fetchUserPreferences(userId), ]); const sluggedFilters = buildSluggedFilters(filterSources); @@ -99,6 +105,7 @@ export default async function Page({ params, searchParams }: PageProps) { const accountOptions = filterSources.contaRows.map((conta: Conta) => ({ id: conta.id, name: conta.name ?? "Conta", + logo: conta.logo ?? null, })); const contaName = diff --git a/app/(dashboard)/cartoes/layout.tsx b/src/app/(dashboard)/cards/layout.tsx similarity index 90% rename from app/(dashboard)/cartoes/layout.tsx rename to src/app/(dashboard)/cards/layout.tsx index 90b73e2..366ede9 100644 --- a/app/(dashboard)/cartoes/layout.tsx +++ b/src/app/(dashboard)/cards/layout.tsx @@ -1,5 +1,5 @@ import { RiBankCard2Line } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Cartões | OpenMonetis", diff --git a/app/(dashboard)/cartoes/loading.tsx b/src/app/(dashboard)/cards/loading.tsx similarity index 94% rename from app/(dashboard)/cartoes/loading.tsx rename to src/app/(dashboard)/cards/loading.tsx index 4908802..f914020 100644 --- a/app/(dashboard)/cartoes/loading.tsx +++ b/src/app/(dashboard)/cards/loading.tsx @@ -1,4 +1,4 @@ -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/shared/components/ui/skeleton"; export default function CartoesLoading() { return ( diff --git a/app/(dashboard)/cartoes/page.tsx b/src/app/(dashboard)/cards/page.tsx similarity index 67% rename from app/(dashboard)/cartoes/page.tsx rename to src/app/(dashboard)/cards/page.tsx index 3cbae11..a945f15 100644 --- a/app/(dashboard)/cartoes/page.tsx +++ b/src/app/(dashboard)/cards/page.tsx @@ -1,6 +1,6 @@ -import { CardsPage } from "@/components/cartoes/cards-page"; -import { getUserId } from "@/lib/auth/server"; -import { fetchAllCardsForUser } from "./data"; +import { CardsPage } from "@/features/cards/components/cards-page"; +import { fetchAllCardsForUser } from "@/features/cards/queries"; +import { getUserId } from "@/shared/lib/auth/server"; export default async function Page() { const userId = await getUserId(); diff --git a/app/(dashboard)/categorias/[categoryId]/page.tsx b/src/app/(dashboard)/categories/[categoryId]/page.tsx similarity index 79% rename from app/(dashboard)/categorias/[categoryId]/page.tsx rename to src/app/(dashboard)/categories/[categoryId]/page.tsx index 6d7307d..91cade9 100644 --- a/app/(dashboard)/categorias/[categoryId]/page.tsx +++ b/src/app/(dashboard)/categories/[categoryId]/page.tsx @@ -1,17 +1,19 @@ import { notFound } from "next/navigation"; -import { fetchUserPreferences } from "@/app/(dashboard)/ajustes/data"; -import { getRecentEstablishmentsAction } from "@/app/(dashboard)/lancamentos/actions"; -import { CategoryDetailHeader } from "@/components/categorias/category-detail-header"; -import { LancamentosPage } from "@/components/lancamentos/page/lancamentos-page"; -import MonthNavigation from "@/components/month-picker/month-navigation"; -import { getUserId } from "@/lib/auth/server"; -import { fetchCategoryDetails } from "@/lib/dashboard/categories/category-details"; +import { CategoryDetailHeader } from "@/features/categories/components/category-detail-header"; +import { fetchCategoryDetails } from "@/features/dashboard/categories/category-details-queries"; +import { fetchUserPreferences } from "@/features/settings/queries"; +import { LancamentosPage } from "@/features/transactions/components/page/transactions-page"; import { buildOptionSets, buildSluggedFilters, +} from "@/features/transactions/page-helpers"; +import { fetchLancamentoFilterSources, -} from "@/lib/lancamentos/page-helpers"; -import { displayPeriod, parsePeriodParam } from "@/lib/utils/period"; + fetchRecentEstablishments, +} from "@/features/transactions/queries"; +import MonthNavigation from "@/shared/components/month-picker/month-navigation"; +import { getUserId } from "@/shared/lib/auth/server"; +import { displayPeriod, parsePeriodParam } from "@/shared/utils/period"; type PageSearchParams = Promise>; @@ -41,7 +43,7 @@ export default async function Page({ params, searchParams }: PageProps) { await Promise.all([ fetchCategoryDetails(userId, categoryId, selectedPeriod), fetchLancamentoFilterSources(userId), - getRecentEstablishmentsAction(), + fetchRecentEstablishments(userId), fetchUserPreferences(userId), ]); diff --git a/app/(dashboard)/categorias/historico/loading.tsx b/src/app/(dashboard)/categories/history/loading.tsx similarity index 88% rename from app/(dashboard)/categorias/historico/loading.tsx rename to src/app/(dashboard)/categories/history/loading.tsx index ef68ec7..d04b11d 100644 --- a/app/(dashboard)/categorias/historico/loading.tsx +++ b/src/app/(dashboard)/categories/history/loading.tsx @@ -1,5 +1,5 @@ -import { Card, CardContent } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card, CardContent } from "@/shared/components/ui/card"; +import { Skeleton } from "@/shared/components/ui/skeleton"; export default function Loading() { return ( diff --git a/src/app/(dashboard)/categories/history/page.tsx b/src/app/(dashboard)/categories/history/page.tsx new file mode 100644 index 0000000..a1ba805 --- /dev/null +++ b/src/app/(dashboard)/categories/history/page.tsx @@ -0,0 +1,17 @@ +import { fetchCategoryHistory } from "@/features/dashboard/categories/category-history-queries"; +import { CategoryHistoryWidget } from "@/features/dashboard/components/category-history-widget"; +import { getUser } from "@/shared/lib/auth/server"; +import { getCurrentPeriod } from "@/shared/utils/period"; + +export default async function HistoricoCategoriasPage() { + const user = await getUser(); + const currentPeriod = getCurrentPeriod(); + + const data = await fetchCategoryHistory(user.id, currentPeriod); + + return ( +
+ +
+ ); +} diff --git a/app/(dashboard)/categorias/layout.tsx b/src/app/(dashboard)/categories/layout.tsx similarity index 88% rename from app/(dashboard)/categorias/layout.tsx rename to src/app/(dashboard)/categories/layout.tsx index 0b6f26d..765018f 100644 --- a/app/(dashboard)/categorias/layout.tsx +++ b/src/app/(dashboard)/categories/layout.tsx @@ -1,5 +1,5 @@ import { RiPriceTag3Line } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Categorias | OpenMonetis", diff --git a/app/(dashboard)/categorias/loading.tsx b/src/app/(dashboard)/categories/loading.tsx similarity index 94% rename from app/(dashboard)/categorias/loading.tsx rename to src/app/(dashboard)/categories/loading.tsx index 044b0b1..4da52eb 100644 --- a/app/(dashboard)/categorias/loading.tsx +++ b/src/app/(dashboard)/categories/loading.tsx @@ -1,5 +1,5 @@ -import { Card, CardContent } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card, CardContent } from "@/shared/components/ui/card"; +import { Skeleton } from "@/shared/components/ui/skeleton"; export default function CategoriasLoading() { return ( diff --git a/app/(dashboard)/categorias/page.tsx b/src/app/(dashboard)/categories/page.tsx similarity index 55% rename from app/(dashboard)/categorias/page.tsx rename to src/app/(dashboard)/categories/page.tsx index dddb61b..f4fd745 100644 --- a/app/(dashboard)/categorias/page.tsx +++ b/src/app/(dashboard)/categories/page.tsx @@ -1,6 +1,6 @@ -import { CategoriesPage } from "@/components/categorias/categories-page"; -import { getUserId } from "@/lib/auth/server"; -import { fetchCategoriesForUser } from "./data"; +import { CategoriesPage } from "@/features/categories/components/categories-page"; +import { fetchCategoriesForUser } from "@/features/categories/queries"; +import { getUserId } from "@/shared/lib/auth/server"; export default async function Page() { const userId = await getUserId(); diff --git a/app/(dashboard)/dashboard/loading.tsx b/src/app/(dashboard)/dashboard/loading.tsx similarity index 80% rename from app/(dashboard)/dashboard/loading.tsx rename to src/app/(dashboard)/dashboard/loading.tsx index a5a5d25..4ce2231 100644 --- a/app/(dashboard)/dashboard/loading.tsx +++ b/src/app/(dashboard)/dashboard/loading.tsx @@ -1,5 +1,5 @@ -import { DashboardGridSkeleton } from "@/components/shared/skeletons"; -import { Skeleton } from "@/components/ui/skeleton"; +import { DashboardGridSkeleton } from "@/shared/components/skeletons"; +import { Skeleton } from "@/shared/components/ui/skeleton"; export default function DashboardLoading() { return ( diff --git a/app/(dashboard)/dashboard/page.tsx b/src/app/(dashboard)/dashboard/page.tsx similarity index 62% rename from app/(dashboard)/dashboard/page.tsx rename to src/app/(dashboard)/dashboard/page.tsx index c5277f1..33a5296 100644 --- a/app/(dashboard)/dashboard/page.tsx +++ b/src/app/(dashboard)/dashboard/page.tsx @@ -1,17 +1,21 @@ -import { DashboardGridEditable } from "@/components/dashboard/dashboard-grid-editable"; -import { DashboardMetricsCards } from "@/components/dashboard/dashboard-metrics-cards"; -import { DashboardWelcome } from "@/components/dashboard/dashboard-welcome"; -import MonthNavigation from "@/components/month-picker/month-navigation"; -import { getUser } from "@/lib/auth/server"; -import { fetchDashboardData } from "@/lib/dashboard/fetch-dashboard-data"; +import { DashboardGridEditable } from "@/features/dashboard/components/dashboard-grid-editable"; +import { DashboardMetricsCards } from "@/features/dashboard/components/dashboard-metrics-cards"; +import { DashboardWelcome } from "@/features/dashboard/components/dashboard-welcome"; +import { fetchDashboardData } from "@/features/dashboard/fetch-dashboard-data"; +import { fetchUserDashboardPreferences } from "@/features/dashboard/preferences-queries"; +import { triggerRecurringGeneration } from "@/features/recurring/trigger-recurring-generation"; import { buildOptionSets, buildSluggedFilters, + getSingleParam, +} from "@/features/transactions/page-helpers"; +import { fetchLancamentoFilterSources, -} from "@/lib/lancamentos/page-helpers"; -import { parsePeriodParam } from "@/lib/utils/period"; -import { getRecentEstablishmentsAction } from "../lancamentos/actions"; -import { fetchUserDashboardPreferences } from "./data"; + fetchRecentEstablishments, +} from "@/features/transactions/queries"; +import MonthNavigation from "@/shared/components/month-picker/month-navigation"; +import { getUser } from "@/shared/lib/auth/server"; +import { parsePeriodParam } from "@/shared/utils/period"; type PageSearchParams = Promise>; @@ -19,17 +23,9 @@ type PageProps = { searchParams?: PageSearchParams; }; -const getSingleParam = ( - params: Record | undefined, - key: string, -) => { - const value = params?.[key]; - if (!value) return null; - return Array.isArray(value) ? (value[0] ?? null) : value; -}; - export default async function Page({ searchParams }: PageProps) { const user = await getUser(); + await triggerRecurringGeneration(user.id); const resolvedSearchParams = searchParams ? await searchParams : undefined; const periodoParam = getSingleParam(resolvedSearchParams, "periodo"); const { period: selectedPeriod } = parsePeriodParam(periodoParam); @@ -39,7 +35,7 @@ export default async function Page({ searchParams }: PageProps) { fetchDashboardData(user.id, selectedPeriod), fetchUserDashboardPreferences(user.id), fetchLancamentoFilterSources(user.id), - getRecentEstablishmentsAction(), + fetchRecentEstablishments(user.id), ]); const { dashboardWidgets } = preferences; const sluggedFilters = buildSluggedFilters(filterSources); diff --git a/app/(dashboard)/pre-lancamentos/layout.tsx b/src/app/(dashboard)/inbox/layout.tsx similarity index 86% rename from app/(dashboard)/pre-lancamentos/layout.tsx rename to src/app/(dashboard)/inbox/layout.tsx index d39a2a1..749c4f1 100644 --- a/app/(dashboard)/pre-lancamentos/layout.tsx +++ b/src/app/(dashboard)/inbox/layout.tsx @@ -1,5 +1,5 @@ import { RiAtLine } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Pré-Lançamentos | OpenMonetis", diff --git a/app/(dashboard)/pre-lancamentos/loading.tsx b/src/app/(dashboard)/inbox/loading.tsx similarity index 89% rename from app/(dashboard)/pre-lancamentos/loading.tsx rename to src/app/(dashboard)/inbox/loading.tsx index f3fdd73..44335fc 100644 --- a/app/(dashboard)/pre-lancamentos/loading.tsx +++ b/src/app/(dashboard)/inbox/loading.tsx @@ -1,5 +1,5 @@ -import { Card } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card } from "@/shared/components/ui/card"; +import { Skeleton } from "@/shared/components/ui/skeleton"; export default function Loading() { return ( diff --git a/app/(dashboard)/pre-lancamentos/page.tsx b/src/app/(dashboard)/inbox/page.tsx similarity index 80% rename from app/(dashboard)/pre-lancamentos/page.tsx rename to src/app/(dashboard)/inbox/page.tsx index 14526a0..b535760 100644 --- a/app/(dashboard)/pre-lancamentos/page.tsx +++ b/src/app/(dashboard)/inbox/page.tsx @@ -1,6 +1,10 @@ -import { InboxPage } from "@/components/pre-lancamentos/inbox-page"; -import { getUserId } from "@/lib/auth/server"; -import { fetchAppLogoMap, fetchInboxDialogData, fetchInboxItems } from "./data"; +import { InboxPage } from "@/features/inbox/components/inbox-page"; +import { + fetchAppLogoMap, + fetchInboxDialogData, + fetchInboxItems, +} from "@/features/inbox/queries"; +import { getUserId } from "@/shared/lib/auth/server"; export default async function Page() { const userId = await getUserId(); diff --git a/app/(dashboard)/insights/layout.tsx b/src/app/(dashboard)/insights/layout.tsx similarity index 88% rename from app/(dashboard)/insights/layout.tsx rename to src/app/(dashboard)/insights/layout.tsx index 97d8e7b..06b1ea0 100644 --- a/app/(dashboard)/insights/layout.tsx +++ b/src/app/(dashboard)/insights/layout.tsx @@ -1,5 +1,5 @@ import { RiSparklingLine } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Insights | OpenMonetis", diff --git a/app/(dashboard)/insights/loading.tsx b/src/app/(dashboard)/insights/loading.tsx similarity index 95% rename from app/(dashboard)/insights/loading.tsx rename to src/app/(dashboard)/insights/loading.tsx index bc92c05..98d3014 100644 --- a/app/(dashboard)/insights/loading.tsx +++ b/src/app/(dashboard)/insights/loading.tsx @@ -1,4 +1,4 @@ -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/shared/components/ui/skeleton"; /** * Loading state para a página de insights com IA diff --git a/app/(dashboard)/insights/page.tsx b/src/app/(dashboard)/insights/page.tsx similarity index 78% rename from app/(dashboard)/insights/page.tsx rename to src/app/(dashboard)/insights/page.tsx index 424118a..f0885e5 100644 --- a/app/(dashboard)/insights/page.tsx +++ b/src/app/(dashboard)/insights/page.tsx @@ -1,6 +1,6 @@ -import { InsightsPage } from "@/components/insights/insights-page"; -import MonthNavigation from "@/components/month-picker/month-navigation"; -import { parsePeriodParam } from "@/lib/utils/period"; +import { InsightsPage } from "@/features/insights/components/insights-page"; +import MonthNavigation from "@/shared/components/month-picker/month-navigation"; +import { parsePeriodParam } from "@/shared/utils/period"; type PageSearchParams = Promise>; diff --git a/app/(dashboard)/layout.tsx b/src/app/(dashboard)/layout.tsx similarity index 60% rename from app/(dashboard)/layout.tsx rename to src/app/(dashboard)/layout.tsx index 73f20e3..8a9b543 100644 --- a/app/(dashboard)/layout.tsx +++ b/src/app/(dashboard)/layout.tsx @@ -1,13 +1,13 @@ -import { AppNavbar } from "@/components/navigation/navbar/app-navbar"; -import { FontProvider } from "@/components/providers/font-provider"; -import { PrivacyProvider } from "@/components/providers/privacy-provider"; -import { getUserSession } from "@/lib/auth/server"; -import { fetchDashboardNotifications } from "@/lib/dashboard/notifications"; -import { fetchPagadoresWithAccess } from "@/lib/pagadores/access"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; -import { fetchUserFontPreferences } from "@/lib/preferences/fonts"; -import { parsePeriodParam } from "@/lib/utils/period"; -import { fetchPendingInboxCount } from "./pre-lancamentos/data"; +import { fetchDashboardNotifications } from "@/features/dashboard/notifications-queries"; +import { fetchPendingInboxCount } from "@/features/inbox/queries"; +import { AppNavbar } from "@/shared/components/navigation/navbar/app-navbar"; +import { FontProvider } from "@/shared/components/providers/font-provider"; +import { PrivacyProvider } from "@/shared/components/providers/privacy-provider"; +import { getUserSession } from "@/shared/lib/auth/server"; +import { fetchPagadoresWithAccess } from "@/shared/lib/payers/access"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { fetchUserFontPreferences } from "@/shared/lib/preferences/fonts"; +import { parsePeriodParam } from "@/shared/utils/period"; export default async function DashboardLayout({ children, @@ -36,16 +36,13 @@ export default async function DashboardLayout({ const { period: currentPeriod } = parsePeriodParam( singlePeriodoParam ?? null, ); - const notificationsSnapshot = await fetchDashboardNotifications( - session.user.id, - currentPeriod, - ); - - // Buscar contagem de pré-lançamentos pendentes e preferências de fonte - const [preLancamentosCount, fontPrefs] = await Promise.all([ - fetchPendingInboxCount(session.user.id), - fetchUserFontPreferences(session.user.id), - ]); + // Buscar notificações, contagem de pré-lançamentos e preferências de fonte em paralelo + const [notificationsSnapshot, preLancamentosCount, fontPrefs] = + await Promise.all([ + fetchDashboardNotifications(session.user.id, currentPeriod), + fetchPendingInboxCount(session.user.id), + fetchUserFontPreferences(session.user.id), + ]); return ( ; type PageProps = { - params: Promise<{ pagadorId: string }>; + params: Promise<{ payerId: string }>; searchParams?: PageSearchParams; }; @@ -90,7 +91,7 @@ const createEmptySlugMaps = (): SlugMaps => ({ type OptionSet = ReturnType; export default async function Page({ params, searchParams }: PageProps) { - const { pagadorId } = await params; + const { payerId: pagadorId } = await params; const userId = await getUserId(); const resolvedSearchParams = searchParams ? await searchParams : undefined; @@ -206,7 +207,7 @@ export default async function Page({ params, searchParams }: PageProps) { }), sharesPromise, currentUserSharePromise, - getRecentEstablishmentsAction(), + fetchRecentEstablishments(userId), fetchUserPreferences(userId), ]); @@ -403,90 +404,3 @@ export default async function Page({ params, searchParams }: PageProps) { ); } - -const normalizeOptionLabel = ( - value: string | null | undefined, - fallback: string, -) => (value?.trim().length ? value.trim() : fallback); - -function buildReadOnlyOptionSets( - items: LancamentoItem[], - pagador: typeof pagadores.$inferSelect, -): OptionSet { - const pagadorLabel = normalizeOptionLabel(pagador.name, "Pagador"); - const pagadorOptions: SelectOption[] = [ - { - value: pagador.id, - label: pagadorLabel, - slug: pagador.id, - }, - ]; - - const contaOptionsMap = new Map(); - const cartaoOptionsMap = new Map(); - const categoriaOptionsMap = new Map(); - - items.forEach((item) => { - if (item.contaId && !contaOptionsMap.has(item.contaId)) { - contaOptionsMap.set(item.contaId, { - value: item.contaId, - label: normalizeOptionLabel(item.contaName, "Conta sem nome"), - slug: item.contaId, - }); - } - if (item.cartaoId && !cartaoOptionsMap.has(item.cartaoId)) { - cartaoOptionsMap.set(item.cartaoId, { - value: item.cartaoId, - label: normalizeOptionLabel(item.cartaoName, "Cartão sem nome"), - slug: item.cartaoId, - }); - } - if (item.categoriaId && !categoriaOptionsMap.has(item.categoriaId)) { - categoriaOptionsMap.set(item.categoriaId, { - value: item.categoriaId, - label: normalizeOptionLabel(item.categoriaName, "Categoria"), - slug: item.categoriaId, - }); - } - }); - - const contaOptions = Array.from(contaOptionsMap.values()); - const cartaoOptions = Array.from(cartaoOptionsMap.values()); - const categoriaOptions = Array.from(categoriaOptionsMap.values()); - - const pagadorFilterOptions: LancamentoFilterOption[] = [ - { slug: pagador.id, label: pagadorLabel }, - ]; - - const categoriaFilterOptions: LancamentoFilterOption[] = categoriaOptions.map( - (option) => ({ - slug: option.value, - label: option.label, - }), - ); - - const contaCartaoFilterOptions: ContaCartaoFilterOption[] = [ - ...contaOptions.map((option) => ({ - slug: option.value, - label: option.label, - kind: "conta" as const, - })), - ...cartaoOptions.map((option) => ({ - slug: option.value, - label: option.label, - kind: "cartao" as const, - })), - ]; - - return { - pagadorOptions, - splitPagadorOptions: [], - defaultPagadorId: pagador.id, - contaOptions, - cartaoOptions, - categoriaOptions, - pagadorFilterOptions, - categoriaFilterOptions, - contaCartaoFilterOptions, - }; -} diff --git a/app/(dashboard)/pagadores/layout.tsx b/src/app/(dashboard)/payers/layout.tsx similarity index 87% rename from app/(dashboard)/pagadores/layout.tsx rename to src/app/(dashboard)/payers/layout.tsx index 7c97e11..c2595eb 100644 --- a/app/(dashboard)/pagadores/layout.tsx +++ b/src/app/(dashboard)/payers/layout.tsx @@ -1,5 +1,5 @@ import { RiGroupLine } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Pagadores | OpenMonetis", diff --git a/app/(dashboard)/pagadores/loading.tsx b/src/app/(dashboard)/payers/loading.tsx similarity index 97% rename from app/(dashboard)/pagadores/loading.tsx rename to src/app/(dashboard)/payers/loading.tsx index bbf3c35..944cf9e 100644 --- a/app/(dashboard)/pagadores/loading.tsx +++ b/src/app/(dashboard)/payers/loading.tsx @@ -1,4 +1,4 @@ -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/shared/components/ui/skeleton"; /** * Loading state para a página de pagadores diff --git a/app/(dashboard)/pagadores/page.tsx b/src/app/(dashboard)/payers/page.tsx similarity index 60% rename from app/(dashboard)/pagadores/page.tsx rename to src/app/(dashboard)/payers/page.tsx index 67008d3..ab7c4dd 100644 --- a/app/(dashboard)/pagadores/page.tsx +++ b/src/app/(dashboard)/payers/page.tsx @@ -1,6 +1,6 @@ -import { PagadoresPage } from "@/components/pagadores/pagadores-page"; -import { getUserId } from "@/lib/auth/server"; -import { fetchPagadoresForUser } from "./data"; +import { PagadoresPage } from "@/features/payers/components/payers-page"; +import { fetchPagadoresForUser } from "@/features/payers/queries"; +import { getUserId } from "@/shared/lib/auth/server"; export default async function Page() { const userId = await getUserId(); diff --git a/app/(dashboard)/relatorios/uso-cartoes/layout.tsx b/src/app/(dashboard)/reports/card-usage/layout.tsx similarity index 87% rename from app/(dashboard)/relatorios/uso-cartoes/layout.tsx rename to src/app/(dashboard)/reports/card-usage/layout.tsx index 8a54809..20d9071 100644 --- a/app/(dashboard)/relatorios/uso-cartoes/layout.tsx +++ b/src/app/(dashboard)/reports/card-usage/layout.tsx @@ -1,5 +1,5 @@ import { RiBankCard2Line } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Uso de Cartões | OpenMonetis", diff --git a/app/(dashboard)/relatorios/uso-cartoes/loading.tsx b/src/app/(dashboard)/reports/card-usage/loading.tsx similarity index 94% rename from app/(dashboard)/relatorios/uso-cartoes/loading.tsx rename to src/app/(dashboard)/reports/card-usage/loading.tsx index 8d91195..300a5be 100644 --- a/app/(dashboard)/relatorios/uso-cartoes/loading.tsx +++ b/src/app/(dashboard)/reports/card-usage/loading.tsx @@ -1,5 +1,5 @@ -import { Card, CardContent, CardHeader } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card, CardContent, CardHeader } from "@/shared/components/ui/card"; +import { Skeleton } from "@/shared/components/ui/skeleton"; export default function Loading() { return ( diff --git a/app/(dashboard)/relatorios/uso-cartoes/page.tsx b/src/app/(dashboard)/reports/card-usage/page.tsx similarity index 72% rename from app/(dashboard)/relatorios/uso-cartoes/page.tsx rename to src/app/(dashboard)/reports/card-usage/page.tsx index e35e36c..7c8ed68 100644 --- a/app/(dashboard)/relatorios/uso-cartoes/page.tsx +++ b/src/app/(dashboard)/reports/card-usage/page.tsx @@ -1,14 +1,14 @@ import { RiBankCard2Line } from "@remixicon/react"; -import MonthNavigation from "@/components/month-picker/month-navigation"; -import { CardCategoryBreakdown } from "@/components/relatorios/cartoes/card-category-breakdown"; -import { CardInvoiceStatus } from "@/components/relatorios/cartoes/card-invoice-status"; -import { CardTopExpenses } from "@/components/relatorios/cartoes/card-top-expenses"; -import { CardUsageChart } from "@/components/relatorios/cartoes/card-usage-chart"; -import { CardsOverview } from "@/components/relatorios/cartoes/cards-overview"; -import { Card } from "@/components/ui/card"; -import { getUser } from "@/lib/auth/server"; -import { fetchCartoesReportData } from "@/lib/relatorios/cartoes-report"; -import { parsePeriodParam } from "@/lib/utils/period"; +import { fetchCartoesReportData } from "@/features/reports/cards-report-queries"; +import { CardCategoryBreakdown } from "@/features/reports/components/cards/card-category-breakdown"; +import { CardInvoiceStatus } from "@/features/reports/components/cards/card-invoice-status"; +import { CardTopExpenses } from "@/features/reports/components/cards/card-top-expenses"; +import { CardUsageChart } from "@/features/reports/components/cards/card-usage-chart"; +import { CardsOverview } from "@/features/reports/components/cards/cards-overview"; +import MonthNavigation from "@/shared/components/month-picker/month-navigation"; +import { Card } from "@/shared/components/ui/card"; +import { getUser } from "@/shared/lib/auth/server"; +import { parsePeriodParam } from "@/shared/utils/period"; type PageSearchParams = Promise>; diff --git a/app/(dashboard)/relatorios/tendencias/layout.tsx b/src/app/(dashboard)/reports/category-trends/layout.tsx similarity index 88% rename from app/(dashboard)/relatorios/tendencias/layout.tsx rename to src/app/(dashboard)/reports/category-trends/layout.tsx index a496fd9..7f0f098 100644 --- a/app/(dashboard)/relatorios/tendencias/layout.tsx +++ b/src/app/(dashboard)/reports/category-trends/layout.tsx @@ -1,5 +1,5 @@ import { RiFileChartLine } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Tendências | OpenMonetis", diff --git a/app/(dashboard)/relatorios/tendencias/loading.tsx b/src/app/(dashboard)/reports/category-trends/loading.tsx similarity index 72% rename from app/(dashboard)/relatorios/tendencias/loading.tsx rename to src/app/(dashboard)/reports/category-trends/loading.tsx index bedc39a..547f9cc 100644 --- a/app/(dashboard)/relatorios/tendencias/loading.tsx +++ b/src/app/(dashboard)/reports/category-trends/loading.tsx @@ -1,4 +1,4 @@ -import { CategoryReportSkeleton } from "@/components/shared/skeletons/category-report-skeleton"; +import { CategoryReportSkeleton } from "@/shared/components/skeletons/category-report-skeleton"; export default function Loading() { return ( diff --git a/app/(dashboard)/relatorios/tendencias/page.tsx b/src/app/(dashboard)/reports/category-trends/page.tsx similarity index 79% rename from app/(dashboard)/relatorios/tendencias/page.tsx rename to src/app/(dashboard)/reports/category-trends/page.tsx index 882264c..c90ddc3 100644 --- a/app/(dashboard)/relatorios/tendencias/page.tsx +++ b/src/app/(dashboard)/reports/category-trends/page.tsx @@ -1,17 +1,17 @@ import { redirect } from "next/navigation"; -import { CategoryReportPage } from "@/components/relatorios/category-report-page"; +import type { Categoria } from "@/db/schema"; +import { fetchCategoryChartData } from "@/features/reports/category-chart-queries"; +import { fetchCategoryReport } from "@/features/reports/category-report-queries"; +import { fetchUserCategories } from "@/features/reports/category-trends-queries"; +import { CategoryReportPage } from "@/features/reports/components/category-report-page"; import type { CategoryOption, FilterState, -} from "@/components/relatorios/types"; -import type { Categoria } from "@/db/schema"; -import { getUserId } from "@/lib/auth/server"; -import { fetchCategoryChartData } from "@/lib/relatorios/fetch-category-chart-data"; -import { fetchCategoryReport } from "@/lib/relatorios/fetch-category-report"; -import type { CategoryReportFilters } from "@/lib/types/relatorios"; -import { validateDateRange } from "@/lib/relatorios/utils"; -import { addMonthsToPeriod, getCurrentPeriod } from "@/lib/utils/period"; -import { fetchUserCategories } from "./data"; +} from "@/features/reports/components/types"; +import { validateDateRange } from "@/features/reports/utils"; +import { getUserId } from "@/shared/lib/auth/server"; +import type { CategoryReportFilters } from "@/shared/lib/types/reports"; +import { addMonthsToPeriod, getCurrentPeriod } from "@/shared/utils/period"; type PageSearchParams = Promise>; @@ -58,7 +58,7 @@ export default async function Page({ searchParams }: PageProps) { if (!validation.isValid) { // Redirect to default if validation fails redirect( - `/relatorios/tendencias?inicio=${defaultStartPeriod}&fim=${currentPeriod}`, + `/reports/category-trends?inicio=${defaultStartPeriod}&fim=${currentPeriod}`, ); } diff --git a/app/(dashboard)/relatorios/estabelecimentos/layout.tsx b/src/app/(dashboard)/reports/establishments/layout.tsx similarity index 87% rename from app/(dashboard)/relatorios/estabelecimentos/layout.tsx rename to src/app/(dashboard)/reports/establishments/layout.tsx index 95d9e9a..802cfd0 100644 --- a/app/(dashboard)/relatorios/estabelecimentos/layout.tsx +++ b/src/app/(dashboard)/reports/establishments/layout.tsx @@ -1,5 +1,5 @@ import { RiStore2Line } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Top Estabelecimentos | OpenMonetis", diff --git a/app/(dashboard)/relatorios/estabelecimentos/loading.tsx b/src/app/(dashboard)/reports/establishments/loading.tsx similarity index 91% rename from app/(dashboard)/relatorios/estabelecimentos/loading.tsx rename to src/app/(dashboard)/reports/establishments/loading.tsx index 78728d1..9a1590c 100644 --- a/app/(dashboard)/relatorios/estabelecimentos/loading.tsx +++ b/src/app/(dashboard)/reports/establishments/loading.tsx @@ -1,5 +1,5 @@ -import { Card, CardContent, CardHeader } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card, CardContent, CardHeader } from "@/shared/components/ui/card"; +import { Skeleton } from "@/shared/components/ui/skeleton"; export default function Loading() { return ( diff --git a/app/(dashboard)/relatorios/estabelecimentos/page.tsx b/src/app/(dashboard)/reports/establishments/page.tsx similarity index 71% rename from app/(dashboard)/relatorios/estabelecimentos/page.tsx rename to src/app/(dashboard)/reports/establishments/page.tsx index 4634366..16e0d79 100644 --- a/app/(dashboard)/relatorios/estabelecimentos/page.tsx +++ b/src/app/(dashboard)/reports/establishments/page.tsx @@ -1,15 +1,15 @@ -import { EstablishmentsList } from "@/components/relatorios/estabelecimentos/establishments-list"; -import { HighlightsCards } from "@/components/relatorios/estabelecimentos/highlights-cards"; -import { PeriodFilterButtons } from "@/components/relatorios/estabelecimentos/period-filter"; -import { SummaryCards } from "@/components/relatorios/estabelecimentos/summary-cards"; -import { TopCategories } from "@/components/relatorios/estabelecimentos/top-categories"; -import { Card } from "@/components/ui/card"; -import { getUser } from "@/lib/auth/server"; +import { EstablishmentsList } from "@/features/reports/components/establishments/establishments-list"; +import { HighlightsCards } from "@/features/reports/components/establishments/highlights-cards"; +import { PeriodFilterButtons } from "@/features/reports/components/establishments/period-filter"; +import { SummaryCards } from "@/features/reports/components/establishments/summary-cards"; +import { TopCategories } from "@/features/reports/components/establishments/top-categories"; import { fetchTopEstabelecimentosData, type PeriodFilter, -} from "@/lib/relatorios/estabelecimentos/fetch-data"; -import { parsePeriodParam } from "@/lib/utils/period"; +} from "@/features/reports/establishments/queries"; +import { Card } from "@/shared/components/ui/card"; +import { getUser } from "@/shared/lib/auth/server"; +import { parsePeriodParam } from "@/shared/utils/period"; type PageSearchParams = Promise>; diff --git a/app/(dashboard)/relatorios/analise-parcelas/layout.tsx b/src/app/(dashboard)/reports/installment-analysis/layout.tsx similarity index 88% rename from app/(dashboard)/relatorios/analise-parcelas/layout.tsx rename to src/app/(dashboard)/reports/installment-analysis/layout.tsx index 85d107a..db9a20a 100644 --- a/app/(dashboard)/relatorios/analise-parcelas/layout.tsx +++ b/src/app/(dashboard)/reports/installment-analysis/layout.tsx @@ -1,5 +1,5 @@ import { RiSecurePaymentLine } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Análise de Parcelas | OpenMonetis", diff --git a/src/app/(dashboard)/reports/installment-analysis/page.tsx b/src/app/(dashboard)/reports/installment-analysis/page.tsx new file mode 100644 index 0000000..278505a --- /dev/null +++ b/src/app/(dashboard)/reports/installment-analysis/page.tsx @@ -0,0 +1,14 @@ +import { InstallmentAnalysisPage } from "@/features/dashboard/components/installment-analysis/installment-analysis-page"; +import { fetchInstallmentAnalysis } from "@/features/dashboard/expenses/installment-analysis-queries"; +import { getUser } from "@/shared/lib/auth/server"; + +export default async function Page() { + const user = await getUser(); + const data = await fetchInstallmentAnalysis(user.id); + + return ( +
+ +
+ ); +} diff --git a/app/(dashboard)/changelog/layout.tsx b/src/app/(dashboard)/settings/changelog/layout.tsx similarity index 87% rename from app/(dashboard)/changelog/layout.tsx rename to src/app/(dashboard)/settings/changelog/layout.tsx index ebf41f6..226f8f2 100644 --- a/app/(dashboard)/changelog/layout.tsx +++ b/src/app/(dashboard)/settings/changelog/layout.tsx @@ -1,5 +1,5 @@ import { RiHistoryLine } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Cartões | OpenMonetis", diff --git a/app/(dashboard)/changelog/page.tsx b/src/app/(dashboard)/settings/changelog/page.tsx similarity index 53% rename from app/(dashboard)/changelog/page.tsx rename to src/app/(dashboard)/settings/changelog/page.tsx index bbc8d46..34069d6 100644 --- a/app/(dashboard)/changelog/page.tsx +++ b/src/app/(dashboard)/settings/changelog/page.tsx @@ -1,5 +1,5 @@ -import { ChangelogTab } from "@/components/ajustes/changelog-tab"; -import { parseChangelog } from "@/lib/changelog/parse-changelog"; +import { ChangelogTab } from "@/features/settings/components/changelog-tab"; +import { parseChangelog } from "@/features/settings/lib/parse-changelog"; export default function ChangelogPage() { const versions = parseChangelog(); diff --git a/app/(dashboard)/ajustes/layout.tsx b/src/app/(dashboard)/settings/layout.tsx similarity index 88% rename from app/(dashboard)/ajustes/layout.tsx rename to src/app/(dashboard)/settings/layout.tsx index 4ca3c5b..5e69f3d 100644 --- a/app/(dashboard)/ajustes/layout.tsx +++ b/src/app/(dashboard)/settings/layout.tsx @@ -1,5 +1,5 @@ import { RiSettings2Line } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Ajustes | OpenMonetis", diff --git a/app/(dashboard)/ajustes/page.tsx b/src/app/(dashboard)/settings/page.tsx similarity index 86% rename from app/(dashboard)/ajustes/page.tsx rename to src/app/(dashboard)/settings/page.tsx index 23e34ae..450667e 100644 --- a/app/(dashboard)/ajustes/page.tsx +++ b/src/app/(dashboard)/settings/page.tsx @@ -2,18 +2,23 @@ import { RiArrowRightSLine } from "@remixicon/react"; import { headers } from "next/headers"; import { redirect } from "next/navigation"; -import { CompanionTab } from "@/components/ajustes/companion-tab"; -import { DeleteAccountForm } from "@/components/ajustes/delete-account-form"; -import { PasskeysForm } from "@/components/ajustes/passkeys-form"; -import { PreferencesForm } from "@/components/ajustes/preferences-form"; -import { UpdateEmailForm } from "@/components/ajustes/update-email-form"; -import { UpdateNameForm } from "@/components/ajustes/update-name-form"; -import { UpdatePasswordForm } from "@/components/ajustes/update-password-form"; -import { Card } from "@/components/ui/card"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { auth } from "@/lib/auth/config"; +import { CompanionTab } from "@/features/settings/components/companion-tab"; +import { DeleteAccountForm } from "@/features/settings/components/delete-account-form"; +import { PasskeysForm } from "@/features/settings/components/passkeys-form"; +import { PreferencesForm } from "@/features/settings/components/preferences-form"; +import { UpdateEmailForm } from "@/features/settings/components/update-email-form"; +import { UpdateNameForm } from "@/features/settings/components/update-name-form"; +import { UpdatePasswordForm } from "@/features/settings/components/update-password-form"; +import { fetchAjustesPageData } from "@/features/settings/queries"; import { DEFAULT_FONT_KEY } from "@/public/fonts/font_index"; -import { fetchAjustesPageData } from "./data"; +import { Card } from "@/shared/components/ui/card"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/shared/components/ui/tabs"; +import { auth } from "@/shared/lib/auth/config"; export default async function Page() { const session = await auth.api.getSession({ diff --git a/app/(dashboard)/lancamentos/layout.tsx b/src/app/(dashboard)/transactions/layout.tsx similarity index 90% rename from app/(dashboard)/lancamentos/layout.tsx rename to src/app/(dashboard)/transactions/layout.tsx index 4a19089..23477de 100644 --- a/app/(dashboard)/lancamentos/layout.tsx +++ b/src/app/(dashboard)/transactions/layout.tsx @@ -1,5 +1,5 @@ import { RiArrowLeftRightLine } from "@remixicon/react"; -import PageDescription from "@/components/shared/page-description"; +import PageDescription from "@/shared/components/page-description"; export const metadata = { title: "Lançamentos | OpenMonetis", diff --git a/app/(dashboard)/lancamentos/loading.tsx b/src/app/(dashboard)/transactions/loading.tsx similarity index 88% rename from app/(dashboard)/lancamentos/loading.tsx rename to src/app/(dashboard)/transactions/loading.tsx index 2eeb034..8fae457 100644 --- a/app/(dashboard)/lancamentos/loading.tsx +++ b/src/app/(dashboard)/transactions/loading.tsx @@ -1,8 +1,8 @@ import { FilterSkeleton, TransactionsTableSkeleton, -} from "@/components/shared/skeletons"; -import { Skeleton } from "@/components/ui/skeleton"; +} from "@/shared/components/skeletons"; +import { Skeleton } from "@/shared/components/ui/skeleton"; /** * Loading state para a página de lançamentos diff --git a/app/(dashboard)/lancamentos/page.tsx b/src/app/(dashboard)/transactions/page.tsx similarity index 74% rename from app/(dashboard)/lancamentos/page.tsx rename to src/app/(dashboard)/transactions/page.tsx index 5cd3fad..2a2281a 100644 --- a/app/(dashboard)/lancamentos/page.tsx +++ b/src/app/(dashboard)/transactions/page.tsx @@ -1,21 +1,24 @@ -import { fetchUserPreferences } from "@/app/(dashboard)/ajustes/data"; -import { LancamentosPage } from "@/components/lancamentos/page/lancamentos-page"; -import MonthNavigation from "@/components/month-picker/month-navigation"; -import { getUserId } from "@/lib/auth/server"; +import { triggerRecurringGeneration } from "@/features/recurring/trigger-recurring-generation"; +import { fetchUserPreferences } from "@/features/settings/queries"; +import { LancamentosPage } from "@/features/transactions/components/page/transactions-page"; import { buildLancamentoWhere, buildOptionSets, buildSluggedFilters, buildSlugMaps, extractLancamentoSearchFilters, - fetchLancamentoFilterSources, getSingleParam, mapLancamentosData, type ResolvedSearchParams, -} from "@/lib/lancamentos/page-helpers"; -import { parsePeriodParam } from "@/lib/utils/period"; -import { getRecentEstablishmentsAction } from "./actions"; -import { fetchLancamentos } from "./data"; +} from "@/features/transactions/page-helpers"; +import { + fetchLancamentoFilterSources, + fetchLancamentos, + fetchRecentEstablishments, +} from "@/features/transactions/queries"; +import MonthNavigation from "@/shared/components/month-picker/month-navigation"; +import { getUserId } from "@/shared/lib/auth/server"; +import { parsePeriodParam } from "@/shared/utils/period"; type PageSearchParams = Promise; @@ -25,6 +28,7 @@ type PageProps = { export default async function Page({ searchParams }: PageProps) { const userId = await getUserId(); + await triggerRecurringGeneration(userId); const resolvedSearchParams = searchParams ? await searchParams : undefined; const periodoParamRaw = getSingleParam(resolvedSearchParams, "periodo"); @@ -47,7 +51,10 @@ export default async function Page({ searchParams }: PageProps) { slugMaps, }); - const lancamentoRows = await fetchLancamentos(filters); + const [lancamentoRows, estabelecimentos] = await Promise.all([ + fetchLancamentos(filters), + fetchRecentEstablishments(userId), + ]); const lancamentosData = mapLancamentosData(lancamentoRows); const { @@ -65,8 +72,6 @@ export default async function Page({ searchParams }: PageProps) { pagadorRows: filterSources.pagadorRows, }); - const estabelecimentos = await getRecentEstablishmentsAction(); - return (
diff --git a/app/(landing-page)/layout.tsx b/src/app/(landing-page)/layout.tsx similarity index 95% rename from app/(landing-page)/layout.tsx rename to src/app/(landing-page)/layout.tsx index 6a5a75c..75477a0 100644 --- a/app/(landing-page)/layout.tsx +++ b/src/app/(landing-page)/layout.tsx @@ -36,7 +36,7 @@ export const metadata: Metadata = { description: DESCRIPTION, images: [ { - url: "/imagens/dashboard-preview-light.webp", + url: "/images/dashboard-preview-light.webp", width: 1920, height: 1080, alt: "OpenMonetis — Dashboard de finanças pessoais", @@ -47,7 +47,7 @@ export const metadata: Metadata = { card: "summary_large_image", title: TITLE, description: DESCRIPTION, - images: ["/imagens/dashboard-preview-light.webp"], + images: ["/images/dashboard-preview-light.webp"], }, robots: { index: true, diff --git a/app/(landing-page)/page.tsx b/src/app/(landing-page)/page.tsx similarity index 96% rename from app/(landing-page)/page.tsx rename to src/app/(landing-page)/page.tsx index 3732756..5ee532a 100644 --- a/app/(landing-page)/page.tsx +++ b/src/app/(landing-page)/page.tsx @@ -30,15 +30,15 @@ import { import { headers } from "next/headers"; import Image from "next/image"; import Link from "next/link"; -import { AnimateOnScroll } from "@/components/landing/animate-on-scroll"; -import { MobileNav } from "@/components/landing/mobile-nav"; -import { SetupTabs } from "@/components/landing/setup-tabs"; -import { AnimatedThemeToggler } from "@/components/shared/animated-theme-toggler"; -import { Logo } from "@/components/shared/logo"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; -import { getOptionalUserSession } from "@/lib/auth/server"; +import { AnimateOnScroll } from "@/features/landing/components/animate-on-scroll"; +import { MobileNav } from "@/features/landing/components/mobile-nav"; +import { SetupTabs } from "@/features/landing/components/setup-tabs"; +import { AnimatedThemeToggler } from "@/shared/components/animated-theme-toggler"; +import { Logo } from "@/shared/components/logo"; +import { Badge } from "@/shared/components/ui/badge"; +import { Button } from "@/shared/components/ui/button"; +import { Card, CardContent } from "@/shared/components/ui/card"; +import { getOptionalUserSession } from "@/shared/lib/auth/server"; const mainFeatures = [ { @@ -120,20 +120,20 @@ const screenshotSections = [ { title: "Lançamentos", description: "Registre e organize todas as suas transações financeiras", - lightSrc: "/imagens/preview-lancamentos-light.webp", - darkSrc: "/imagens/preview-lancamentos-dark.webp", + lightSrc: "/images/preview-lancamentos-light.webp", + darkSrc: "/images/preview-lancamentos-dark.webp", }, { title: "Calendário", description: "Visualize suas finanças no calendário mensal", - lightSrc: "/imagens/preview-calendario-light.webp", - darkSrc: "/imagens/preview-calendario-dark.webp", + lightSrc: "/images/preview-calendario-light.webp", + darkSrc: "/images/preview-calendario-dark.webp", }, { title: "Cartões", description: "Acompanhe faturas, limites e vencimentos dos seus cartões", - lightSrc: "/imagens/preview-cartao-light.webp", - darkSrc: "/imagens/preview-cartao-dark.webp", + lightSrc: "/images/preview-cartao-light.webp", + darkSrc: "/images/preview-cartao-dark.webp", }, ]; @@ -353,7 +353,7 @@ export default async function Page() {
openmonetis Dashboard Preview openmonetis Dashboard Preview
OpenMonetis Companion App; diff --git a/app/api/auth/device/tokens/route.ts b/src/app/api/auth/device/tokens/route.ts similarity index 92% rename from app/api/auth/device/tokens/route.ts rename to src/app/api/auth/device/tokens/route.ts index 3842316..6613600 100644 --- a/app/api/auth/device/tokens/route.ts +++ b/src/app/api/auth/device/tokens/route.ts @@ -2,8 +2,8 @@ import { and, desc, eq, isNull } from "drizzle-orm"; import { headers } from "next/headers"; import { NextResponse } from "next/server"; import { tokensApi } from "@/db/schema"; -import { auth } from "@/lib/auth/config"; -import { db } from "@/lib/db"; +import { auth } from "@/shared/lib/auth/config"; +import { db } from "@/shared/lib/db"; export async function GET() { try { diff --git a/app/api/auth/device/verify/route.ts b/src/app/api/auth/device/verify/route.ts similarity index 93% rename from app/api/auth/device/verify/route.ts rename to src/app/api/auth/device/verify/route.ts index 7e71724..a197359 100644 --- a/app/api/auth/device/verify/route.ts +++ b/src/app/api/auth/device/verify/route.ts @@ -1,8 +1,8 @@ import { and, eq, isNull } from "drizzle-orm"; import { NextResponse } from "next/server"; import { tokensApi } from "@/db/schema"; -import { extractBearerToken, hashToken } from "@/lib/auth/api-token"; -import { db } from "@/lib/db"; +import { extractBearerToken, hashToken } from "@/shared/lib/auth/api-token"; +import { db } from "@/shared/lib/db"; export async function POST(request: Request) { try { diff --git a/app/api/health/route.ts b/src/app/api/health/route.ts similarity index 96% rename from app/api/health/route.ts rename to src/app/api/health/route.ts index 955092f..17d1054 100644 --- a/app/api/health/route.ts +++ b/src/app/api/health/route.ts @@ -1,5 +1,5 @@ import { NextResponse } from "next/server"; -import { db } from "@/lib/db"; +import { db } from "@/shared/lib/db"; const APP_VERSION = "1.0.0"; diff --git a/app/api/inbox/batch/route.ts b/src/app/api/inbox/batch/route.ts similarity index 95% rename from app/api/inbox/batch/route.ts rename to src/app/api/inbox/batch/route.ts index c4d618b..52cfd74 100644 --- a/app/api/inbox/batch/route.ts +++ b/src/app/api/inbox/batch/route.ts @@ -2,9 +2,9 @@ import { and, eq, isNull } from "drizzle-orm"; import { NextResponse } from "next/server"; import { z } from "zod"; import { preLancamentos, tokensApi } from "@/db/schema"; -import { extractBearerToken, hashToken } from "@/lib/auth/api-token"; -import { db } from "@/lib/db"; -import { inboxBatchSchema } from "@/lib/schemas/inbox"; +import { extractBearerToken, hashToken } from "@/shared/lib/auth/api-token"; +import { db } from "@/shared/lib/db"; +import { inboxBatchSchema } from "@/shared/lib/schemas/inbox"; // Rate limiting simples em memória const rateLimitMap = new Map(); diff --git a/app/api/inbox/route.ts b/src/app/api/inbox/route.ts similarity index 94% rename from app/api/inbox/route.ts rename to src/app/api/inbox/route.ts index eb9adac..d4425cf 100644 --- a/app/api/inbox/route.ts +++ b/src/app/api/inbox/route.ts @@ -2,9 +2,9 @@ import { and, eq, isNull } from "drizzle-orm"; import { NextResponse } from "next/server"; import { z } from "zod"; import { preLancamentos, tokensApi } from "@/db/schema"; -import { extractBearerToken, hashToken } from "@/lib/auth/api-token"; -import { db } from "@/lib/db"; -import { inboxItemSchema } from "@/lib/schemas/inbox"; +import { extractBearerToken, hashToken } from "@/shared/lib/auth/api-token"; +import { db } from "@/shared/lib/db"; +import { inboxItemSchema } from "@/shared/lib/schemas/inbox"; // Rate limiting simples em memória (em produção, use Redis) const rateLimitMap = new Map(); diff --git a/app/apple-icon.png b/src/app/apple-icon.png similarity index 100% rename from app/apple-icon.png rename to src/app/apple-icon.png diff --git a/app/error.tsx b/src/app/error.tsx similarity index 93% rename from app/error.tsx rename to src/app/error.tsx index 38e35ee..80e6b44 100644 --- a/app/error.tsx +++ b/src/app/error.tsx @@ -4,7 +4,7 @@ import { RiErrorWarningFill } from "@remixicon/react"; import Link from "next/link"; import { useEffect } from "react"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/shared/components/ui/button"; import { Empty, EmptyContent, @@ -12,7 +12,7 @@ import { EmptyHeader, EmptyMedia, EmptyTitle, -} from "@/components/ui/empty"; +} from "@/shared/components/ui/empty"; export default function ErrorComponent({ error, diff --git a/app/favicon.ico b/src/app/favicon.ico similarity index 100% rename from app/favicon.ico rename to src/app/favicon.ico diff --git a/app/globals.css b/src/app/globals.css similarity index 99% rename from app/globals.css rename to src/app/globals.css index 69133e7..a5668fe 100644 --- a/app/globals.css +++ b/src/app/globals.css @@ -15,14 +15,14 @@ /* Base surfaces - warm cream with subtle orange undertone */ --background: oklch(98.01% 0.00331 67.026); - --foreground: #0a0a0a; + --foreground: #201207; --card: var(--background); - --card-foreground: #0a0a0a; + --card-foreground: #201207; --popover: oklch(99.5% 0.004 80); --popover-foreground: oklch(18% 0.02 45); /* Primary - rich terracotta orange */ - --primary: #fc712b; + --primary: #f17a35; --primary-foreground: oklch(98% 0.008 80); /* Secondary - warm stone with subtle saturation */ diff --git a/app/icon0.svg b/src/app/icon0.svg similarity index 100% rename from app/icon0.svg rename to src/app/icon0.svg diff --git a/app/icon1.png b/src/app/icon1.png similarity index 100% rename from app/icon1.png rename to src/app/icon1.png diff --git a/app/layout.tsx b/src/app/layout.tsx similarity index 88% rename from app/layout.tsx rename to src/app/layout.tsx index e64e228..0ab25e7 100644 --- a/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,9 +1,9 @@ import { Analytics } from "@vercel/analytics/next"; import { SpeedInsights } from "@vercel/speed-insights/next"; import type { Metadata } from "next"; -import { ThemeProvider } from "@/components/providers/theme-provider"; -import { Toaster } from "@/components/ui/sonner"; import { allFontVariables } from "@/public/fonts/font_index"; +import { ThemeProvider } from "@/shared/components/providers/theme-provider"; +import { Toaster } from "@/shared/components/ui/sonner"; import "./globals.css"; export const metadata: Metadata = { diff --git a/app/manifest.json b/src/app/manifest.json similarity index 75% rename from app/manifest.json rename to src/app/manifest.json index 571ea6c..66fe7a5 100644 --- a/app/manifest.json +++ b/src/app/manifest.json @@ -3,13 +3,13 @@ "short_name": "OpenMonetis", "icons": [ { - "src": "/imagens/web-app-manifest-192x192.png", + "src": "/images/web-app-manifest-192x192.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/imagens/web-app-manifest-512x512.png", + "src": "/images/web-app-manifest-512x512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/app/not-found.tsx b/src/app/not-found.tsx similarity index 90% rename from app/not-found.tsx rename to src/app/not-found.tsx index 0959f78..e96cf42 100644 --- a/app/not-found.tsx +++ b/src/app/not-found.tsx @@ -1,7 +1,7 @@ import { RiFileSearchLine } from "@remixicon/react"; import Link from "next/link"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/shared/components/ui/button"; import { Empty, EmptyContent, @@ -9,7 +9,7 @@ import { EmptyHeader, EmptyMedia, EmptyTitle, -} from "@/components/ui/empty"; +} from "@/shared/components/ui/empty"; export default function NotFound() { return ( diff --git a/app/robots.ts b/src/app/robots.ts similarity index 67% rename from app/robots.ts rename to src/app/robots.ts index 446c333..d79f966 100644 --- a/app/robots.ts +++ b/src/app/robots.ts @@ -12,19 +12,19 @@ export default function robots(): MetadataRoute.Robots { allow: "/", disallow: [ "/dashboard", - "/lancamentos", - "/contas", - "/cartoes", - "/categorias", - "/orcamentos", - "/pagadores", - "/anotacoes", + "/transactions", + "/accounts", + "/cards", + "/categories", + "/budgets", + "/payers", + "/notes", "/insights", - "/calendario", + "/calendar", "/consultor", - "/ajustes", - "/relatorios", - "/pre-lancamentos", + "/settings", + "/reports", + "/inbox", "/login", "/api/", ], diff --git a/app/sitemap.ts b/src/app/sitemap.ts similarity index 100% rename from app/sitemap.ts rename to src/app/sitemap.ts diff --git a/db/schema.ts b/src/db/schema.ts similarity index 92% rename from db/schema.ts rename to src/db/schema.ts index f4ae871..66bd5f2 100644 --- a/db/schema.ts +++ b/src/db/schema.ts @@ -561,6 +561,57 @@ export const antecipacoesParcelas = pgTable( }), ); +// ===================== RECURRING SERIES ===================== + +export type RecurringSeriesTemplate = { + name: string; + amount: string; + transactionType: string; + paymentMethod: string; + categoriaId: string | null; + contaId: string | null; + cartaoId: string | null; + pagadorId: string | null; + note: string | null; + condition: string; +}; + +export const recurringSeries = pgTable( + "recurring_series", + { + id: uuid("id").primaryKey().default(sql`gen_random_uuid()`), + userId: text("user_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + status: text("status").notNull().default("active"), // "active" | "paused" | "cancelled" + dayOfMonth: smallint("day_of_month").notNull(), + lastGeneratedPeriod: text("last_generated_period").notNull(), // YYYY-MM + templateData: jsonb("template_data") + .notNull() + .$type(), + createdAt: timestamp("created_at", { + mode: "date", + withTimezone: true, + }) + .notNull() + .defaultNow(), + updatedAt: timestamp("updated_at", { + mode: "date", + withTimezone: true, + }) + .notNull() + .defaultNow(), + }, + (table) => ({ + userIdStatusIdx: index("recurring_series_user_id_status_idx").on( + table.userId, + table.status, + ), + }), +); + +// ===================== LANCAMENTOS ===================== + export const lancamentos = pgTable( "lancamentos", { @@ -612,6 +663,10 @@ export const lancamentos = pgTable( }), seriesId: uuid("series_id"), transferId: uuid("transfer_id"), + recurringSeriesId: uuid("recurring_series_id").references( + () => recurringSeries.id, + { onDelete: "set null" }, + ), }, (table) => ({ // Índice composto mais importante: userId + period (usado em quase todas as queries do dashboard) @@ -666,6 +721,7 @@ export const userRelations = relations(user, ({ many, one }) => ({ antecipacoesParcelas: many(antecipacoesParcelas), tokensApi: many(tokensApi), preLancamentos: many(preLancamentos), + recurringSeries: many(recurringSeries), })); export const accountRelations = relations(account, ({ one }) => ({ @@ -819,8 +875,23 @@ export const lancamentosRelations = relations(lancamentos, ({ one }) => ({ fields: [lancamentos.anticipationId], references: [antecipacoesParcelas.id], }), + recurringSeries: one(recurringSeries, { + fields: [lancamentos.recurringSeriesId], + references: [recurringSeries.id], + }), })); +export const recurringSeriesRelations = relations( + recurringSeries, + ({ one, many }) => ({ + user: one(user, { + fields: [recurringSeries.userId], + references: [user.id], + }), + lancamentos: many(lancamentos), + }), +); + export const antecipacoesParcRelations = relations( antecipacoesParcelas, ({ one, many }) => ({ @@ -866,3 +937,5 @@ export type TokenApi = typeof tokensApi.$inferSelect; export type NovoTokenApi = typeof tokensApi.$inferInsert; export type PreLancamento = typeof preLancamentos.$inferSelect; export type NovoPreLancamento = typeof preLancamentos.$inferInsert; +export type RecurringSeries = typeof recurringSeries.$inferSelect; +export type NewRecurringSeries = typeof recurringSeries.$inferInsert; diff --git a/app/(dashboard)/contas/actions.ts b/src/features/accounts/actions.ts similarity index 95% rename from app/(dashboard)/contas/actions.ts rename to src/features/accounts/actions.ts index 3e7272b..d36f4f4 100644 --- a/app/(dashboard)/contas/actions.ts +++ b/src/features/accounts/actions.ts @@ -3,32 +3,32 @@ import { and, eq } from "drizzle-orm"; import { z } from "zod"; import { categorias, contas, lancamentos, pagadores } from "@/db/schema"; -import { - type ActionResult, - handleActionError, - revalidateForEntity, -} from "@/lib/actions/helpers"; -import { getUser } from "@/lib/auth/server"; import { INITIAL_BALANCE_CATEGORY_NAME, INITIAL_BALANCE_CONDITION, INITIAL_BALANCE_NOTE, INITIAL_BALANCE_PAYMENT_METHOD, INITIAL_BALANCE_TRANSACTION_TYPE, -} from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; -import { noteSchema, uuidSchema } from "@/lib/schemas/common"; +} from "@/shared/lib/accounts/constants"; +import { + type ActionResult, + handleActionError, + revalidateForEntity, +} from "@/shared/lib/actions/helpers"; +import { getUser } from "@/shared/lib/auth/server"; +import { db } from "@/shared/lib/db"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { noteSchema, uuidSchema } from "@/shared/lib/schemas/common"; import { TRANSFER_CATEGORY_NAME, TRANSFER_CONDITION, TRANSFER_ESTABLISHMENT_ENTRADA, TRANSFER_ESTABLISHMENT_SAIDA, TRANSFER_PAYMENT_METHOD, -} from "@/lib/transferencias/constants"; -import { formatDecimalForDbRequired } from "@/lib/utils/currency"; -import { getTodayInfo } from "@/lib/utils/date"; -import { normalizeFilePath } from "@/lib/utils/string"; +} from "@/shared/lib/transfers/constants"; +import { formatDecimalForDbRequired } from "@/shared/utils/currency"; +import { getTodayInfo } from "@/shared/utils/date"; +import { normalizeFilePath } from "@/shared/utils/string"; const accountBaseSchema = z.object({ name: z diff --git a/components/contas/account-card.tsx b/src/features/accounts/components/account-card.tsx similarity index 93% rename from components/contas/account-card.tsx rename to src/features/accounts/components/account-card.tsx index fe32cc1..d323159 100644 --- a/components/contas/account-card.tsx +++ b/src/features/accounts/components/account-card.tsx @@ -7,10 +7,14 @@ import { RiPencilLine, } from "@remixicon/react"; import type React from "react"; -import { cn } from "@/lib/utils/ui"; -import MoneyValues from "@/components/shared/money-values"; -import { Card, CardContent, CardFooter } from "../ui/card"; -import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip"; +import MoneyValues from "@/shared/components/money-values"; +import { Card, CardContent, CardFooter } from "@/shared/components/ui/card"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@/shared/components/ui/tooltip"; +import { cn } from "@/shared/utils/ui"; interface AccountCardProps { accountName: string; diff --git a/components/contas/account-dialog.tsx b/src/features/accounts/components/account-dialog.tsx similarity index 93% rename from components/contas/account-dialog.tsx rename to src/features/accounts/components/account-dialog.tsx index f772411..5b3e267 100644 --- a/components/contas/account-dialog.tsx +++ b/src/features/accounts/components/account-dialog.tsx @@ -5,10 +5,13 @@ import { toast } from "sonner"; import { createAccountAction, updateAccountAction, -} from "@/app/(dashboard)/contas/actions"; -import { LogoPickerDialog, LogoPickerTrigger } from "@/components/logo-picker"; -import { useLogoSelection } from "@/components/logo-picker/use-logo-selection"; -import { Button } from "@/components/ui/button"; +} from "@/features/accounts/actions"; +import { + LogoPickerDialog, + LogoPickerTrigger, +} from "@/shared/components/logo-picker"; +import { useLogoSelection } from "@/shared/components/logo-picker/use-logo-selection"; +import { Button } from "@/shared/components/ui/button"; import { Dialog, DialogContent, @@ -17,14 +20,14 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; -import { useControlledState } from "@/lib/hooks/use-controlled-state"; -import { useFormState } from "@/lib/hooks/use-form-state"; -import { deriveNameFromLogo, normalizeLogo } from "@/lib/logo"; +} from "@/shared/components/ui/dialog"; +import { useControlledState } from "@/shared/hooks/use-controlled-state"; +import { useFormState } from "@/shared/hooks/use-form-state"; +import { deriveNameFromLogo, normalizeLogo } from "@/shared/lib/logo"; import { formatInitialBalanceInput, normalizeDecimalInput, -} from "@/lib/utils/currency"; +} from "@/shared/utils/currency"; import { AccountFormFields } from "./account-form-fields"; import type { Account, AccountFormValues } from "./types"; diff --git a/components/contas/account-form-fields.tsx b/src/features/accounts/components/account-form-fields.tsx similarity index 92% rename from components/contas/account-form-fields.tsx rename to src/features/accounts/components/account-form-fields.tsx index be69620..0cbc1b7 100644 --- a/components/contas/account-form-fields.tsx +++ b/src/features/accounts/components/account-form-fields.tsx @@ -1,17 +1,17 @@ "use client"; -import { Checkbox } from "@/components/ui/checkbox"; -import { CurrencyInput } from "@/components/ui/currency-input"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; +import { Checkbox } from "@/shared/components/ui/checkbox"; +import { CurrencyInput } from "@/shared/components/ui/currency-input"; +import { Input } from "@/shared/components/ui/input"; +import { Label } from "@/shared/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { Textarea } from "@/components/ui/textarea"; +} from "@/shared/components/ui/select"; +import { Textarea } from "@/shared/components/ui/textarea"; import { StatusSelectContent } from "./account-select-items"; import type { AccountFormValues } from "./types"; diff --git a/components/contas/account-select-items.tsx b/src/features/accounts/components/account-select-items.tsx similarity index 84% rename from components/contas/account-select-items.tsx rename to src/features/accounts/components/account-select-items.tsx index 114c55f..72262ca 100644 --- a/components/contas/account-select-items.tsx +++ b/src/features/accounts/components/account-select-items.tsx @@ -1,6 +1,6 @@ "use client"; -import StatusDot from "@/components/shared/status-dot"; +import StatusDot from "@/shared/components/status-dot"; export function StatusSelectContent({ label }: { label: string }) { const isActive = label === "Ativa"; diff --git a/components/contas/account-statement-card.tsx b/src/features/accounts/components/account-statement-card.tsx similarity index 92% rename from components/contas/account-statement-card.tsx rename to src/features/accounts/components/account-statement-card.tsx index b405361..2da6565 100644 --- a/components/contas/account-statement-card.tsx +++ b/src/features/accounts/components/account-statement-card.tsx @@ -2,17 +2,22 @@ import { RiInformationLine } from "@remixicon/react"; import Image from "next/image"; import type { ReactNode } from "react"; -import MoneyValues from "@/components/shared/money-values"; -import { Badge } from "@/components/ui/badge"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import MoneyValues from "@/shared/components/money-values"; +import { Badge } from "@/shared/components/ui/badge"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; import { Tooltip, TooltipContent, TooltipTrigger, -} from "@/components/ui/tooltip"; -import { resolveLogoSrc } from "@/lib/logo"; -import { formatCurrency } from "@/lib/utils/currency"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/tooltip"; +import { resolveLogoSrc } from "@/shared/lib/logo"; +import { formatCurrency } from "@/shared/utils/currency"; +import { cn } from "@/shared/utils/ui"; type DetailValue = string | number | ReactNode; diff --git a/components/contas/accounts-page.tsx b/src/features/accounts/components/accounts-page.tsx similarity index 90% rename from components/contas/accounts-page.tsx rename to src/features/accounts/components/accounts-page.tsx index 33bb90b..ce9efce 100644 --- a/components/contas/accounts-page.tsx +++ b/src/features/accounts/components/accounts-page.tsx @@ -5,15 +5,20 @@ import Image from "next/image"; import { useRouter } from "next/navigation"; import { useState } from "react"; import { toast } from "sonner"; -import { deleteAccountAction } from "@/app/(dashboard)/contas/actions"; -import { AccountCard } from "@/components/contas/account-card"; -import { ConfirmActionDialog } from "@/components/shared/confirm-action-dialog"; -import { EmptyState } from "@/components/shared/empty-state"; -import { Button } from "@/components/ui/button"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { resolveLogoSrc } from "@/lib/logo"; -import { getCurrentPeriod } from "@/lib/utils/period"; -import { Card } from "../ui/card"; +import { deleteAccountAction } from "@/features/accounts/actions"; +import { AccountCard } from "@/features/accounts/components/account-card"; +import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog"; +import { EmptyState } from "@/shared/components/empty-state"; +import { Button } from "@/shared/components/ui/button"; +import { Card } from "@/shared/components/ui/card"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/shared/components/ui/tabs"; +import { resolveLogoSrc } from "@/shared/lib/logo"; +import { getCurrentPeriod } from "@/shared/utils/period"; import { AccountDialog } from "./account-dialog"; import { TransferDialog } from "./transfer-dialog"; import type { Account } from "./types"; @@ -155,7 +160,7 @@ export function AccountsPage({ onRemove={() => handleRemoveRequest(account)} onTransfer={() => handleTransferRequest(account)} onViewStatement={() => - router.push(`/contas/${account.id}/extrato`) + router.push(`/accounts/${account.id}/statement`) } /> ); diff --git a/components/contas/transfer-dialog.tsx b/src/features/accounts/components/transfer-dialog.tsx similarity index 89% rename from components/contas/transfer-dialog.tsx rename to src/features/accounts/components/transfer-dialog.tsx index bf2c65f..4bb7502 100644 --- a/components/contas/transfer-dialog.tsx +++ b/src/features/accounts/components/transfer-dialog.tsx @@ -2,13 +2,13 @@ import { useState, useTransition } from "react"; import { toast } from "sonner"; -import { transferBetweenAccountsAction } from "@/app/(dashboard)/contas/actions"; -import type { AccountData } from "@/app/(dashboard)/contas/data"; -import { ContaCartaoSelectContent } from "@/components/lancamentos/select-items"; -import { PeriodPicker } from "@/components/shared/period-picker"; -import { Button } from "@/components/ui/button"; -import { CurrencyInput } from "@/components/ui/currency-input"; -import { DatePicker } from "@/components/ui/date-picker"; +import { transferBetweenAccountsAction } from "@/features/accounts/actions"; +import type { AccountData } from "@/features/accounts/queries"; +import { ContaCartaoSelectContent } from "@/features/transactions/components/select-items"; +import { PeriodPicker } from "@/shared/components/period-picker"; +import { Button } from "@/shared/components/ui/button"; +import { CurrencyInput } from "@/shared/components/ui/currency-input"; +import { DatePicker } from "@/shared/components/ui/date-picker"; import { Dialog, DialogContent, @@ -17,17 +17,17 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; -import { Label } from "@/components/ui/label"; +} from "@/shared/components/ui/dialog"; +import { Label } from "@/shared/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { useControlledState } from "@/lib/hooks/use-controlled-state"; -import { getTodayDateString } from "@/lib/utils/date"; +} from "@/shared/components/ui/select"; +import { useControlledState } from "@/shared/hooks/use-controlled-state"; +import { getTodayDateString } from "@/shared/utils/date"; interface TransferDialogProps { trigger?: React.ReactNode; diff --git a/components/contas/types.ts b/src/features/accounts/components/types.ts similarity index 100% rename from components/contas/types.ts rename to src/features/accounts/components/types.ts diff --git a/app/(dashboard)/contas/data.ts b/src/features/accounts/queries.ts similarity index 95% rename from app/(dashboard)/contas/data.ts rename to src/features/accounts/queries.ts index 3cc927e..5019fb1 100644 --- a/app/(dashboard)/contas/data.ts +++ b/src/features/accounts/queries.ts @@ -1,9 +1,9 @@ import { and, eq, ilike, not, sql } from "drizzle-orm"; import { contas, lancamentos, pagadores } from "@/db/schema"; -import { INITIAL_BALANCE_NOTE } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { loadLogoOptions } from "@/lib/logo/options"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; +import { INITIAL_BALANCE_NOTE } from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; +import { loadLogoOptions } from "@/shared/lib/logo/options"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; export type AccountData = { id: string; diff --git a/app/(dashboard)/contas/[contaId]/extrato/data.ts b/src/features/accounts/statement-queries.ts similarity index 95% rename from app/(dashboard)/contas/[contaId]/extrato/data.ts rename to src/features/accounts/statement-queries.ts index 06f701a..db32cd3 100644 --- a/app/(dashboard)/contas/[contaId]/extrato/data.ts +++ b/src/features/accounts/statement-queries.ts @@ -1,8 +1,8 @@ import { and, desc, eq, lt, type SQL, sql } from "drizzle-orm"; import { contas, lancamentos, pagadores } from "@/db/schema"; -import { INITIAL_BALANCE_NOTE } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; +import { INITIAL_BALANCE_NOTE } from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; export type AccountSummaryData = { openingBalance: number; diff --git a/components/auth/auth-error-alert.tsx b/src/features/auth/components/auth-error-alert.tsx similarity index 84% rename from components/auth/auth-error-alert.tsx rename to src/features/auth/components/auth-error-alert.tsx index c4b7062..032ad77 100644 --- a/components/auth/auth-error-alert.tsx +++ b/src/features/auth/components/auth-error-alert.tsx @@ -1,5 +1,5 @@ import { RiTerminalLine } from "@remixicon/react"; -import { Alert, AlertDescription } from "@/components/ui/alert"; +import { Alert, AlertDescription } from "@/shared/components/ui/alert"; interface AuthErrorAlertProps { error: string; diff --git a/components/auth/auth-header.tsx b/src/features/auth/components/auth-header.tsx similarity index 87% rename from components/auth/auth-header.tsx rename to src/features/auth/components/auth-header.tsx index 2379229..2164f33 100644 --- a/components/auth/auth-header.tsx +++ b/src/features/auth/components/auth-header.tsx @@ -1,4 +1,4 @@ -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; interface AuthHeaderProps { title: string; diff --git a/components/auth/auth-sidebar.tsx b/src/features/auth/components/auth-sidebar.tsx similarity index 100% rename from components/auth/auth-sidebar.tsx rename to src/features/auth/components/auth-sidebar.tsx diff --git a/components/auth/google-auth-button.tsx b/src/features/auth/components/google-auth-button.tsx similarity index 96% rename from components/auth/google-auth-button.tsx rename to src/features/auth/components/google-auth-button.tsx index 04951f4..0e7df14 100644 --- a/components/auth/google-auth-button.tsx +++ b/src/features/auth/components/google-auth-button.tsx @@ -1,5 +1,5 @@ import { RiLoader4Line } from "@remixicon/react"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/shared/components/ui/button"; interface GoogleAuthButtonProps { onClick: () => void; diff --git a/components/auth/login-form.tsx b/src/features/auth/components/login-form.tsx similarity index 94% rename from components/auth/login-form.tsx rename to src/features/auth/components/login-form.tsx index bb0e6a6..a55e430 100644 --- a/components/auth/login-form.tsx +++ b/src/features/auth/components/login-form.tsx @@ -3,19 +3,19 @@ import { RiFingerprintLine, RiLoader4Line } from "@remixicon/react"; import { useRouter } from "next/navigation"; import { type FormEvent, useEffect, useState } from "react"; import { toast } from "sonner"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; +import { Logo } from "@/shared/components/logo"; +import { Button } from "@/shared/components/ui/button"; +import { Card, CardContent } from "@/shared/components/ui/card"; import { Field, FieldDescription, FieldGroup, FieldLabel, FieldSeparator, -} from "@/components/ui/field"; -import { Input } from "@/components/ui/input"; -import { authClient, googleSignInAvailable } from "@/lib/auth/client"; -import { cn } from "@/lib/utils/ui"; -import { Logo } from "@/components/shared/logo"; +} from "@/shared/components/ui/field"; +import { Input } from "@/shared/components/ui/input"; +import { authClient, googleSignInAvailable } from "@/shared/lib/auth/client"; +import { cn } from "@/shared/utils/ui"; import { AuthErrorAlert } from "./auth-error-alert"; import { AuthHeader } from "./auth-header"; import AuthSidebar from "./auth-sidebar"; diff --git a/components/auth/signup-form.tsx b/src/features/auth/components/signup-form.tsx similarity index 94% rename from components/auth/signup-form.tsx rename to src/features/auth/components/signup-form.tsx index 1dd922f..51b817c 100644 --- a/components/auth/signup-form.tsx +++ b/src/features/auth/components/signup-form.tsx @@ -3,19 +3,19 @@ import { RiCheckLine, RiCloseLine, RiLoader4Line } from "@remixicon/react"; import { useRouter } from "next/navigation"; import { type FormEvent, useState } from "react"; import { toast } from "sonner"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; +import { Logo } from "@/shared/components/logo"; +import { Button } from "@/shared/components/ui/button"; +import { Card, CardContent } from "@/shared/components/ui/card"; import { Field, FieldDescription, FieldGroup, FieldLabel, FieldSeparator, -} from "@/components/ui/field"; -import { Input } from "@/components/ui/input"; -import { authClient, googleSignInAvailable } from "@/lib/auth/client"; -import { cn } from "@/lib/utils/ui"; -import { Logo } from "@/components/shared/logo"; +} from "@/shared/components/ui/field"; +import { Input } from "@/shared/components/ui/input"; +import { authClient, googleSignInAvailable } from "@/shared/lib/auth/client"; +import { cn } from "@/shared/utils/ui"; import { AuthErrorAlert } from "./auth-error-alert"; import { AuthHeader } from "./auth-header"; import AuthSidebar from "./auth-sidebar"; diff --git a/app/(dashboard)/orcamentos/actions.ts b/src/features/budgets/actions.ts similarity index 94% rename from app/(dashboard)/orcamentos/actions.ts rename to src/features/budgets/actions.ts index 72c22f8..c66578a 100644 --- a/app/(dashboard)/orcamentos/actions.ts +++ b/src/features/budgets/actions.ts @@ -3,16 +3,19 @@ import { and, eq, ne } from "drizzle-orm"; import { z } from "zod"; import { categorias, orcamentos } from "@/db/schema"; -import { handleActionError, revalidateForEntity } from "@/lib/actions/helpers"; -import { getUser } from "@/lib/auth/server"; -import { db } from "@/lib/db"; -import { periodSchema, uuidSchema } from "@/lib/schemas/common"; -import type { ActionResult } from "@/lib/types/actions"; +import { + handleActionError, + revalidateForEntity, +} from "@/shared/lib/actions/helpers"; +import { getUser } from "@/shared/lib/auth/server"; +import { db } from "@/shared/lib/db"; +import { periodSchema, uuidSchema } from "@/shared/lib/schemas/common"; +import type { ActionResult } from "@/shared/lib/types/actions"; import { formatDecimalForDbRequired, normalizeDecimalInput, -} from "@/lib/utils/currency"; -import { getPreviousPeriod } from "@/lib/utils/period"; +} from "@/shared/utils/currency"; +import { getPreviousPeriod } from "@/shared/utils/period"; const budgetBaseSchema = z.object({ categoriaId: uuidSchema("Categoria"), diff --git a/components/orcamentos/budget-card.tsx b/src/features/budgets/components/budget-card.tsx similarity index 89% rename from components/orcamentos/budget-card.tsx rename to src/features/budgets/components/budget-card.tsx index 07cb614..6007811 100644 --- a/components/orcamentos/budget-card.tsx +++ b/src/features/budgets/components/budget-card.tsx @@ -6,11 +6,11 @@ import { RiPencilLine, } from "@remixicon/react"; import Link from "next/link"; -import { CategoryIconBadge } from "@/components/categorias/category-icon-badge"; -import MoneyValues from "@/components/shared/money-values"; -import { Card, CardContent, CardFooter } from "@/components/ui/card"; -import { Progress } from "@/components/ui/progress"; -import { cn } from "@/lib/utils/ui"; +import { CategoryIconBadge } from "@/features/categories/components/category-icon-badge"; +import MoneyValues from "@/shared/components/money-values"; +import { Card, CardContent, CardFooter } from "@/shared/components/ui/card"; +import { Progress } from "@/shared/components/ui/progress"; +import { cn } from "@/shared/utils/ui"; import type { Budget } from "./types"; interface BudgetCardProps { @@ -105,7 +105,7 @@ export function BudgetCard({ {budget.category && ( detalhes diff --git a/components/orcamentos/budget-dialog.tsx b/src/features/budgets/components/budget-dialog.tsx similarity index 92% rename from components/orcamentos/budget-dialog.tsx rename to src/features/budgets/components/budget-dialog.tsx index 414fa81..e770255 100644 --- a/components/orcamentos/budget-dialog.tsx +++ b/src/features/budgets/components/budget-dialog.tsx @@ -5,10 +5,10 @@ import { toast } from "sonner"; import { createBudgetAction, updateBudgetAction, -} from "@/app/(dashboard)/orcamentos/actions"; -import { CategoryIcon } from "@/components/categorias/category-icon"; -import { PeriodPicker } from "@/components/shared/period-picker"; -import { Button } from "@/components/ui/button"; +} from "@/features/budgets/actions"; +import { CategoryIcon } from "@/features/categories/components/category-icon"; +import { PeriodPicker } from "@/shared/components/period-picker"; +import { Button } from "@/shared/components/ui/button"; import { Dialog, DialogContent, @@ -17,19 +17,19 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; -import { Label } from "@/components/ui/label"; +} from "@/shared/components/ui/dialog"; +import { Label } from "@/shared/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { Slider } from "@/components/ui/slider"; -import { useControlledState } from "@/lib/hooks/use-controlled-state"; -import { useFormState } from "@/lib/hooks/use-form-state"; -import { formatCurrency } from "@/lib/utils/currency"; +} from "@/shared/components/ui/select"; +import { Slider } from "@/shared/components/ui/slider"; +import { useControlledState } from "@/shared/hooks/use-controlled-state"; +import { useFormState } from "@/shared/hooks/use-form-state"; +import { formatCurrency } from "@/shared/utils/currency"; import type { Budget, BudgetCategory, BudgetFormValues } from "./types"; diff --git a/components/orcamentos/budgets-page.tsx b/src/features/budgets/components/budgets-page.tsx similarity index 94% rename from components/orcamentos/budgets-page.tsx rename to src/features/budgets/components/budgets-page.tsx index 4c9b674..f9ac9eb 100644 --- a/components/orcamentos/budgets-page.tsx +++ b/src/features/budgets/components/budgets-page.tsx @@ -6,11 +6,11 @@ import { toast } from "sonner"; import { deleteBudgetAction, duplicatePreviousMonthBudgetsAction, -} from "@/app/(dashboard)/orcamentos/actions"; -import { ConfirmActionDialog } from "@/components/shared/confirm-action-dialog"; -import { EmptyState } from "@/components/shared/empty-state"; -import { Button } from "@/components/ui/button"; -import { Card } from "../ui/card"; +} from "@/features/budgets/actions"; +import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog"; +import { EmptyState } from "@/shared/components/empty-state"; +import { Button } from "@/shared/components/ui/button"; +import { Card } from "@/shared/components/ui/card"; import { BudgetCard } from "./budget-card"; import { BudgetDialog } from "./budget-dialog"; import type { Budget, BudgetCategory } from "./types"; diff --git a/components/orcamentos/types.ts b/src/features/budgets/components/types.ts similarity index 100% rename from components/orcamentos/types.ts rename to src/features/budgets/components/types.ts diff --git a/app/(dashboard)/orcamentos/data.ts b/src/features/budgets/queries.ts similarity index 94% rename from app/(dashboard)/orcamentos/data.ts rename to src/features/budgets/queries.ts index c4bf984..0e852c2 100644 --- a/app/(dashboard)/orcamentos/data.ts +++ b/src/features/budgets/queries.ts @@ -6,9 +6,9 @@ import { orcamentos, pagadores, } from "@/db/schema"; -import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; +import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; const toNumber = (value: string | number | null | undefined) => { if (typeof value === "number") return value; diff --git a/components/calendario/calendar-grid.tsx b/src/features/calendar/components/calendar-grid.tsx similarity index 80% rename from components/calendario/calendar-grid.tsx rename to src/features/calendar/components/calendar-grid.tsx index 93deb4c..33b73c2 100644 --- a/components/calendario/calendar-grid.tsx +++ b/src/features/calendar/components/calendar-grid.tsx @@ -1,10 +1,10 @@ "use client"; -import { DayCell } from "@/components/calendario/day-cell"; +import { DayCell } from "@/features/calendar/components/day-cell"; -import type { CalendarDay } from "@/lib/types/calendario"; -import { WEEK_DAYS_SHORT } from "@/lib/utils/calendario"; -import { cn } from "@/lib/utils/ui"; +import type { CalendarDay } from "@/shared/lib/types/calendar"; +import { WEEK_DAYS_SHORT } from "@/shared/utils/calendar"; +import { cn } from "@/shared/utils/ui"; type CalendarGridProps = { days: CalendarDay[]; diff --git a/components/calendario/calendar-legend.tsx b/src/features/calendar/components/calendar-legend.tsx similarity index 74% rename from components/calendario/calendar-legend.tsx rename to src/features/calendar/components/calendar-legend.tsx index fe0298a..12a1e38 100644 --- a/components/calendario/calendar-legend.tsx +++ b/src/features/calendar/components/calendar-legend.tsx @@ -1,9 +1,9 @@ "use client"; -import { EVENT_TYPE_STYLES } from "@/components/calendario/day-cell"; -import type { CalendarEvent } from "@/lib/types/calendario"; -import StatusDot from "../shared/status-dot"; -import { Card } from "../ui/card"; +import { EVENT_TYPE_STYLES } from "@/features/calendar/components/day-cell"; +import StatusDot from "@/shared/components/status-dot"; +import { Card } from "@/shared/components/ui/card"; +import type { CalendarEvent } from "@/shared/lib/types/calendar"; const LEGEND_ITEMS: Array<{ type?: CalendarEvent["type"]; diff --git a/components/calendario/day-cell.tsx b/src/features/calendar/components/day-cell.tsx similarity index 96% rename from components/calendario/day-cell.tsx rename to src/features/calendar/components/day-cell.tsx index 1ec945e..cd4b7b7 100644 --- a/components/calendario/day-cell.tsx +++ b/src/features/calendar/components/day-cell.tsx @@ -2,9 +2,9 @@ import { RiAddLine } from "@remixicon/react"; import type { KeyboardEvent, MouseEvent } from "react"; -import type { CalendarDay, CalendarEvent } from "@/lib/types/calendario"; -import { currencyFormatter } from "@/lib/lancamentos/formatting-helpers"; -import { cn } from "@/lib/utils/ui"; +import type { CalendarDay, CalendarEvent } from "@/shared/lib/types/calendar"; +import { currencyFormatter } from "@/shared/utils/currency"; +import { cn } from "@/shared/utils/ui"; type DayCellProps = { day: CalendarDay; diff --git a/components/calendario/event-modal.tsx b/src/features/calendar/components/event-modal.tsx similarity index 89% rename from components/calendario/event-modal.tsx rename to src/features/calendar/components/event-modal.tsx index a85e5bc..d7885ab 100644 --- a/components/calendario/event-modal.tsx +++ b/src/features/calendar/components/event-modal.tsx @@ -1,9 +1,11 @@ "use client"; import type { ReactNode } from "react"; -import { EVENT_TYPE_STYLES } from "@/components/calendario/day-cell"; -import MoneyValues from "@/components/shared/money-values"; -import { Button } from "@/components/ui/button"; +import { EVENT_TYPE_STYLES } from "@/features/calendar/components/day-cell"; +import MoneyValues from "@/shared/components/money-values"; +import { Badge } from "@/shared/components/ui/badge"; +import { Button } from "@/shared/components/ui/button"; +import { Card } from "@/shared/components/ui/card"; import { Dialog, DialogContent, @@ -11,13 +13,11 @@ import { DialogFooter, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import type { CalendarDay, CalendarEvent } from "@/lib/types/calendario"; -import { friendlyDate, parseLocalDateString } from "@/lib/utils/date"; -import { formatFinancialDateLabel } from "@/lib/utils/financial-dates"; -import { cn } from "@/lib/utils/ui"; -import { Badge } from "../ui/badge"; -import { Card } from "../ui/card"; +} from "@/shared/components/ui/dialog"; +import type { CalendarDay, CalendarEvent } from "@/shared/lib/types/calendar"; +import { friendlyDate, parseLocalDateString } from "@/shared/utils/date"; +import { formatFinancialDateLabel } from "@/shared/utils/financial-dates"; +import { cn } from "@/shared/utils/ui"; type EventModalProps = { open: boolean; diff --git a/components/calendario/monthly-calendar.tsx b/src/features/calendar/components/monthly-calendar.tsx similarity index 83% rename from components/calendario/monthly-calendar.tsx rename to src/features/calendar/components/monthly-calendar.tsx index 84da79b..819ac1f 100644 --- a/components/calendario/monthly-calendar.tsx +++ b/src/features/calendar/components/monthly-calendar.tsx @@ -1,18 +1,18 @@ "use client"; import { useMemo, useState } from "react"; -import { CalendarGrid } from "@/components/calendario/calendar-grid"; -import { CalendarLegend } from "@/components/calendario/calendar-legend"; -import { EventModal } from "@/components/calendario/event-modal"; -import { LancamentoDialog } from "@/components/lancamentos/dialogs/lancamento-dialog/lancamento-dialog"; +import { CalendarGrid } from "@/features/calendar/components/calendar-grid"; +import { CalendarLegend } from "@/features/calendar/components/calendar-legend"; +import { EventModal } from "@/features/calendar/components/event-modal"; +import { LancamentoDialog } from "@/features/transactions/components/dialogs/transaction-dialog/transaction-dialog"; import type { CalendarDay, CalendarEvent, CalendarFormOptions, CalendarPeriod, -} from "@/lib/types/calendario"; -import { buildCalendarDays } from "@/lib/utils/calendario"; -import { parsePeriod } from "@/lib/utils/period"; +} from "@/shared/lib/types/calendar"; +import { buildCalendarDays } from "@/shared/utils/calendar"; +import { parsePeriod } from "@/shared/utils/period"; type MonthlyCalendarProps = { period: CalendarPeriod; diff --git a/app/(dashboard)/calendario/data.ts b/src/features/calendar/queries.ts similarity index 91% rename from app/(dashboard)/calendario/data.ts rename to src/features/calendar/queries.ts index 4196efa..e60f8fa 100644 --- a/app/(dashboard)/calendario/data.ts +++ b/src/features/calendar/queries.ts @@ -1,17 +1,19 @@ import { and, eq, gte, lte, ne, or } from "drizzle-orm"; -import { getRecentEstablishmentsAction } from "@/app/(dashboard)/lancamentos/actions"; import { cartoes, lancamentos } from "@/db/schema"; -import { db } from "@/lib/db"; import { buildOptionSets, buildSluggedFilters, - fetchLancamentoFilterSources, mapLancamentosData, -} from "@/lib/lancamentos/page-helpers"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; -import type { CalendarData, CalendarEvent } from "@/lib/types/calendario"; -import { formatDateKey } from "@/lib/utils/calendario"; -import { parsePeriod } from "@/lib/utils/period"; +} from "@/features/transactions/page-helpers"; +import { + fetchLancamentoFilterSources, + fetchRecentEstablishments, +} from "@/features/transactions/queries"; +import { db } from "@/shared/lib/db"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import type { CalendarData, CalendarEvent } from "@/shared/lib/types/calendar"; +import { formatDateKey } from "@/shared/utils/calendar"; +import { parsePeriod } from "@/shared/utils/period"; const PAYMENT_METHOD_BOLETO = "Boleto"; const TRANSACTION_TYPE_TRANSFERENCIA = "Transferência"; @@ -187,7 +189,7 @@ export const fetchCalendarData = async ({ pagadorRows: filterSources.pagadorRows, }); - const estabelecimentos = await getRecentEstablishmentsAction(); + const estabelecimentos = await fetchRecentEstablishments(userId); return { events, diff --git a/app/(dashboard)/cartoes/actions.ts b/src/features/cards/actions.ts similarity index 93% rename from app/(dashboard)/cartoes/actions.ts rename to src/features/cards/actions.ts index 1d1fe7b..0513d8d 100644 --- a/app/(dashboard)/cartoes/actions.ts +++ b/src/features/cards/actions.ts @@ -7,17 +7,17 @@ import { type ActionResult, handleActionError, revalidateForEntity, -} from "@/lib/actions/helpers"; -import { getUser } from "@/lib/auth/server"; -import { db } from "@/lib/db"; +} from "@/shared/lib/actions/helpers"; +import { getUser } from "@/shared/lib/auth/server"; +import { db } from "@/shared/lib/db"; import { dayOfMonthSchema, noteSchema, optionalDecimalSchema, uuidSchema, -} from "@/lib/schemas/common"; -import { formatDecimalForDb } from "@/lib/utils/currency"; -import { normalizeFilePath } from "@/lib/utils/string"; +} from "@/shared/lib/schemas/common"; +import { formatDecimalForDb } from "@/shared/utils/currency"; +import { normalizeFilePath } from "@/shared/utils/string"; const cardBaseSchema = z.object({ name: z diff --git a/components/cartoes/card-dialog.tsx b/src/features/cards/components/card-dialog.tsx similarity index 90% rename from components/cartoes/card-dialog.tsx rename to src/features/cards/components/card-dialog.tsx index 90d9549..9e5eb29 100644 --- a/components/cartoes/card-dialog.tsx +++ b/src/features/cards/components/card-dialog.tsx @@ -2,13 +2,13 @@ import { useEffect, useMemo, useState, useTransition } from "react"; import { toast } from "sonner"; +import { createCardAction, updateCardAction } from "@/features/cards/actions"; import { - createCardAction, - updateCardAction, -} from "@/app/(dashboard)/cartoes/actions"; -import { LogoPickerDialog, LogoPickerTrigger } from "@/components/logo-picker"; -import { useLogoSelection } from "@/components/logo-picker/use-logo-selection"; -import { Button } from "@/components/ui/button"; + LogoPickerDialog, + LogoPickerTrigger, +} from "@/shared/components/logo-picker"; +import { useLogoSelection } from "@/shared/components/logo-picker/use-logo-selection"; +import { Button } from "@/shared/components/ui/button"; import { Dialog, DialogContent, @@ -17,15 +17,18 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; +} from "@/shared/components/ui/dialog"; +import { useControlledState } from "@/shared/hooks/use-controlled-state"; +import { useFormState } from "@/shared/hooks/use-form-state"; import { DEFAULT_CARD_BRANDS, DEFAULT_CARD_STATUS, -} from "@/lib/cartoes/constants"; -import { useControlledState } from "@/lib/hooks/use-controlled-state"; -import { useFormState } from "@/lib/hooks/use-form-state"; -import { deriveNameFromLogo, normalizeLogo } from "@/lib/logo"; -import { formatLimitInput, normalizeDecimalInput } from "@/lib/utils/currency"; +} from "@/shared/lib/cards/constants"; +import { deriveNameFromLogo, normalizeLogo } from "@/shared/lib/logo"; +import { + formatLimitInput, + normalizeDecimalInput, +} from "@/shared/utils/currency"; import { CardFormFields } from "./card-form-fields"; import type { Card, CardFormValues } from "./types"; diff --git a/components/cartoes/card-form-fields.tsx b/src/features/cards/components/card-form-fields.tsx similarity index 94% rename from components/cartoes/card-form-fields.tsx rename to src/features/cards/components/card-form-fields.tsx index 87d1482..e600283 100644 --- a/components/cartoes/card-form-fields.tsx +++ b/src/features/cards/components/card-form-fields.tsx @@ -1,26 +1,26 @@ "use client"; -import { CurrencyInput } from "@/components/ui/currency-input"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; +import { CurrencyInput } from "@/shared/components/ui/currency-input"; +import { Input } from "@/shared/components/ui/input"; +import { Label } from "@/shared/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { Textarea } from "@/components/ui/textarea"; +} from "@/shared/components/ui/select"; +import { Textarea } from "@/shared/components/ui/textarea"; +import { + DAYS_IN_MONTH, + DEFAULT_CARD_BRANDS, + DEFAULT_CARD_STATUS, +} from "@/shared/lib/cards/constants"; import { AccountSelectContent, BrandSelectContent, StatusSelectContent, } from "./card-select-items"; -import { - DAYS_IN_MONTH, - DEFAULT_CARD_BRANDS, - DEFAULT_CARD_STATUS, -} from "@/lib/cartoes/constants"; import type { CardFormValues } from "./types"; interface AccountOption { diff --git a/components/cartoes/card-item.tsx b/src/features/cards/components/card-item.tsx similarity index 94% rename from components/cartoes/card-item.tsx rename to src/features/cards/components/card-item.tsx index fcd9e4e..47498a6 100644 --- a/components/cartoes/card-item.tsx +++ b/src/features/cards/components/card-item.tsx @@ -7,22 +7,22 @@ import { RiPencilLine, } from "@remixicon/react"; import Image from "next/image"; -import MoneyValues from "@/components/shared/money-values"; +import MoneyValues from "@/shared/components/money-values"; import { Card, CardContent, CardFooter, CardHeader, -} from "@/components/ui/card"; -import { Progress } from "@/components/ui/progress"; +} from "@/shared/components/ui/card"; +import { Progress } from "@/shared/components/ui/progress"; import { Tooltip, TooltipContent, TooltipTrigger, -} from "@/components/ui/tooltip"; -import { resolveCardBrandAsset } from "@/lib/cartoes/brand-assets"; -import { resolveLogoSrc } from "@/lib/logo"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/tooltip"; +import { resolveCardBrandAsset } from "@/shared/lib/cards/brand-assets"; +import { resolveLogoSrc } from "@/shared/lib/logo"; +import { cn } from "@/shared/utils/ui"; interface CardItemProps { name: string; diff --git a/components/cartoes/card-select-items.tsx b/src/features/cards/components/card-select-items.tsx similarity index 88% rename from components/cartoes/card-select-items.tsx rename to src/features/cards/components/card-select-items.tsx index d925c04..3cb7285 100644 --- a/components/cartoes/card-select-items.tsx +++ b/src/features/cards/components/card-select-items.tsx @@ -2,9 +2,9 @@ import { RiBankLine } from "@remixicon/react"; import Image from "next/image"; -import StatusDot from "@/components/shared/status-dot"; -import { resolveCardBrandLogoSrc } from "@/lib/cartoes/brand-assets"; -import { resolveLogoSrc } from "@/lib/logo"; +import StatusDot from "@/shared/components/status-dot"; +import { resolveCardBrandLogoSrc } from "@/shared/lib/cards/brand-assets"; +import { resolveLogoSrc } from "@/shared/lib/logo"; type SelectItemContentProps = { label: string; diff --git a/components/cartoes/cards-page.tsx b/src/features/cards/components/cards-page.tsx similarity index 91% rename from components/cartoes/cards-page.tsx rename to src/features/cards/components/cards-page.tsx index 7bd7dc1..3cb1ddf 100644 --- a/components/cartoes/cards-page.tsx +++ b/src/features/cards/components/cards-page.tsx @@ -4,12 +4,17 @@ import { RiAddCircleLine, RiBankCard2Line } from "@remixicon/react"; import { useRouter } from "next/navigation"; import { useMemo, useState } from "react"; import { toast } from "sonner"; -import { deleteCardAction } from "@/app/(dashboard)/cartoes/actions"; -import { ConfirmActionDialog } from "@/components/shared/confirm-action-dialog"; -import { EmptyState } from "@/components/shared/empty-state"; -import { Button } from "@/components/ui/button"; -import { Card as UiCard } from "@/components/ui/card"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { deleteCardAction } from "@/features/cards/actions"; +import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog"; +import { EmptyState } from "@/shared/components/empty-state"; +import { Button } from "@/shared/components/ui/button"; +import { Card as UiCard } from "@/shared/components/ui/card"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/shared/components/ui/tabs"; import { CardDialog } from "./card-dialog"; import { CardItem } from "./card-item"; import type { Card as CreditCard } from "./types"; @@ -73,7 +78,7 @@ export function CardsPage({ }; const handleInvoice = (card: CreditCard) => { - router.push(`/cartoes/${card.id}/fatura`); + router.push(`/cards/${card.id}/invoice`); }; const handleRemoveOpenChange = (open: boolean) => { diff --git a/components/cartoes/types.ts b/src/features/cards/components/types.ts similarity index 100% rename from components/cartoes/types.ts rename to src/features/cards/components/types.ts diff --git a/app/(dashboard)/cartoes/data.ts b/src/features/cards/queries.ts similarity index 98% rename from app/(dashboard)/cartoes/data.ts rename to src/features/cards/queries.ts index 3ede582..a1e8c23 100644 --- a/app/(dashboard)/cartoes/data.ts +++ b/src/features/cards/queries.ts @@ -1,7 +1,7 @@ import { and, eq, ilike, isNull, ne, not, or, sql } from "drizzle-orm"; import { cartoes, contas, lancamentos } from "@/db/schema"; -import { db } from "@/lib/db"; -import { loadLogoOptions } from "@/lib/logo/options"; +import { db } from "@/shared/lib/db"; +import { loadLogoOptions } from "@/shared/lib/logo/options"; export type CardData = { id: string; diff --git a/app/(dashboard)/categorias/actions.ts b/src/features/categories/actions.ts similarity index 92% rename from app/(dashboard)/categorias/actions.ts rename to src/features/categories/actions.ts index 1087dde..0695405 100644 --- a/app/(dashboard)/categorias/actions.ts +++ b/src/features/categories/actions.ts @@ -7,12 +7,12 @@ import { type ActionResult, handleActionError, revalidateForEntity, -} from "@/lib/actions/helpers"; -import { getUser } from "@/lib/auth/server"; -import { CATEGORY_TYPES } from "@/lib/categorias/constants"; -import { db } from "@/lib/db"; -import { uuidSchema } from "@/lib/schemas/common"; -import { normalizeIconInput } from "@/lib/utils/string"; +} from "@/shared/lib/actions/helpers"; +import { getUser } from "@/shared/lib/auth/server"; +import { CATEGORY_TYPES } from "@/shared/lib/categories/constants"; +import { db } from "@/shared/lib/db"; +import { uuidSchema } from "@/shared/lib/schemas/common"; +import { normalizeIconInput } from "@/shared/utils/string"; const categoryBaseSchema = z.object({ name: z diff --git a/components/categorias/categories-page.tsx b/src/features/categories/components/categories-page.tsx similarity index 93% rename from components/categorias/categories-page.tsx rename to src/features/categories/components/categories-page.tsx index 9d4452a..8285524 100644 --- a/components/categorias/categories-page.tsx +++ b/src/features/categories/components/categories-page.tsx @@ -9,10 +9,10 @@ import { import Link from "next/link"; import { useMemo, useState } from "react"; import { toast } from "sonner"; -import { deleteCategoryAction } from "@/app/(dashboard)/categorias/actions"; -import { ConfirmActionDialog } from "@/components/shared/confirm-action-dialog"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; +import { deleteCategoryAction } from "@/features/categories/actions"; +import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog"; +import { Button } from "@/shared/components/ui/button"; +import { Card, CardContent } from "@/shared/components/ui/card"; import { Table, TableBody, @@ -20,12 +20,17 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +} from "@/shared/components/ui/table"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/shared/components/ui/tabs"; import { CATEGORY_TYPE_LABEL, CATEGORY_TYPES, -} from "@/lib/categorias/constants"; +} from "@/shared/lib/categories/constants"; import { CategoryDialog } from "./category-dialog"; import { CategoryIconBadge } from "./category-icon-badge"; import type { Category, CategoryType } from "./types"; @@ -178,7 +183,7 @@ export function CategoriesPage({ categories }: CategoriesPageProps) { {category.name} diff --git a/components/categorias/category-detail-header.tsx b/src/features/categories/components/category-detail-header.tsx similarity index 90% rename from components/categorias/category-detail-header.tsx rename to src/features/categories/components/category-detail-header.tsx index 6c9f37f..c8fcfd2 100644 --- a/components/categorias/category-detail-header.tsx +++ b/src/features/categories/components/category-detail-header.tsx @@ -1,10 +1,10 @@ import { RiArrowDownSFill, RiArrowUpSFill } from "@remixicon/react"; -import { TypeBadge } from "@/components/shared/type-badge"; -import type { CategoryType } from "@/lib/categorias/constants"; -import { currencyFormatter } from "@/lib/lancamentos/formatting-helpers"; -import { formatPercentage } from "@/lib/utils/percentage"; -import { cn } from "@/lib/utils/ui"; -import { Card } from "../ui/card"; +import { TypeBadge } from "@/shared/components/type-badge"; +import { Card } from "@/shared/components/ui/card"; +import type { CategoryType } from "@/shared/lib/categories/constants"; +import { currencyFormatter } from "@/shared/utils/currency"; +import { formatPercentage } from "@/shared/utils/percentage"; +import { cn } from "@/shared/utils/ui"; import { CategoryIconBadge } from "./category-icon-badge"; type CategorySummary = { diff --git a/components/categorias/category-dialog.tsx b/src/features/categories/components/category-dialog.tsx similarity index 90% rename from components/categorias/category-dialog.tsx rename to src/features/categories/components/category-dialog.tsx index 90e69f0..cf6dd36 100644 --- a/components/categorias/category-dialog.tsx +++ b/src/features/categories/components/category-dialog.tsx @@ -5,8 +5,8 @@ import { toast } from "sonner"; import { createCategoryAction, updateCategoryAction, -} from "@/app/(dashboard)/categorias/actions"; -import { Button } from "@/components/ui/button"; +} from "@/features/categories/actions"; +import { Button } from "@/shared/components/ui/button"; import { Dialog, DialogContent, @@ -15,11 +15,11 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; -import { CATEGORY_TYPES } from "@/lib/categorias/constants"; -import { getDefaultIconForType } from "@/lib/categorias/icons"; -import { useControlledState } from "@/lib/hooks/use-controlled-state"; -import { useFormState } from "@/lib/hooks/use-form-state"; +} from "@/shared/components/ui/dialog"; +import { useControlledState } from "@/shared/hooks/use-controlled-state"; +import { useFormState } from "@/shared/hooks/use-form-state"; +import { CATEGORY_TYPES } from "@/shared/lib/categories/constants"; +import { getDefaultIconForType } from "@/shared/lib/categories/icons"; import { CategoryFormFields } from "./category-form-fields"; import type { Category, CategoryFormValues } from "./types"; diff --git a/components/categorias/category-form-fields.tsx b/src/features/categories/components/category-form-fields.tsx similarity index 89% rename from components/categorias/category-form-fields.tsx rename to src/features/categories/components/category-form-fields.tsx index 2d1e417..04a02f9 100644 --- a/components/categorias/category-form-fields.tsx +++ b/src/features/categories/components/category-form-fields.tsx @@ -2,27 +2,27 @@ import { RiMoreLine } from "@remixicon/react"; import { useState } from "react"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; +import { Button } from "@/shared/components/ui/button"; +import { Input } from "@/shared/components/ui/input"; +import { Label } from "@/shared/components/ui/label"; import { Popover, PopoverContent, PopoverTrigger, -} from "@/components/ui/popover"; +} from "@/shared/components/ui/popover"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; +} from "@/shared/components/ui/select"; import { CATEGORY_TYPE_LABEL, CATEGORY_TYPES, -} from "@/lib/categorias/constants"; -import { getCategoryIconOptions } from "@/lib/categorias/icons"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/lib/categories/constants"; +import { getCategoryIconOptions } from "@/shared/lib/categories/icons"; +import { cn } from "@/shared/utils/ui"; import { CategoryIcon } from "./category-icon"; import { TypeSelectContent } from "./category-select-items"; diff --git a/components/categorias/category-icon-badge.tsx b/src/features/categories/components/category-icon-badge.tsx similarity index 92% rename from components/categorias/category-icon-badge.tsx rename to src/features/categories/components/category-icon-badge.tsx index f99d575..4925141 100644 --- a/components/categorias/category-icon-badge.tsx +++ b/src/features/categories/components/category-icon-badge.tsx @@ -4,9 +4,9 @@ import { buildCategoryInitials, getCategoryBgColor, getCategoryColor, -} from "@/lib/utils/category-colors"; -import { getIconComponent } from "@/lib/utils/icons"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/utils/category-colors"; +import { getIconComponent } from "@/shared/utils/icons"; +import { cn } from "@/shared/utils/ui"; const sizeVariants = { sm: { diff --git a/components/categorias/category-icon.tsx b/src/features/categories/components/category-icon.tsx similarity index 94% rename from components/categorias/category-icon.tsx rename to src/features/categories/components/category-icon.tsx index 323d60b..8287b11 100644 --- a/components/categorias/category-icon.tsx +++ b/src/features/categories/components/category-icon.tsx @@ -2,7 +2,7 @@ import type { RemixiconComponentType } from "@remixicon/react"; import * as RemixIcons from "@remixicon/react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; const ICONS = RemixIcons as Record; const FALLBACK_ICON = ICONS.RiPriceTag3Line; diff --git a/components/categorias/category-select-items.tsx b/src/features/categories/components/category-select-items.tsx similarity index 83% rename from components/categorias/category-select-items.tsx rename to src/features/categories/components/category-select-items.tsx index 5c2d508..bac4bf6 100644 --- a/components/categorias/category-select-items.tsx +++ b/src/features/categories/components/category-select-items.tsx @@ -1,6 +1,6 @@ "use client"; -import StatusDot from "@/components/shared/status-dot"; +import StatusDot from "@/shared/components/status-dot"; export function TypeSelectContent({ label }: { label: string }) { const isReceita = label === "Receita"; diff --git a/components/categorias/types.ts b/src/features/categories/components/types.ts similarity index 56% rename from components/categorias/types.ts rename to src/features/categories/components/types.ts index 671dd4d..11db653 100644 --- a/components/categorias/types.ts +++ b/src/features/categories/components/types.ts @@ -1,10 +1,10 @@ -import type { CategoryType } from "@/lib/categorias/constants"; +import type { CategoryType } from "@/shared/lib/categories/constants"; -export type { CategoryType } from "@/lib/categorias/constants"; +export type { CategoryType } from "@/shared/lib/categories/constants"; export { CATEGORY_TYPE_LABEL, CATEGORY_TYPES, -} from "@/lib/categorias/constants"; +} from "@/shared/lib/categories/constants"; export type Category = { id: string; diff --git a/app/(dashboard)/categorias/data.ts b/src/features/categories/queries.ts similarity index 83% rename from app/(dashboard)/categorias/data.ts rename to src/features/categories/queries.ts index beb0e8d..1cc7128 100644 --- a/app/(dashboard)/categorias/data.ts +++ b/src/features/categories/queries.ts @@ -1,7 +1,7 @@ import { eq } from "drizzle-orm"; -import type { CategoryType } from "@/components/categorias/types"; import { type Categoria, categorias } from "@/db/schema"; -import { db } from "@/lib/db"; +import type { CategoryType } from "@/features/categories/components/types"; +import { db } from "@/shared/lib/db"; export type CategoryData = { id: string; diff --git a/lib/dashboard/accounts.ts b/src/features/dashboard/accounts-queries.ts similarity index 91% rename from lib/dashboard/accounts.ts rename to src/features/dashboard/accounts-queries.ts index c71515b..dbb5f94 100644 --- a/lib/dashboard/accounts.ts +++ b/src/features/dashboard/accounts-queries.ts @@ -1,9 +1,9 @@ import { and, eq, sql } from "drizzle-orm"; import { contas, lancamentos, pagadores } from "@/db/schema"; -import { INITIAL_BALANCE_NOTE } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +import { INITIAL_BALANCE_NOTE } from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; type RawDashboardAccount = { id: string; diff --git a/lib/dashboard/bills-helpers.ts b/src/features/dashboard/bills-helpers.ts similarity index 79% rename from lib/dashboard/bills-helpers.ts rename to src/features/dashboard/bills-helpers.ts index 87281cd..11bfd12 100644 --- a/lib/dashboard/bills-helpers.ts +++ b/src/features/dashboard/bills-helpers.ts @@ -1,10 +1,10 @@ -import type { DashboardBill } from "@/lib/dashboard/bills"; -import type { PaymentDialogState } from "@/lib/dashboard/use-payment-dialog-controller"; -import { getBusinessDateString, isDateOnlyPast } from "@/lib/utils/date"; +import type { DashboardBill } from "@/features/dashboard/bills-queries"; +import type { PaymentDialogState } from "@/features/dashboard/use-payment-dialog-controller"; +import { getBusinessDateString, isDateOnlyPast } from "@/shared/utils/date"; import { buildFinancialStatusLabel, formatFinancialDateLabel, -} from "@/lib/utils/financial-dates"; +} from "@/shared/utils/financial-dates"; export type BillDialogState = PaymentDialogState; export type BillStatusDateItem = Pick< diff --git a/lib/dashboard/bills.ts b/src/features/dashboard/bills-queries.ts similarity index 89% rename from lib/dashboard/bills.ts rename to src/features/dashboard/bills-queries.ts index c6e1d42..39fef73 100644 --- a/lib/dashboard/bills.ts +++ b/src/features/dashboard/bills-queries.ts @@ -2,10 +2,10 @@ import { and, asc, eq } from "drizzle-orm"; import { lancamentos } from "@/db/schema"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { toDateOnlyString } from "@/lib/utils/date"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { toDateOnlyString } from "@/shared/utils/date"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; const PAYMENT_METHOD_BOLETO = "Boleto"; diff --git a/lib/dashboard/categories/category-breakdown.ts b/src/features/dashboard/categories/category-breakdown.ts similarity index 95% rename from lib/dashboard/categories/category-breakdown.ts rename to src/features/dashboard/categories/category-breakdown.ts index 92c221d..8751d33 100644 --- a/lib/dashboard/categories/category-breakdown.ts +++ b/src/features/dashboard/categories/category-breakdown.ts @@ -1,5 +1,5 @@ -import { calculatePercentageChange } from "@/lib/utils/math"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +import { calculatePercentageChange } from "@/shared/utils/math"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; export type DashboardCategoryBreakdownItem = { categoryId: string; diff --git a/lib/dashboard/categories/category-details.ts b/src/features/dashboard/categories/category-details-queries.ts similarity index 78% rename from lib/dashboard/categories/category-details.ts rename to src/features/dashboard/categories/category-details-queries.ts index f45139b..78fae91 100644 --- a/lib/dashboard/categories/category-details.ts +++ b/src/features/dashboard/categories/category-details-queries.ts @@ -1,15 +1,16 @@ import { and, desc, eq, isNull, ne, or, sql } from "drizzle-orm"; import { categorias, contas, lancamentos, pagadores } from "@/db/schema"; -import type { CategoryType } from "@/lib/categorias/constants"; +import { mapLancamentosData } from "@/features/transactions/page-helpers"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX, INITIAL_BALANCE_NOTE, -} from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { mapLancamentosData } from "@/lib/lancamentos/page-helpers"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; -import { getPreviousPeriod } from "@/lib/utils/period"; +} from "@/shared/lib/accounts/constants"; +import type { CategoryType } from "@/shared/lib/categories/constants"; +import { db } from "@/shared/lib/db"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { calculatePercentageChange } from "@/shared/utils/math"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; +import { getPreviousPeriod } from "@/shared/utils/period"; type MappedLancamentos = ReturnType; @@ -28,23 +29,6 @@ export type CategoryDetailData = { transactions: MappedLancamentos; }; -const calculatePercentageChange = ( - current: number, - previous: number, -): number | null => { - const EPSILON = 0.01; // Considera valores menores que 1 centavo como zero - - if (Math.abs(previous) < EPSILON) { - if (Math.abs(current) < EPSILON) return null; - return current > 0 ? 100 : -100; - } - - const change = ((current - previous) / Math.abs(previous)) * 100; - - // Protege contra valores absurdos (retorna null se > 1 milhão %) - return Number.isFinite(change) && Math.abs(change) < 1000000 ? change : null; -}; - export async function fetchCategoryDetails( userId: string, categoryId: string, diff --git a/lib/dashboard/categories/category-history.ts b/src/features/dashboard/categories/category-history-queries.ts similarity index 93% rename from lib/dashboard/categories/category-history.ts rename to src/features/dashboard/categories/category-history-queries.ts index 997e110..999d159 100644 --- a/lib/dashboard/categories/category-history.ts +++ b/src/features/dashboard/categories/category-history-queries.ts @@ -1,15 +1,15 @@ import { and, eq, inArray, isNull, or, sql } from "drizzle-orm"; import { categorias, lancamentos, pagadores } from "@/db/schema"; -import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; -import { CATEGORY_COLORS } from "@/lib/utils/category-colors"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { CATEGORY_COLORS } from "@/shared/utils/category-colors"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; import { addMonthsToPeriod, buildPeriodWindow, formatPeriodMonthShort, -} from "@/lib/utils/period"; +} from "@/shared/utils/period"; export type CategoryOption = { id: string; diff --git a/lib/dashboard/categories/expenses-by-category.ts b/src/features/dashboard/categories/expenses-by-category-queries.ts similarity index 87% rename from lib/dashboard/categories/expenses-by-category.ts rename to src/features/dashboard/categories/expenses-by-category-queries.ts index 72fd704..925a4a9 100644 --- a/lib/dashboard/categories/expenses-by-category.ts +++ b/src/features/dashboard/categories/expenses-by-category-queries.ts @@ -4,14 +4,14 @@ import { buildCategoryBreakdownData, type DashboardCategoryBreakdownData, type DashboardCategoryBreakdownItem, -} from "@/lib/dashboard/categories/category-breakdown"; +} from "@/features/dashboard/categories/category-breakdown"; import { buildDashboardAdminFilters, excludeAutoInvoiceEntries, -} from "@/lib/dashboard/lancamento-filters"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { getPreviousPeriod } from "@/lib/utils/period"; +} from "@/features/dashboard/lancamento-filters"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getPreviousPeriod } from "@/shared/utils/period"; export type CategoryExpenseItem = DashboardCategoryBreakdownItem; export type ExpensesByCategoryData = DashboardCategoryBreakdownData; diff --git a/lib/dashboard/categories/income-by-category.ts b/src/features/dashboard/categories/income-by-category-queries.ts similarity index 87% rename from lib/dashboard/categories/income-by-category.ts rename to src/features/dashboard/categories/income-by-category-queries.ts index 2c48481..cb2e9ec 100644 --- a/lib/dashboard/categories/income-by-category.ts +++ b/src/features/dashboard/categories/income-by-category-queries.ts @@ -4,15 +4,15 @@ import { buildCategoryBreakdownData, type DashboardCategoryBreakdownData, type DashboardCategoryBreakdownItem, -} from "@/lib/dashboard/categories/category-breakdown"; +} from "@/features/dashboard/categories/category-breakdown"; import { buildDashboardAdminFilters, excludeAutoInvoiceEntries, excludeInitialBalanceWhenConfigured, -} from "@/lib/dashboard/lancamento-filters"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { getPreviousPeriod } from "@/lib/utils/period"; +} from "@/features/dashboard/lancamento-filters"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getPreviousPeriod } from "@/shared/utils/period"; export type CategoryIncomeItem = DashboardCategoryBreakdownItem; export type IncomeByCategoryData = DashboardCategoryBreakdownData; diff --git a/components/dashboard/bill-widget.tsx b/src/features/dashboard/components/bill-widget.tsx similarity index 80% rename from components/dashboard/bill-widget.tsx rename to src/features/dashboard/components/bill-widget.tsx index d7108f9..4ef2bb9 100644 --- a/components/dashboard/bill-widget.tsx +++ b/src/features/dashboard/components/bill-widget.tsx @@ -1,7 +1,7 @@ "use client"; -import type { DashboardBill } from "@/lib/dashboard/bills"; -import { useBillWidgetController } from "@/lib/dashboard/use-bill-widget-controller"; +import type { DashboardBill } from "@/features/dashboard/bills-queries"; +import { useBillWidgetController } from "@/features/dashboard/use-bill-widget-controller"; import { BillsWidgetView } from "./bills/bills-widget-view"; type BillWidgetProps = { diff --git a/components/dashboard/bills/bill-list-item.tsx b/src/features/dashboard/components/bills/bill-list-item.tsx similarity index 82% rename from components/dashboard/bills/bill-list-item.tsx rename to src/features/dashboard/components/bills/bill-list-item.tsx index 9965d70..7aace27 100644 --- a/components/dashboard/bills/bill-list-item.tsx +++ b/src/features/dashboard/components/bills/bill-list-item.tsx @@ -1,13 +1,13 @@ import { RiCheckboxCircleFill } from "@remixicon/react"; -import { EstabelecimentoLogo } from "@/components/lancamentos/shared/estabelecimento-logo"; -import MoneyValues from "@/components/shared/money-values"; -import { Button } from "@/components/ui/button"; -import type { DashboardBill } from "@/lib/dashboard/bills"; import { buildBillStatusLabel, isBillOverdue, -} from "@/lib/dashboard/bills-helpers"; -import { cn } from "@/lib/utils/ui"; +} from "@/features/dashboard/bills-helpers"; +import type { DashboardBill } from "@/features/dashboard/bills-queries"; +import { EstabelecimentoLogo } from "@/features/transactions/components/shared/establishment-logo"; +import MoneyValues from "@/shared/components/money-values"; +import { Button } from "@/shared/components/ui/button"; +import { cn } from "@/shared/utils/ui"; type BillListItemProps = { bill: DashboardBill; diff --git a/components/dashboard/bills/bill-payment-dialog.tsx b/src/features/dashboard/components/bills/bill-payment-dialog.tsx similarity index 93% rename from components/dashboard/bills/bill-payment-dialog.tsx rename to src/features/dashboard/components/bills/bill-payment-dialog.tsx index eacfdec..2d5ef99 100644 --- a/components/dashboard/bills/bill-payment-dialog.tsx +++ b/src/features/dashboard/components/bills/bill-payment-dialog.tsx @@ -4,9 +4,15 @@ import { RiLoader4Line, RiMoneyDollarCircleLine, } from "@remixicon/react"; -import MoneyValues from "@/components/shared/money-values"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +import { + type BillDialogState, + formatBillDateLabel, + getBillStatusBadgeVariant, +} from "@/features/dashboard/bills-helpers"; +import type { DashboardBill } from "@/features/dashboard/bills-queries"; +import MoneyValues from "@/shared/components/money-values"; +import { Badge } from "@/shared/components/ui/badge"; +import { Button } from "@/shared/components/ui/button"; import { Dialog, DialogContent, @@ -14,13 +20,7 @@ import { DialogFooter, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import type { DashboardBill } from "@/lib/dashboard/bills"; -import { - type BillDialogState, - formatBillDateLabel, - getBillStatusBadgeVariant, -} from "@/lib/dashboard/bills-helpers"; +} from "@/shared/components/ui/dialog"; type BillPaymentDialogProps = { bill: DashboardBill | null; diff --git a/components/dashboard/bills/bills-list.tsx b/src/features/dashboard/components/bills/bills-list.tsx similarity index 83% rename from components/dashboard/bills/bills-list.tsx rename to src/features/dashboard/components/bills/bills-list.tsx index 962ccc0..7e9ebe4 100644 --- a/components/dashboard/bills/bills-list.tsx +++ b/src/features/dashboard/components/bills/bills-list.tsx @@ -1,6 +1,6 @@ import { RiBarcodeFill } from "@remixicon/react"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; -import type { DashboardBill } from "@/lib/dashboard/bills"; +import type { DashboardBill } from "@/features/dashboard/bills-queries"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; import { BillListItem } from "./bill-list-item"; type BillsListProps = { diff --git a/components/dashboard/bills/bills-widget-view.tsx b/src/features/dashboard/components/bills/bills-widget-view.tsx similarity index 85% rename from components/dashboard/bills/bills-widget-view.tsx rename to src/features/dashboard/components/bills/bills-widget-view.tsx index d901dea..c001f6d 100644 --- a/components/dashboard/bills/bills-widget-view.tsx +++ b/src/features/dashboard/components/bills/bills-widget-view.tsx @@ -1,5 +1,5 @@ -import type { DashboardBill } from "@/lib/dashboard/bills"; -import type { BillDialogState } from "@/lib/dashboard/bills-helpers"; +import type { BillDialogState } from "@/features/dashboard/bills-helpers"; +import type { DashboardBill } from "@/features/dashboard/bills-queries"; import { BillPaymentDialog } from "./bill-payment-dialog"; import { BillsList } from "./bills-list"; diff --git a/components/dashboard/category-breakdown/category-breakdown-widget-view.tsx b/src/features/dashboard/components/category-breakdown/category-breakdown-widget-view.tsx similarity index 93% rename from components/dashboard/category-breakdown/category-breakdown-widget-view.tsx rename to src/features/dashboard/components/category-breakdown/category-breakdown-widget-view.tsx index 0d7bd7f..2a329ad 100644 --- a/components/dashboard/category-breakdown/category-breakdown-widget-view.tsx +++ b/src/features/dashboard/components/category-breakdown/category-breakdown-widget-view.tsx @@ -12,15 +12,20 @@ import { import Link from "next/link"; import { useMemo, useState } from "react"; import { Pie, PieChart, Tooltip } from "recharts"; -import { CategoryIconBadge } from "@/components/categorias/category-icon-badge"; -import MoneyValues from "@/components/shared/money-values"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; -import { type ChartConfig, ChartContainer } from "@/components/ui/chart"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import type { DashboardCategoryBreakdownData } from "@/lib/dashboard/categories/category-breakdown"; -import { formatCurrency } from "@/lib/lancamentos/formatting-helpers"; -import { formatPercentage as formatPercentageValue } from "@/lib/utils/percentage"; -import { formatPeriodForUrl } from "@/lib/utils/period"; +import { CategoryIconBadge } from "@/features/categories/components/category-icon-badge"; +import type { DashboardCategoryBreakdownData } from "@/features/dashboard/categories/category-breakdown"; +import MoneyValues from "@/shared/components/money-values"; +import { type ChartConfig, ChartContainer } from "@/shared/components/ui/chart"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/shared/components/ui/tabs"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; +import { formatCurrency } from "@/shared/utils/currency"; +import { formatPercentage as formatPercentageValue } from "@/shared/utils/percentage"; +import { formatPeriodForUrl } from "@/shared/utils/period"; type CategoryBreakdownVariant = "income" | "expense"; @@ -228,7 +233,7 @@ export function CategoryBreakdownWidgetView({
diff --git a/components/dashboard/category-history-widget.tsx b/src/features/dashboard/components/category-history-widget.tsx similarity index 95% rename from components/dashboard/category-history-widget.tsx rename to src/features/dashboard/components/category-history-widget.tsx index 00eed86..e4c6518 100644 --- a/components/dashboard/category-history-widget.tsx +++ b/src/features/dashboard/components/category-history-widget.tsx @@ -6,14 +6,14 @@ import { } from "@remixicon/react"; import { useEffect, useMemo, useRef, useState } from "react"; import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; +import type { CategoryHistoryData } from "@/features/dashboard/categories/category-history-queries"; +import { Button } from "@/shared/components/ui/button"; +import { Card, CardContent } from "@/shared/components/ui/card"; import { type ChartConfig, ChartContainer, ChartTooltip, -} from "@/components/ui/chart"; +} from "@/shared/components/ui/chart"; import { Command, CommandEmpty, @@ -21,16 +21,16 @@ import { CommandInput, CommandItem, CommandList, -} from "@/components/ui/command"; +} from "@/shared/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger, -} from "@/components/ui/popover"; -import type { CategoryHistoryData } from "@/lib/dashboard/categories/category-history"; -import { CATEGORY_COLORS } from "@/lib/utils/category-colors"; -import { formatCurrency, formatCurrencyCompact } from "@/lib/utils/currency"; -import { getIconComponent } from "@/lib/utils/icons"; +} from "@/shared/components/ui/popover"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; +import { CATEGORY_COLORS } from "@/shared/utils/category-colors"; +import { formatCurrency, formatCurrencyCompact } from "@/shared/utils/currency"; +import { getIconComponent } from "@/shared/utils/icons"; type CategoryHistoryWidgetProps = { data: CategoryHistoryData; diff --git a/components/dashboard/dashboard-grid-editable.tsx b/src/features/dashboard/components/dashboard-grid-editable.tsx similarity index 93% rename from components/dashboard/dashboard-grid-editable.tsx rename to src/features/dashboard/components/dashboard-grid-editable.tsx index 8603640..8373292 100644 --- a/components/dashboard/dashboard-grid-editable.tsx +++ b/src/features/dashboard/components/dashboard-grid-editable.tsx @@ -25,23 +25,23 @@ import { } from "@remixicon/react"; import { useMemo, useState, useTransition } from "react"; import { toast } from "sonner"; -import { NoteDialog } from "@/components/anotacoes/note-dialog"; -import { SortableWidget } from "@/components/dashboard/sortable-widget"; -import { WidgetSettingsDialog } from "@/components/dashboard/widget-settings-dialog"; -import { LancamentoDialog } from "@/components/lancamentos/dialogs/lancamento-dialog/lancamento-dialog"; -import type { SelectOption } from "@/components/lancamentos/types"; -import { ExpandableWidgetCard } from "@/components/shared/expandable-widget-card"; -import { Button } from "@/components/ui/button"; -import type { DashboardData } from "@/lib/dashboard/fetch-dashboard-data"; +import { SortableWidget } from "@/features/dashboard/components/sortable-widget"; +import { WidgetSettingsDialog } from "@/features/dashboard/components/widget-settings-dialog"; +import type { DashboardData } from "@/features/dashboard/fetch-dashboard-data"; import { resetWidgetPreferences, updateWidgetPreferences, type WidgetPreferences, -} from "@/lib/dashboard/widgets/actions"; +} from "@/features/dashboard/widgets/actions"; import { type WidgetConfig, widgetsConfig, -} from "@/lib/dashboard/widgets/widgets-config"; +} from "@/features/dashboard/widgets/widgets-config"; +import { NoteDialog } from "@/features/notes/components/note-dialog"; +import { LancamentoDialog } from "@/features/transactions/components/dialogs/transaction-dialog/transaction-dialog"; +import type { SelectOption } from "@/features/transactions/components/types"; +import { ExpandableWidgetCard } from "@/shared/components/expandable-widget-card"; +import { Button } from "@/shared/components/ui/button"; type DashboardGridEditableProps = { data: DashboardData; diff --git a/components/dashboard/dashboard-metrics-cards.tsx b/src/features/dashboard/components/dashboard-metrics-cards.tsx similarity index 90% rename from components/dashboard/dashboard-metrics-cards.tsx rename to src/features/dashboard/components/dashboard-metrics-cards.tsx index 474f961..75a55b5 100644 --- a/components/dashboard/dashboard-metrics-cards.tsx +++ b/src/features/dashboard/components/dashboard-metrics-cards.tsx @@ -7,16 +7,16 @@ import { RiIncreaseDecreaseLine, RiSubtractLine, } from "@remixicon/react"; -import MoneyValues from "@/components/shared/money-values"; +import type { DashboardCardMetrics } from "@/features/dashboard/dashboard-metrics-queries"; +import MoneyValues from "@/shared/components/money-values"; import { Card, CardAction, CardFooter, CardHeader, CardTitle, -} from "@/components/ui/card"; -import type { DashboardCardMetrics } from "@/lib/dashboard/dashboard-metrics"; -import { formatPercentage } from "@/lib/utils/percentage"; +} from "@/shared/components/ui/card"; +import { formatPercentage } from "@/shared/utils/percentage"; type DashboardMetricsCardsProps = { metrics: DashboardCardMetrics; @@ -99,7 +99,7 @@ export function DashboardMetricsCards({ metrics }: DashboardMetricsCardsProps) { return ( - + {label} diff --git a/components/dashboard/dashboard-welcome.tsx b/src/features/dashboard/components/dashboard-welcome.tsx similarity index 91% rename from components/dashboard/dashboard-welcome.tsx rename to src/features/dashboard/components/dashboard-welcome.tsx index 0d634c6..f2d680f 100644 --- a/components/dashboard/dashboard-welcome.tsx +++ b/src/features/dashboard/components/dashboard-welcome.tsx @@ -8,7 +8,7 @@ export function DashboardWelcome({ name }: { name?: string | null }) { return (
-

+

{greeting}, {displayName}

{formattedDate}

diff --git a/components/dashboard/expenses-by-category-widget-with-chart.tsx b/src/features/dashboard/components/expenses-by-category-widget-with-chart.tsx similarity index 80% rename from components/dashboard/expenses-by-category-widget-with-chart.tsx rename to src/features/dashboard/components/expenses-by-category-widget-with-chart.tsx index 6cc09d7..5473fad 100644 --- a/components/dashboard/expenses-by-category-widget-with-chart.tsx +++ b/src/features/dashboard/components/expenses-by-category-widget-with-chart.tsx @@ -1,6 +1,6 @@ "use client"; -import type { ExpensesByCategoryData } from "@/lib/dashboard/categories/expenses-by-category"; +import type { ExpensesByCategoryData } from "@/features/dashboard/categories/expenses-by-category-queries"; import { CategoryBreakdownWidgetView } from "./category-breakdown/category-breakdown-widget-view"; type ExpensesByCategoryWidgetWithChartProps = { diff --git a/components/dashboard/goals-progress-widget.tsx b/src/features/dashboard/components/goals-progress-widget.tsx similarity index 76% rename from components/dashboard/goals-progress-widget.tsx rename to src/features/dashboard/components/goals-progress-widget.tsx index 1ddbe21..4aaa7b8 100644 --- a/components/dashboard/goals-progress-widget.tsx +++ b/src/features/dashboard/components/goals-progress-widget.tsx @@ -1,7 +1,7 @@ "use client"; -import type { GoalsProgressData } from "@/lib/dashboard/goals-progress"; -import { useGoalsProgressWidgetController } from "@/lib/dashboard/use-goals-progress-widget-controller"; +import type { GoalsProgressData } from "@/features/dashboard/goals-progress-queries"; +import { useGoalsProgressWidgetController } from "@/features/dashboard/use-goals-progress-widget-controller"; import { GoalsProgressWidgetView } from "./goals-progress/goals-progress-widget-view"; type GoalsProgressWidgetProps = { diff --git a/components/dashboard/goals-progress/goal-progress-item.tsx b/src/features/dashboard/components/goals-progress/goal-progress-item.tsx similarity index 83% rename from components/dashboard/goals-progress/goal-progress-item.tsx rename to src/features/dashboard/components/goals-progress/goal-progress-item.tsx index eb3b203..6583f51 100644 --- a/components/dashboard/goals-progress/goal-progress-item.tsx +++ b/src/features/dashboard/components/goals-progress/goal-progress-item.tsx @@ -1,14 +1,14 @@ import { RiPencilLine } from "@remixicon/react"; -import { CategoryIconBadge } from "@/components/categorias/category-icon-badge"; -import MoneyValues from "@/components/shared/money-values"; -import { Button } from "@/components/ui/button"; -import { Progress } from "@/components/ui/progress"; -import type { GoalProgressItem as GoalProgressItemData } from "@/lib/dashboard/goals-progress"; +import { CategoryIconBadge } from "@/features/categories/components/category-icon-badge"; import { clampGoalProgress, formatGoalProgressPercentage, getGoalProgressStatusColorClass, -} from "@/lib/dashboard/goals-progress-helpers"; +} from "@/features/dashboard/goals-progress-helpers"; +import type { GoalProgressItem as GoalProgressItemData } from "@/features/dashboard/goals-progress-queries"; +import MoneyValues from "@/shared/components/money-values"; +import { Button } from "@/shared/components/ui/button"; +import { Progress } from "@/shared/components/ui/progress"; type GoalProgressItemProps = { item: GoalProgressItemData; diff --git a/components/dashboard/goals-progress/goals-progress-list.tsx b/src/features/dashboard/components/goals-progress/goals-progress-list.tsx similarity index 84% rename from components/dashboard/goals-progress/goals-progress-list.tsx rename to src/features/dashboard/components/goals-progress/goals-progress-list.tsx index 66188b5..3cacbe6 100644 --- a/components/dashboard/goals-progress/goals-progress-list.tsx +++ b/src/features/dashboard/components/goals-progress/goals-progress-list.tsx @@ -1,6 +1,6 @@ import { RiFundsLine } from "@remixicon/react"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; -import type { GoalProgressItem } from "@/lib/dashboard/goals-progress"; +import type { GoalProgressItem } from "@/features/dashboard/goals-progress-queries"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; import { GoalProgressItem as GoalProgressListItem } from "./goal-progress-item"; type GoalsProgressListProps = { diff --git a/components/dashboard/goals-progress/goals-progress-widget-dialogs.tsx b/src/features/dashboard/components/goals-progress/goals-progress-widget-dialogs.tsx similarity index 78% rename from components/dashboard/goals-progress/goals-progress-widget-dialogs.tsx rename to src/features/dashboard/components/goals-progress/goals-progress-widget-dialogs.tsx index 12c2917..bce61be 100644 --- a/components/dashboard/goals-progress/goals-progress-widget-dialogs.tsx +++ b/src/features/dashboard/components/goals-progress/goals-progress-widget-dialogs.tsx @@ -1,5 +1,8 @@ -import { BudgetDialog } from "@/components/orcamentos/budget-dialog"; -import type { Budget, BudgetCategory } from "@/components/orcamentos/types"; +import { BudgetDialog } from "@/features/budgets/components/budget-dialog"; +import type { + Budget, + BudgetCategory, +} from "@/features/budgets/components/types"; type GoalsProgressWidgetDialogsProps = { selectedBudget: Budget | null; diff --git a/components/dashboard/goals-progress/goals-progress-widget-view.tsx b/src/features/dashboard/components/goals-progress/goals-progress-widget-view.tsx similarity index 87% rename from components/dashboard/goals-progress/goals-progress-widget-view.tsx rename to src/features/dashboard/components/goals-progress/goals-progress-widget-view.tsx index 1a711c5..59bd676 100644 --- a/components/dashboard/goals-progress/goals-progress-widget-view.tsx +++ b/src/features/dashboard/components/goals-progress/goals-progress-widget-view.tsx @@ -1,8 +1,11 @@ -import type { Budget, BudgetCategory } from "@/components/orcamentos/types"; +import type { + Budget, + BudgetCategory, +} from "@/features/budgets/components/types"; import type { GoalProgressItem, GoalsProgressData, -} from "@/lib/dashboard/goals-progress"; +} from "@/features/dashboard/goals-progress-queries"; import { GoalsProgressList } from "./goals-progress-list"; import { GoalsProgressWidgetDialogs } from "./goals-progress-widget-dialogs"; diff --git a/components/dashboard/income-by-category-widget-with-chart.tsx b/src/features/dashboard/components/income-by-category-widget-with-chart.tsx similarity index 79% rename from components/dashboard/income-by-category-widget-with-chart.tsx rename to src/features/dashboard/components/income-by-category-widget-with-chart.tsx index d797c52..522c096 100644 --- a/components/dashboard/income-by-category-widget-with-chart.tsx +++ b/src/features/dashboard/components/income-by-category-widget-with-chart.tsx @@ -1,6 +1,6 @@ "use client"; -import type { IncomeByCategoryData } from "@/lib/dashboard/categories/income-by-category"; +import type { IncomeByCategoryData } from "@/features/dashboard/categories/income-by-category-queries"; import { CategoryBreakdownWidgetView } from "./category-breakdown/category-breakdown-widget-view"; type IncomeByCategoryWidgetWithChartProps = { diff --git a/components/dashboard/income-expense-balance-widget.tsx b/src/features/dashboard/components/income-expense-balance-widget.tsx similarity index 92% rename from components/dashboard/income-expense-balance-widget.tsx rename to src/features/dashboard/components/income-expense-balance-widget.tsx index 275cfb5..536eff1 100644 --- a/components/dashboard/income-expense-balance-widget.tsx +++ b/src/features/dashboard/components/income-expense-balance-widget.tsx @@ -2,15 +2,15 @@ import { RiLineChartLine } from "@remixicon/react"; import { Bar, BarChart, CartesianGrid, XAxis } from "recharts"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; -import { CardContent } from "@/components/ui/card"; +import type { IncomeExpenseBalanceData } from "@/features/dashboard/income-expense-balance-queries"; +import { CardContent } from "@/shared/components/ui/card"; import { type ChartConfig, ChartContainer, ChartTooltip, -} from "@/components/ui/chart"; -import type { IncomeExpenseBalanceData } from "@/lib/dashboard/income-expense-balance"; -import { formatCurrency } from "@/lib/utils/currency"; +} from "@/shared/components/ui/chart"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; +import { formatCurrency } from "@/shared/utils/currency"; type IncomeExpenseBalanceWidgetProps = { data: IncomeExpenseBalanceData; diff --git a/components/dashboard/installment-analysis/installment-analysis-page.tsx b/src/features/dashboard/components/installment-analysis/installment-analysis-page.tsx similarity index 97% rename from components/dashboard/installment-analysis/installment-analysis-page.tsx rename to src/features/dashboard/components/installment-analysis/installment-analysis-page.tsx index 514a2ec..c505756 100644 --- a/components/dashboard/installment-analysis/installment-analysis-page.tsx +++ b/src/features/dashboard/components/installment-analysis/installment-analysis-page.tsx @@ -6,9 +6,9 @@ import { RiCheckboxLine, } from "@remixicon/react"; import { useMemo, useState } from "react"; -import MoneyValues from "@/components/shared/money-values"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; +import MoneyValues from "@/shared/components/money-values"; +import { Button } from "@/shared/components/ui/button"; +import { Card, CardContent } from "@/shared/components/ui/card"; import { InstallmentGroupCard } from "./installment-group-card"; import type { InstallmentAnalysisData } from "./types"; diff --git a/components/dashboard/installment-analysis/installment-group-card.tsx b/src/features/dashboard/components/installment-analysis/installment-group-card.tsx similarity index 95% rename from components/dashboard/installment-analysis/installment-group-card.tsx rename to src/features/dashboard/components/installment-analysis/installment-group-card.tsx index 429a1cc..cb4c198 100644 --- a/components/dashboard/installment-analysis/installment-group-card.tsx +++ b/src/features/dashboard/components/installment-analysis/installment-group-card.tsx @@ -8,12 +8,12 @@ import { import { format } from "date-fns"; import { ptBR } from "date-fns/locale"; import { useState } from "react"; -import MoneyValues from "@/components/shared/money-values"; -import { Badge } from "@/components/ui/badge"; -import { Card, CardContent } from "@/components/ui/card"; -import { Checkbox } from "@/components/ui/checkbox"; -import { Progress } from "@/components/ui/progress"; -import { cn } from "@/lib/utils/ui"; +import MoneyValues from "@/shared/components/money-values"; +import { Badge } from "@/shared/components/ui/badge"; +import { Card, CardContent } from "@/shared/components/ui/card"; +import { Checkbox } from "@/shared/components/ui/checkbox"; +import { Progress } from "@/shared/components/ui/progress"; +import { cn } from "@/shared/utils/ui"; import type { InstallmentGroup } from "./types"; type InstallmentGroupCardProps = { diff --git a/components/dashboard/installment-analysis/types.ts b/src/features/dashboard/components/installment-analysis/types.ts similarity index 63% rename from components/dashboard/installment-analysis/types.ts rename to src/features/dashboard/components/installment-analysis/types.ts index 4f18f59..50ac299 100644 --- a/components/dashboard/installment-analysis/types.ts +++ b/src/features/dashboard/components/installment-analysis/types.ts @@ -1,6 +1,6 @@ import type { InstallmentAnalysisData, InstallmentGroup, -} from "@/lib/dashboard/expenses/installment-analysis"; +} from "@/features/dashboard/expenses/installment-analysis-queries"; export type { InstallmentAnalysisData, InstallmentGroup }; diff --git a/components/dashboard/installment-expenses-widget.tsx b/src/features/dashboard/components/installment-expenses-widget.tsx similarity index 75% rename from components/dashboard/installment-expenses-widget.tsx rename to src/features/dashboard/components/installment-expenses-widget.tsx index c5d4be3..260f5c5 100644 --- a/components/dashboard/installment-expenses-widget.tsx +++ b/src/features/dashboard/components/installment-expenses-widget.tsx @@ -1,4 +1,4 @@ -import type { InstallmentExpensesData } from "@/lib/dashboard/expenses/installment-expenses"; +import type { InstallmentExpensesData } from "@/features/dashboard/expenses/installment-expenses-queries"; import { InstallmentExpensesWidgetView } from "./installment-expenses/installment-expenses-widget-view"; type InstallmentExpensesWidgetProps = { diff --git a/components/dashboard/installment-expenses/installment-expense-list-item.tsx b/src/features/dashboard/components/installment-expenses/installment-expense-list-item.tsx similarity index 82% rename from components/dashboard/installment-expenses/installment-expense-list-item.tsx rename to src/features/dashboard/components/installment-expenses/installment-expense-list-item.tsx index c931eea..85b2b8d 100644 --- a/components/dashboard/installment-expenses/installment-expense-list-item.tsx +++ b/src/features/dashboard/components/installment-expenses/installment-expense-list-item.tsx @@ -1,13 +1,13 @@ import Image from "next/image"; -import MoneyValues from "@/components/shared/money-values"; -import { Progress } from "@/components/ui/progress"; +import type { InstallmentExpense } from "@/features/dashboard/expenses/installment-expenses-queries"; +import { buildInstallmentExpenseDisplay } from "@/features/dashboard/installment-expenses-helpers"; +import MoneyValues from "@/shared/components/money-values"; +import { Progress } from "@/shared/components/ui/progress"; import { Tooltip, TooltipContent, TooltipTrigger, -} from "@/components/ui/tooltip"; -import type { InstallmentExpense } from "@/lib/dashboard/expenses/installment-expenses"; -import { buildInstallmentExpenseDisplay } from "@/lib/dashboard/installment-expenses-helpers"; +} from "@/shared/components/ui/tooltip"; type InstallmentExpenseListItemProps = { expense: InstallmentExpense; @@ -41,7 +41,7 @@ export function InstallmentExpenseListItem({ Última parcela {account.name} diff --git a/components/dashboard/notes-widget.tsx b/src/features/dashboard/components/notes-widget.tsx similarity index 81% rename from components/dashboard/notes-widget.tsx rename to src/features/dashboard/components/notes-widget.tsx index accf53e..2ccfe73 100644 --- a/components/dashboard/notes-widget.tsx +++ b/src/features/dashboard/components/notes-widget.tsx @@ -1,7 +1,7 @@ "use client"; -import type { DashboardNote } from "@/lib/dashboard/notes"; -import { useNotesWidgetController } from "@/lib/dashboard/use-notes-widget-controller"; +import type { DashboardNote } from "@/features/dashboard/notes-queries"; +import { useNotesWidgetController } from "@/features/dashboard/use-notes-widget-controller"; import { NotesWidgetView } from "./notes/notes-widget-view"; type NotesWidgetProps = { diff --git a/components/dashboard/notes/note-list-item.tsx b/src/features/dashboard/components/notes/note-list-item.tsx similarity index 88% rename from components/dashboard/notes/note-list-item.tsx rename to src/features/dashboard/components/notes/note-list-item.tsx index 85aad79..06317f5 100644 --- a/components/dashboard/notes/note-list-item.tsx +++ b/src/features/dashboard/components/notes/note-list-item.tsx @@ -1,12 +1,12 @@ import { RiFileList2Line, RiPencilLine } from "@remixicon/react"; -import type { Note } from "@/components/anotacoes/types"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +import type { Note } from "@/features/notes/components/types"; import { buildNoteDisplayTitle, formatNoteCreatedAt, getNoteTasksSummary, -} from "@/lib/notes/formatters"; +} from "@/features/notes/lib/formatters"; +import { Badge } from "@/shared/components/ui/badge"; +import { Button } from "@/shared/components/ui/button"; type NoteListItemProps = { note: Note; diff --git a/components/dashboard/notes/notes-list.tsx b/src/features/dashboard/components/notes/notes-list.tsx similarity index 86% rename from components/dashboard/notes/notes-list.tsx rename to src/features/dashboard/components/notes/notes-list.tsx index f72e832..8beeb15 100644 --- a/components/dashboard/notes/notes-list.tsx +++ b/src/features/dashboard/components/notes/notes-list.tsx @@ -1,6 +1,6 @@ import { RiTodoLine } from "@remixicon/react"; -import type { Note } from "@/components/anotacoes/types"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; +import type { Note } from "@/features/notes/components/types"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; import { NoteListItem } from "./note-list-item"; type NotesListProps = { diff --git a/components/dashboard/notes/notes-widget-dialogs.tsx b/src/features/dashboard/components/notes/notes-widget-dialogs.tsx similarity index 75% rename from components/dashboard/notes/notes-widget-dialogs.tsx rename to src/features/dashboard/components/notes/notes-widget-dialogs.tsx index e0c7686..98b3070 100644 --- a/components/dashboard/notes/notes-widget-dialogs.tsx +++ b/src/features/dashboard/components/notes/notes-widget-dialogs.tsx @@ -1,6 +1,6 @@ -import { NoteDetailsDialog } from "@/components/anotacoes/note-details-dialog"; -import { NoteDialog } from "@/components/anotacoes/note-dialog"; -import type { Note } from "@/components/anotacoes/types"; +import { NoteDetailsDialog } from "@/features/notes/components/note-details-dialog"; +import { NoteDialog } from "@/features/notes/components/note-dialog"; +import type { Note } from "@/features/notes/components/types"; type NotesWidgetDialogsProps = { noteToEdit: Note | null; diff --git a/components/dashboard/notes/notes-widget-view.tsx b/src/features/dashboard/components/notes/notes-widget-view.tsx similarity index 94% rename from components/dashboard/notes/notes-widget-view.tsx rename to src/features/dashboard/components/notes/notes-widget-view.tsx index 07c67f3..f226cc5 100644 --- a/components/dashboard/notes/notes-widget-view.tsx +++ b/src/features/dashboard/components/notes/notes-widget-view.tsx @@ -1,4 +1,4 @@ -import type { Note } from "@/components/anotacoes/types"; +import type { Note } from "@/features/notes/components/types"; import { NotesList } from "./notes-list"; import { NotesWidgetDialogs } from "./notes-widget-dialogs"; diff --git a/components/dashboard/payers-widget.tsx b/src/features/dashboard/components/payers-widget.tsx similarity index 87% rename from components/dashboard/payers-widget.tsx rename to src/features/dashboard/components/payers-widget.tsx index 30154ac..f36771a 100644 --- a/components/dashboard/payers-widget.tsx +++ b/src/features/dashboard/components/payers-widget.tsx @@ -8,13 +8,17 @@ import { RiVerifiedBadgeFill, } from "@remixicon/react"; import Link from "next/link"; -import MoneyValues from "@/components/shared/money-values"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; -import { CardContent } from "@/components/ui/card"; -import type { DashboardPagador } from "@/lib/dashboard/pagadores"; -import { getAvatarSrc } from "@/lib/pagadores/utils"; -import { formatPercentage } from "@/lib/utils/percentage"; +import type { DashboardPagador } from "@/features/dashboard/payers-queries"; +import MoneyValues from "@/shared/components/money-values"; +import { + Avatar, + AvatarFallback, + AvatarImage, +} from "@/shared/components/ui/avatar"; +import { CardContent } from "@/shared/components/ui/card"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; +import { getAvatarSrc } from "@/shared/lib/payers/utils"; +import { formatPercentage } from "@/shared/utils/percentage"; type PayersWidgetProps = { pagadores: DashboardPagador[]; @@ -71,7 +75,7 @@ export function PayersWidget({ pagadores }: PayersWidgetProps) {
diff --git a/components/dashboard/payment-overview-widget.tsx b/src/features/dashboard/components/payment-overview-widget.tsx similarity index 66% rename from components/dashboard/payment-overview-widget.tsx rename to src/features/dashboard/components/payment-overview-widget.tsx index 7e69e46..2de4276 100644 --- a/components/dashboard/payment-overview-widget.tsx +++ b/src/features/dashboard/components/payment-overview-widget.tsx @@ -1,8 +1,8 @@ "use client"; -import type { PaymentConditionsData } from "@/lib/dashboard/payments/payment-conditions"; -import type { PaymentMethodsData } from "@/lib/dashboard/payments/payment-methods"; -import { usePaymentOverviewWidgetController } from "@/lib/dashboard/use-payment-overview-widget-controller"; +import type { PaymentConditionsData } from "@/features/dashboard/payments/payment-conditions-queries"; +import type { PaymentMethodsData } from "@/features/dashboard/payments/payment-methods-queries"; +import { usePaymentOverviewWidgetController } from "@/features/dashboard/use-payment-overview-widget-controller"; import { PaymentOverviewWidgetView } from "./payment-overview/payment-overview-widget-view"; type PaymentOverviewWidgetProps = { diff --git a/components/dashboard/payment-overview/payment-breakdown-list-item.tsx b/src/features/dashboard/components/payment-overview/payment-breakdown-list-item.tsx similarity index 87% rename from components/dashboard/payment-overview/payment-breakdown-list-item.tsx rename to src/features/dashboard/components/payment-overview/payment-breakdown-list-item.tsx index b50cde9..6bfca19 100644 --- a/components/dashboard/payment-overview/payment-breakdown-list-item.tsx +++ b/src/features/dashboard/components/payment-overview/payment-breakdown-list-item.tsx @@ -1,10 +1,10 @@ import type { ReactNode } from "react"; -import MoneyValues from "@/components/shared/money-values"; -import { Progress } from "@/components/ui/progress"; import { formatPaymentBreakdownPercentage, formatPaymentBreakdownTransactionsLabel, -} from "@/lib/dashboard/payment-breakdown-formatters"; +} from "@/features/dashboard/payment-breakdown-formatters"; +import MoneyValues from "@/shared/components/money-values"; +import { Progress } from "@/shared/components/ui/progress"; const ICON_WRAPPER_CLASS = "flex size-9.5 shrink-0 items-center justify-center rounded-full bg-muted text-foreground"; diff --git a/components/dashboard/payment-overview/payment-breakdown-list.tsx b/src/features/dashboard/components/payment-overview/payment-breakdown-list.tsx similarity index 93% rename from components/dashboard/payment-overview/payment-breakdown-list.tsx rename to src/features/dashboard/components/payment-overview/payment-breakdown-list.tsx index edd4dd2..1da7954 100644 --- a/components/dashboard/payment-overview/payment-breakdown-list.tsx +++ b/src/features/dashboard/components/payment-overview/payment-breakdown-list.tsx @@ -1,5 +1,5 @@ import type { ReactNode } from "react"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; import { PaymentBreakdownListItem, type PaymentBreakdownListItemData, diff --git a/components/dashboard/payment-overview/payment-conditions-widget.tsx b/src/features/dashboard/components/payment-overview/payment-conditions-widget.tsx similarity index 86% rename from components/dashboard/payment-overview/payment-conditions-widget.tsx rename to src/features/dashboard/components/payment-overview/payment-conditions-widget.tsx index efb3c63..189d398 100644 --- a/components/dashboard/payment-overview/payment-conditions-widget.tsx +++ b/src/features/dashboard/components/payment-overview/payment-conditions-widget.tsx @@ -1,6 +1,6 @@ import { RiCheckLine, RiSlideshowLine } from "@remixicon/react"; -import type { PaymentConditionsData } from "@/lib/dashboard/payments/payment-conditions"; -import { getConditionIcon } from "@/lib/utils/icons"; +import type { PaymentConditionsData } from "@/features/dashboard/payments/payment-conditions-queries"; +import { getConditionIcon } from "@/shared/utils/icons"; import { PaymentBreakdownList, type PaymentBreakdownListItemData, diff --git a/components/dashboard/payment-overview/payment-methods-widget.tsx b/src/features/dashboard/components/payment-overview/payment-methods-widget.tsx similarity index 87% rename from components/dashboard/payment-overview/payment-methods-widget.tsx rename to src/features/dashboard/components/payment-overview/payment-methods-widget.tsx index 83769bd..cf84b59 100644 --- a/components/dashboard/payment-overview/payment-methods-widget.tsx +++ b/src/features/dashboard/components/payment-overview/payment-methods-widget.tsx @@ -1,6 +1,6 @@ import { RiBankCard2Line, RiMoneyDollarCircleLine } from "@remixicon/react"; -import type { PaymentMethodsData } from "@/lib/dashboard/payments/payment-methods"; -import { getPaymentMethodIcon } from "@/lib/utils/icons"; +import type { PaymentMethodsData } from "@/features/dashboard/payments/payment-methods-queries"; +import { getPaymentMethodIcon } from "@/shared/utils/icons"; import { PaymentBreakdownList, type PaymentBreakdownListItemData, diff --git a/components/dashboard/payment-overview/payment-overview-widget-view.tsx b/src/features/dashboard/components/payment-overview/payment-overview-widget-view.tsx similarity index 77% rename from components/dashboard/payment-overview/payment-overview-widget-view.tsx rename to src/features/dashboard/components/payment-overview/payment-overview-widget-view.tsx index 59328e5..9428dd7 100644 --- a/components/dashboard/payment-overview/payment-overview-widget-view.tsx +++ b/src/features/dashboard/components/payment-overview/payment-overview-widget-view.tsx @@ -1,8 +1,13 @@ import { RiMoneyDollarCircleLine, RiSlideshowLine } from "@remixicon/react"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import type { PaymentOverviewTab } from "@/lib/dashboard/payment-overview-tabs"; -import type { PaymentConditionsData } from "@/lib/dashboard/payments/payment-conditions"; -import type { PaymentMethodsData } from "@/lib/dashboard/payments/payment-methods"; +import type { PaymentOverviewTab } from "@/features/dashboard/payment-overview-tabs"; +import type { PaymentConditionsData } from "@/features/dashboard/payments/payment-conditions-queries"; +import type { PaymentMethodsData } from "@/features/dashboard/payments/payment-methods-queries"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/shared/components/ui/tabs"; import { PaymentConditionsWidget } from "./payment-conditions-widget"; import { PaymentMethodsWidget } from "./payment-methods-widget"; diff --git a/components/dashboard/payment-status-widget.tsx b/src/features/dashboard/components/payment-status-widget.tsx similarity index 75% rename from components/dashboard/payment-status-widget.tsx rename to src/features/dashboard/components/payment-status-widget.tsx index 622a031..a7993da 100644 --- a/components/dashboard/payment-status-widget.tsx +++ b/src/features/dashboard/components/payment-status-widget.tsx @@ -1,6 +1,6 @@ "use client"; -import type { PaymentStatusData } from "@/lib/dashboard/payments/payment-status"; +import type { PaymentStatusData } from "@/features/dashboard/payments/payment-status-queries"; import { PaymentStatusWidgetView } from "./payment-status/payment-status-widget-view"; type PaymentStatusWidgetProps = { diff --git a/components/dashboard/payment-status/payment-status-category-section.tsx b/src/features/dashboard/components/payment-status/payment-status-category-section.tsx similarity index 88% rename from components/dashboard/payment-status/payment-status-category-section.tsx rename to src/features/dashboard/components/payment-status/payment-status-category-section.tsx index 0225b17..cb6942e 100644 --- a/components/dashboard/payment-status/payment-status-category-section.tsx +++ b/src/features/dashboard/components/payment-status/payment-status-category-section.tsx @@ -1,6 +1,6 @@ -import MoneyValues from "@/components/shared/money-values"; -import StatusDot from "@/components/shared/status-dot"; -import { Progress } from "@/components/ui/progress"; +import MoneyValues from "@/shared/components/money-values"; +import StatusDot from "@/shared/components/status-dot"; +import { Progress } from "@/shared/components/ui/progress"; type PaymentStatusCategorySectionProps = { title: string; diff --git a/components/dashboard/payment-status/payment-status-widget-view.tsx b/src/features/dashboard/components/payment-status/payment-status-widget-view.tsx similarity index 84% rename from components/dashboard/payment-status/payment-status-widget-view.tsx rename to src/features/dashboard/components/payment-status/payment-status-widget-view.tsx index 9692ae2..9278a7f 100644 --- a/components/dashboard/payment-status/payment-status-widget-view.tsx +++ b/src/features/dashboard/components/payment-status/payment-status-widget-view.tsx @@ -1,7 +1,7 @@ import { RiWallet3Line } from "@remixicon/react"; -import { CardContent } from "@/components/ui/card"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; -import type { PaymentStatusData } from "@/lib/dashboard/payments/payment-status"; +import type { PaymentStatusData } from "@/features/dashboard/payments/payment-status-queries"; +import { CardContent } from "@/shared/components/ui/card"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; import { PaymentStatusCategorySection } from "./payment-status-category-section"; type PaymentStatusWidgetViewProps = { diff --git a/components/dashboard/purchases-by-category-widget.tsx b/src/features/dashboard/components/purchases-by-category-widget.tsx similarity index 92% rename from components/dashboard/purchases-by-category-widget.tsx rename to src/features/dashboard/components/purchases-by-category-widget.tsx index edf8ede..553aed8 100644 --- a/components/dashboard/purchases-by-category-widget.tsx +++ b/src/features/dashboard/components/purchases-by-category-widget.tsx @@ -2,18 +2,18 @@ import { RiArrowDownSFill, RiStore3Line } from "@remixicon/react"; import { useEffect, useMemo, useRef, useState } from "react"; -import { EstabelecimentoLogo } from "@/components/lancamentos/shared/estabelecimento-logo"; -import MoneyValues from "@/components/shared/money-values"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; +import type { PurchasesByCategoryData } from "@/features/dashboard/purchases-by-category-queries"; +import { EstabelecimentoLogo } from "@/features/transactions/components/shared/establishment-logo"; +import MoneyValues from "@/shared/components/money-values"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { CATEGORY_TYPE_LABEL } from "@/lib/categorias/constants"; -import type { PurchasesByCategoryData } from "@/lib/dashboard/purchases-by-category"; +} from "@/shared/components/ui/select"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; +import { CATEGORY_TYPE_LABEL } from "@/shared/lib/categories/constants"; type PurchasesByCategoryWidgetProps = { data: PurchasesByCategoryData; diff --git a/components/dashboard/recurring-expenses-widget.tsx b/src/features/dashboard/components/recurring-expenses-widget.tsx similarity index 83% rename from components/dashboard/recurring-expenses-widget.tsx rename to src/features/dashboard/components/recurring-expenses-widget.tsx index 34f281c..a232e5e 100644 --- a/components/dashboard/recurring-expenses-widget.tsx +++ b/src/features/dashboard/components/recurring-expenses-widget.tsx @@ -1,8 +1,8 @@ import { RiRefreshLine } from "@remixicon/react"; -import { EstabelecimentoLogo } from "@/components/lancamentos/shared/estabelecimento-logo"; -import MoneyValues from "@/components/shared/money-values"; -import type { RecurringExpensesData } from "@/lib/dashboard/expenses/recurring-expenses"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; +import type { RecurringExpensesData } from "@/features/dashboard/expenses/recurring-expenses-queries"; +import { EstabelecimentoLogo } from "@/features/transactions/components/shared/establishment-logo"; +import MoneyValues from "@/shared/components/money-values"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; type RecurringExpensesWidgetProps = { data: RecurringExpensesData; diff --git a/src/features/dashboard/components/recurring-series-widget.tsx b/src/features/dashboard/components/recurring-series-widget.tsx new file mode 100644 index 0000000..e092091 --- /dev/null +++ b/src/features/dashboard/components/recurring-series-widget.tsx @@ -0,0 +1,153 @@ +"use client"; + +import { + RiPauseCircleLine, + RiPlayCircleLine, + RiRefreshLine, + RiStopCircleLine, +} from "@remixicon/react"; +import { useTransition } from "react"; +import { toast } from "sonner"; +import type { RecurringSeriesData } from "@/features/dashboard/recurring/recurring-series-queries"; +import { + cancelRecurringSeriesAction, + pauseRecurringSeriesAction, + resumeRecurringSeriesAction, +} from "@/features/recurring/actions"; +import MoneyValues from "@/shared/components/money-values"; +import { Badge } from "@/shared/components/ui/badge"; +import { Button } from "@/shared/components/ui/button"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; +import { formatMonthYearLabel } from "@/shared/utils/period"; + +type RecurringSeriesWidgetProps = { + data: RecurringSeriesData; +}; + +export function RecurringSeriesWidget({ data }: RecurringSeriesWidgetProps) { + const [isPending, startTransition] = useTransition(); + + if (data.series.length === 0) { + return ( + } + title="Nenhuma série recorrente" + description="Séries recorrentes aparecerão aqui quando forem criadas." + /> + ); + } + + const handlePause = (seriesId: string) => { + startTransition(async () => { + const result = await pauseRecurringSeriesAction({ seriesId }); + if (result.success) { + toast.success(result.message); + } else { + toast.error(result.error); + } + }); + }; + + const handleResume = (seriesId: string) => { + startTransition(async () => { + const result = await resumeRecurringSeriesAction({ seriesId }); + if (result.success) { + toast.success(result.message); + } else { + toast.error(result.error); + } + }); + }; + + const handleCancel = (seriesId: string) => { + if ( + !confirm( + "Tem certeza que deseja cancelar esta série recorrente? Lançamentos passados serão mantidos.", + ) + ) { + return; + } + startTransition(async () => { + const result = await cancelRecurringSeriesAction({ seriesId }); + if (result.success) { + toast.success(result.message); + } else { + toast.error(result.error); + } + }); + }; + + return ( +
+
    + {data.series.map((item) => ( +
  • +
    +
    +
    +

    + {item.name} +

    + + {item.status === "active" ? "Ativo" : "Pausado"} + +
    + +
    + +
    + + Dia {item.dayOfMonth} · {item.paymentMethod} + {item.categoryName ? ` · ${item.categoryName}` : ""} + + Próx: {formatMonthYearLabel(item.nextPeriod)} +
    + +
    + {item.status === "active" ? ( + + ) : ( + + )} + +
    +
    +
  • + ))} +
+
+ ); +} diff --git a/components/dashboard/sortable-widget.tsx b/src/features/dashboard/components/sortable-widget.tsx similarity index 95% rename from components/dashboard/sortable-widget.tsx rename to src/features/dashboard/components/sortable-widget.tsx index 93b783e..285a859 100644 --- a/components/dashboard/sortable-widget.tsx +++ b/src/features/dashboard/components/sortable-widget.tsx @@ -3,7 +3,7 @@ import { useSortable } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; import type { ReactNode } from "react"; -import { cn } from "@/lib/utils"; +import { cn } from "@/shared/utils"; type SortableWidgetProps = { id: string; diff --git a/components/dashboard/spending-overview-widget.tsx b/src/features/dashboard/components/spending-overview-widget.tsx similarity index 84% rename from components/dashboard/spending-overview-widget.tsx rename to src/features/dashboard/components/spending-overview-widget.tsx index 72af23f..22f34c3 100644 --- a/components/dashboard/spending-overview-widget.tsx +++ b/src/features/dashboard/components/spending-overview-widget.tsx @@ -2,9 +2,14 @@ import { RiArrowUpDoubleLine, RiStore2Line } from "@remixicon/react"; import { useState } from "react"; -import type { TopExpensesData } from "@/lib/dashboard/expenses/top-expenses"; -import type { TopEstablishmentsData } from "@/lib/dashboard/top-establishments"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs"; +import type { TopExpensesData } from "@/features/dashboard/expenses/top-expenses-queries"; +import type { TopEstablishmentsData } from "@/features/dashboard/top-establishments-queries"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/shared/components/ui/tabs"; import { TopEstablishmentsWidget } from "./top-establishments-widget"; import { TopExpensesWidget } from "./top-expenses-widget"; diff --git a/components/dashboard/top-establishments-widget.tsx b/src/features/dashboard/components/top-establishments-widget.tsx similarity index 83% rename from components/dashboard/top-establishments-widget.tsx rename to src/features/dashboard/components/top-establishments-widget.tsx index 7f5bdae..dbb2182 100644 --- a/components/dashboard/top-establishments-widget.tsx +++ b/src/features/dashboard/components/top-establishments-widget.tsx @@ -1,8 +1,8 @@ import { RiStore2Line } from "@remixicon/react"; -import { EstabelecimentoLogo } from "@/components/lancamentos/shared/estabelecimento-logo"; -import MoneyValues from "@/components/shared/money-values"; -import type { TopEstablishmentsData } from "@/lib/dashboard/top-establishments"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; +import type { TopEstablishmentsData } from "@/features/dashboard/top-establishments-queries"; +import { EstabelecimentoLogo } from "@/features/transactions/components/shared/establishment-logo"; +import MoneyValues from "@/shared/components/money-values"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; type TopEstablishmentsWidgetProps = { data: TopEstablishmentsData; diff --git a/components/dashboard/top-expenses-widget.tsx b/src/features/dashboard/components/top-expenses-widget.tsx similarity index 91% rename from components/dashboard/top-expenses-widget.tsx rename to src/features/dashboard/components/top-expenses-widget.tsx index 3f5acb4..4892265 100644 --- a/components/dashboard/top-expenses-widget.tsx +++ b/src/features/dashboard/components/top-expenses-widget.tsx @@ -2,14 +2,14 @@ import { RiArrowUpDoubleLine } from "@remixicon/react"; import { useMemo, useState } from "react"; -import { EstabelecimentoLogo } from "@/components/lancamentos/shared/estabelecimento-logo"; -import MoneyValues from "@/components/shared/money-values"; -import { Switch } from "@/components/ui/switch"; import type { TopExpense, TopExpensesData, -} from "@/lib/dashboard/expenses/top-expenses"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; +} from "@/features/dashboard/expenses/top-expenses-queries"; +import { EstabelecimentoLogo } from "@/features/transactions/components/shared/establishment-logo"; +import MoneyValues from "@/shared/components/money-values"; +import { Switch } from "@/shared/components/ui/switch"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; type TopExpensesWidgetProps = { allExpenses: TopExpensesData; diff --git a/components/dashboard/welcome-widget.ts b/src/features/dashboard/components/welcome-widget.ts similarity index 88% rename from components/dashboard/welcome-widget.ts rename to src/features/dashboard/components/welcome-widget.ts index 2dd3a77..efe3aed 100644 --- a/components/dashboard/welcome-widget.ts +++ b/src/features/dashboard/components/welcome-widget.ts @@ -1,7 +1,7 @@ import { formatBusinessCurrentDate, getBusinessGreeting, -} from "@/lib/utils/date"; +} from "@/shared/utils/date"; export const formatCurrentDate = (date = new Date()) => formatBusinessCurrentDate(date); diff --git a/components/dashboard/widget-settings-dialog.tsx b/src/features/dashboard/components/widget-settings-dialog.tsx similarity index 89% rename from components/dashboard/widget-settings-dialog.tsx rename to src/features/dashboard/components/widget-settings-dialog.tsx index ad389a0..c8a0f82 100644 --- a/components/dashboard/widget-settings-dialog.tsx +++ b/src/features/dashboard/components/widget-settings-dialog.tsx @@ -2,7 +2,8 @@ import { RiRefreshLine, RiSettings4Line } from "@remixicon/react"; import { useState } from "react"; -import { Button } from "@/components/ui/button"; +import { widgetsConfig } from "@/features/dashboard/widgets/widgets-config"; +import { Button } from "@/shared/components/ui/button"; import { Dialog, DialogContent, @@ -11,10 +12,9 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; -import { Switch } from "@/components/ui/switch"; -import { widgetsConfig } from "@/lib/dashboard/widgets/widgets-config"; -import { cn } from "@/lib/utils"; +} from "@/shared/components/ui/dialog"; +import { Switch } from "@/shared/components/ui/switch"; +import { cn } from "@/shared/utils"; type WidgetSettingsDialogProps = { hiddenWidgets: string[]; diff --git a/lib/dashboard/dashboard-metrics.ts b/src/features/dashboard/dashboard-metrics-queries.ts similarity index 94% rename from lib/dashboard/dashboard-metrics.ts rename to src/features/dashboard/dashboard-metrics-queries.ts index c6246f7..a63127c 100644 --- a/lib/dashboard/dashboard-metrics.ts +++ b/src/features/dashboard/dashboard-metrics-queries.ts @@ -4,16 +4,16 @@ import { buildDashboardAdminFilters, excludeAutoInvoiceEntries, excludeInitialBalanceWhenConfigured, -} from "@/lib/dashboard/lancamento-filters"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { safeToNumber } from "@/lib/utils/number"; +} from "@/features/dashboard/lancamento-filters"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { safeToNumber } from "@/shared/utils/number"; import { addMonthsToPeriod, buildPeriodRange, comparePeriods, getPreviousPeriod, -} from "@/lib/utils/period"; +} from "@/shared/utils/period"; const RECEITA = "Receita"; const DESPESA = "Despesa"; diff --git a/lib/dashboard/expenses/installment-analysis.ts b/src/features/dashboard/expenses/installment-analysis-queries.ts similarity index 95% rename from lib/dashboard/expenses/installment-analysis.ts rename to src/features/dashboard/expenses/installment-analysis-queries.ts index c458464..8eac629 100644 --- a/lib/dashboard/expenses/installment-analysis.ts +++ b/src/features/dashboard/expenses/installment-analysis-queries.ts @@ -3,14 +3,14 @@ import { cartoes, lancamentos, pagadores } from "@/db/schema"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX, INITIAL_BALANCE_NOTE, -} from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; +} from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; import { buildDateOnlyStringFromPeriodDay, parseLocalDateString, -} from "@/lib/utils/date"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +} from "@/shared/utils/date"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; // Calcula a data de vencimento baseada no período e dia de vencimento do cartão function calculateDueDate(period: string, dueDay: string | null): Date | null { diff --git a/lib/dashboard/expenses/installment-expenses.ts b/src/features/dashboard/expenses/installment-expenses-queries.ts similarity index 92% rename from lib/dashboard/expenses/installment-expenses.ts rename to src/features/dashboard/expenses/installment-expenses-queries.ts index 5b14b6d..0117891 100644 --- a/lib/dashboard/expenses/installment-expenses.ts +++ b/src/features/dashboard/expenses/installment-expenses-queries.ts @@ -3,10 +3,10 @@ import { lancamentos } from "@/db/schema"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX, INITIAL_BALANCE_NOTE, -} from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +} from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; export type InstallmentExpense = { id: string; diff --git a/lib/dashboard/expenses/recurring-expenses.ts b/src/features/dashboard/expenses/recurring-expenses-queries.ts similarity index 88% rename from lib/dashboard/expenses/recurring-expenses.ts rename to src/features/dashboard/expenses/recurring-expenses-queries.ts index bd11cd8..9639915 100644 --- a/lib/dashboard/expenses/recurring-expenses.ts +++ b/src/features/dashboard/expenses/recurring-expenses-queries.ts @@ -3,10 +3,10 @@ import { lancamentos } from "@/db/schema"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX, INITIAL_BALANCE_NOTE, -} from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +} from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; export type RecurringExpense = { id: string; diff --git a/lib/dashboard/expenses/top-expenses.ts b/src/features/dashboard/expenses/top-expenses-queries.ts similarity index 89% rename from lib/dashboard/expenses/top-expenses.ts rename to src/features/dashboard/expenses/top-expenses-queries.ts index 71bd899..b68828b 100644 --- a/lib/dashboard/expenses/top-expenses.ts +++ b/src/features/dashboard/expenses/top-expenses-queries.ts @@ -3,10 +3,10 @@ import { cartoes, contas, lancamentos } from "@/db/schema"; import { buildDashboardAdminPeriodFilters, excludeAutoGeneratedEntryNotes, -} from "@/lib/dashboard/lancamento-filters"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +} from "@/features/dashboard/lancamento-filters"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; export type TopExpense = { id: string; diff --git a/lib/dashboard/fetch-dashboard-data.ts b/src/features/dashboard/fetch-dashboard-data.ts similarity index 73% rename from lib/dashboard/fetch-dashboard-data.ts rename to src/features/dashboard/fetch-dashboard-data.ts index fdb71e5..ae8b2c8 100644 --- a/lib/dashboard/fetch-dashboard-data.ts +++ b/src/features/dashboard/fetch-dashboard-data.ts @@ -1,22 +1,23 @@ import { unstable_cache } from "next/cache"; -import { fetchDashboardAccounts } from "./accounts"; -import { fetchDashboardBills } from "./bills"; -import { fetchExpensesByCategory } from "./categories/expenses-by-category"; -import { fetchIncomeByCategory } from "./categories/income-by-category"; -import { fetchDashboardCardMetrics } from "./dashboard-metrics"; -import { fetchInstallmentExpenses } from "./expenses/installment-expenses"; -import { fetchRecurringExpenses } from "./expenses/recurring-expenses"; -import { fetchTopExpenses } from "./expenses/top-expenses"; -import { fetchGoalsProgressData } from "./goals-progress"; -import { fetchIncomeExpenseBalance } from "./income-expense-balance"; -import { fetchDashboardInvoices } from "./invoices"; -import { fetchDashboardNotes } from "./notes"; -import { fetchDashboardPagadores } from "./pagadores"; -import { fetchPaymentConditions } from "./payments/payment-conditions"; -import { fetchPaymentMethods } from "./payments/payment-methods"; -import { fetchPaymentStatus } from "./payments/payment-status"; -import { fetchPurchasesByCategory } from "./purchases-by-category"; -import { fetchTopEstablishments } from "./top-establishments"; +import { fetchDashboardAccounts } from "./accounts-queries"; +import { fetchDashboardBills } from "./bills-queries"; +import { fetchExpensesByCategory } from "./categories/expenses-by-category-queries"; +import { fetchIncomeByCategory } from "./categories/income-by-category-queries"; +import { fetchDashboardCardMetrics } from "./dashboard-metrics-queries"; +import { fetchInstallmentExpenses } from "./expenses/installment-expenses-queries"; +import { fetchRecurringExpenses } from "./expenses/recurring-expenses-queries"; +import { fetchTopExpenses } from "./expenses/top-expenses-queries"; +import { fetchGoalsProgressData } from "./goals-progress-queries"; +import { fetchIncomeExpenseBalance } from "./income-expense-balance-queries"; +import { fetchDashboardInvoices } from "./invoices-queries"; +import { fetchDashboardNotes } from "./notes-queries"; +import { fetchDashboardPagadores } from "./payers-queries"; +import { fetchPaymentConditions } from "./payments/payment-conditions-queries"; +import { fetchPaymentMethods } from "./payments/payment-methods-queries"; +import { fetchPaymentStatus } from "./payments/payment-status-queries"; +import { fetchPurchasesByCategory } from "./purchases-by-category-queries"; +import { fetchRecurringSeries } from "./recurring/recurring-series-queries"; +import { fetchTopEstablishments } from "./top-establishments-queries"; async function fetchDashboardDataInternal(userId: string, period: string) { const [ @@ -39,6 +40,7 @@ async function fetchDashboardDataInternal(userId: string, period: string) { purchasesByCategoryData, incomeByCategoryData, expensesByCategoryData, + recurringSeriesData, ] = await Promise.all([ fetchDashboardCardMetrics(userId, period), fetchDashboardAccounts(userId), @@ -59,6 +61,7 @@ async function fetchDashboardDataInternal(userId: string, period: string) { fetchPurchasesByCategory(userId, period), fetchIncomeByCategory(userId, period), fetchExpensesByCategory(userId, period), + fetchRecurringSeries(userId), ]); return { @@ -81,6 +84,7 @@ async function fetchDashboardDataInternal(userId: string, period: string) { purchasesByCategoryData, incomeByCategoryData, expensesByCategoryData, + recurringSeriesData, }; } diff --git a/lib/dashboard/goals-progress-helpers.ts b/src/features/dashboard/goals-progress-helpers.ts similarity index 84% rename from lib/dashboard/goals-progress-helpers.ts rename to src/features/dashboard/goals-progress-helpers.ts index 75b240f..9ced368 100644 --- a/lib/dashboard/goals-progress-helpers.ts +++ b/src/features/dashboard/goals-progress-helpers.ts @@ -1,10 +1,13 @@ -import type { Budget, BudgetCategory } from "@/components/orcamentos/types"; +import type { + Budget, + BudgetCategory, +} from "@/features/budgets/components/types"; import type { GoalProgressCategory, GoalProgressItem, GoalProgressStatus, -} from "@/lib/dashboard/goals-progress"; -import { formatPercentage } from "@/lib/utils/percentage"; +} from "@/features/dashboard/goals-progress-queries"; +import { formatPercentage } from "@/shared/utils/percentage"; export const clampGoalProgress = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value)); diff --git a/lib/dashboard/goals-progress.ts b/src/features/dashboard/goals-progress-queries.ts similarity index 95% rename from lib/dashboard/goals-progress.ts rename to src/features/dashboard/goals-progress-queries.ts index a1d5a86..d5946c1 100644 --- a/lib/dashboard/goals-progress.ts +++ b/src/features/dashboard/goals-progress-queries.ts @@ -1,8 +1,8 @@ import { and, eq, ne, sql } from "drizzle-orm"; import { categorias, lancamentos, orcamentos } from "@/db/schema"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; const BUDGET_CRITICAL_THRESHOLD = 80; diff --git a/lib/dashboard/income-expense-balance.ts b/src/features/dashboard/income-expense-balance-queries.ts similarity index 90% rename from lib/dashboard/income-expense-balance.ts rename to src/features/dashboard/income-expense-balance-queries.ts index 9c9cb66..28fc763 100644 --- a/lib/dashboard/income-expense-balance.ts +++ b/src/features/dashboard/income-expense-balance-queries.ts @@ -4,15 +4,15 @@ import { buildDashboardAdminFilters, excludeAutoInvoiceEntries, excludeInitialBalanceWhenConfigured, -} from "@/lib/dashboard/lancamento-filters"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +} from "@/features/dashboard/lancamento-filters"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; import { buildPeriodWindow, formatPeriodMonthShort, getCurrentPeriod, -} from "@/lib/utils/period"; +} from "@/shared/utils/period"; export type MonthData = { month: string; diff --git a/lib/dashboard/installment-expenses-helpers.ts b/src/features/dashboard/installment-expenses-helpers.ts similarity index 94% rename from lib/dashboard/installment-expenses-helpers.ts rename to src/features/dashboard/installment-expenses-helpers.ts index 345374a..6288b59 100644 --- a/lib/dashboard/installment-expenses-helpers.ts +++ b/src/features/dashboard/installment-expenses-helpers.ts @@ -1,8 +1,8 @@ -import type { InstallmentExpense } from "@/lib/dashboard/expenses/installment-expenses"; +import type { InstallmentExpense } from "@/features/dashboard/expenses/installment-expenses-queries"; import { calculateLastInstallmentDate, formatLastInstallmentDate, -} from "@/lib/installments/utils"; +} from "@/shared/lib/installments/utils"; export type InstallmentExpenseDisplay = { compactLabel: string | null; diff --git a/lib/dashboard/invoices-helpers.ts b/src/features/dashboard/invoices-helpers.ts similarity index 82% rename from lib/dashboard/invoices-helpers.ts rename to src/features/dashboard/invoices-helpers.ts index f3303bd..e1dc641 100644 --- a/lib/dashboard/invoices-helpers.ts +++ b/src/features/dashboard/invoices-helpers.ts @@ -1,16 +1,16 @@ -import type { DashboardInvoice } from "@/lib/dashboard/invoices"; -import type { PaymentDialogState } from "@/lib/dashboard/use-payment-dialog-controller"; +import type { DashboardInvoice } from "@/features/dashboard/invoices-queries"; +import type { PaymentDialogState } from "@/features/dashboard/use-payment-dialog-controller"; import { INVOICE_PAYMENT_STATUS, type InvoicePaymentStatus, -} from "@/lib/faturas"; -import { getBusinessDateString } from "@/lib/utils/date"; +} from "@/shared/lib/invoices"; +import { getBusinessDateString } from "@/shared/utils/date"; import { buildDueDateInfoFromPeriodDay, formatFinancialDateLabel, -} from "@/lib/utils/financial-dates"; -import { formatPercentage } from "@/lib/utils/percentage"; -import { formatPeriodForUrl } from "@/lib/utils/period"; +} from "@/shared/utils/financial-dates"; +import { formatPercentage } from "@/shared/utils/percentage"; +import { formatPeriodForUrl } from "@/shared/utils/period"; export type InvoiceDialogState = PaymentDialogState; export type InvoiceLogoTone = "muted" | "accent"; @@ -89,7 +89,7 @@ export const getInvoiceStatusBadgeVariant = ( }; export const buildInvoiceDetailsHref = (cardId: string, period: string) => - `/cartoes/${cardId}/fatura?periodo=${formatPeriodForUrl(period)}`; + `/cards/${cardId}/invoice?periodo=${formatPeriodForUrl(period)}`; export const markInvoiceAsPaid = ( invoice: DashboardInvoice, diff --git a/lib/dashboard/invoices.ts b/src/features/dashboard/invoices-queries.ts similarity index 96% rename from lib/dashboard/invoices.ts rename to src/features/dashboard/invoices-queries.ts index a8287e9..54ffd7b 100644 --- a/lib/dashboard/invoices.ts +++ b/src/features/dashboard/invoices-queries.ts @@ -1,14 +1,14 @@ import { and, eq, ilike, isNotNull, sql } from "drizzle-orm"; import { cartoes, faturas, lancamentos, pagadores } from "@/db/schema"; -import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; +import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; import { INVOICE_PAYMENT_STATUS, INVOICE_STATUS_VALUES, type InvoicePaymentStatus, -} from "@/lib/faturas"; -import { toDateOnlyString } from "@/lib/utils/date"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +} from "@/shared/lib/invoices"; +import { toDateOnlyString } from "@/shared/utils/date"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; type RawDashboardInvoice = { invoiceId: string | null; diff --git a/lib/dashboard/lancamento-filters.ts b/src/features/dashboard/lancamento-filters.ts similarity index 97% rename from lib/dashboard/lancamento-filters.ts rename to src/features/dashboard/lancamento-filters.ts index 3ba7440..f907e81 100644 --- a/lib/dashboard/lancamento-filters.ts +++ b/src/features/dashboard/lancamento-filters.ts @@ -3,7 +3,7 @@ import { contas, lancamentos } from "@/db/schema"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX, INITIAL_BALANCE_NOTE, -} from "@/lib/contas/constants"; +} from "@/shared/lib/accounts/constants"; type DashboardAdminFiltersParams = { userId: string; diff --git a/lib/dashboard/notes-mappers.ts b/src/features/dashboard/notes-mappers.ts similarity index 71% rename from lib/dashboard/notes-mappers.ts rename to src/features/dashboard/notes-mappers.ts index 9dba6fc..546e903 100644 --- a/lib/dashboard/notes-mappers.ts +++ b/src/features/dashboard/notes-mappers.ts @@ -1,5 +1,5 @@ -import type { Note } from "@/components/anotacoes/types"; -import type { DashboardNote } from "@/lib/dashboard/notes"; +import type { DashboardNote } from "@/features/dashboard/notes-queries"; +import type { Note } from "@/features/notes/components/types"; export const mapDashboardNoteToNote = (note: DashboardNote): Note => ({ id: note.id, diff --git a/lib/dashboard/notes.ts b/src/features/dashboard/notes-queries.ts similarity index 97% rename from lib/dashboard/notes.ts rename to src/features/dashboard/notes-queries.ts index fae68c2..64ff22d 100644 --- a/lib/dashboard/notes.ts +++ b/src/features/dashboard/notes-queries.ts @@ -1,6 +1,6 @@ import { and, eq } from "drizzle-orm"; import { anotacoes } from "@/db/schema"; -import { db } from "@/lib/db"; +import { db } from "@/shared/lib/db"; export type DashboardTask = { id: string; diff --git a/lib/dashboard/notifications.ts b/src/features/dashboard/notifications-queries.ts similarity index 97% rename from lib/dashboard/notifications.ts rename to src/features/dashboard/notifications-queries.ts index 8b3ec01..b3e073d 100644 --- a/lib/dashboard/notifications.ts +++ b/src/features/dashboard/notifications-queries.ts @@ -8,17 +8,17 @@ import { lancamentos, orcamentos, } from "@/db/schema"; -import { db } from "@/lib/db"; -import { INVOICE_PAYMENT_STATUS } from "@/lib/faturas"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; +import { db } from "@/shared/lib/db"; +import { INVOICE_PAYMENT_STATUS } from "@/shared/lib/invoices"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; import { buildDateOnlyStringFromPeriodDay, getBusinessDateString, isDateOnlyPast, isDateOnlyWithinDays, toDateOnlyString, -} from "@/lib/utils/date"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +} from "@/shared/utils/date"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; export type NotificationType = "overdue" | "due_soon"; diff --git a/lib/dashboard/pagadores.ts b/src/features/dashboard/payers-queries.ts similarity index 88% rename from lib/dashboard/pagadores.ts rename to src/features/dashboard/payers-queries.ts index cbd5839..d5fd084 100644 --- a/lib/dashboard/pagadores.ts +++ b/src/features/dashboard/payers-queries.ts @@ -1,11 +1,11 @@ import { and, desc, eq, inArray, isNull, or, sql } from "drizzle-orm"; import { lancamentos, pagadores } from "@/db/schema"; -import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; -import { calculatePercentageChange } from "@/lib/utils/math"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; -import { getPreviousPeriod } from "@/lib/utils/period"; +import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { calculatePercentageChange } from "@/shared/utils/math"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; +import { getPreviousPeriod } from "@/shared/utils/period"; export type DashboardPagador = { id: string; diff --git a/lib/dashboard/payment-breakdown-formatters.ts b/src/features/dashboard/payment-breakdown-formatters.ts similarity index 83% rename from lib/dashboard/payment-breakdown-formatters.ts rename to src/features/dashboard/payment-breakdown-formatters.ts index bdf372c..33ebcf9 100644 --- a/lib/dashboard/payment-breakdown-formatters.ts +++ b/src/features/dashboard/payment-breakdown-formatters.ts @@ -1,4 +1,4 @@ -import { formatPercentage } from "@/lib/utils/percentage"; +import { formatPercentage } from "@/shared/utils/percentage"; export const formatPaymentBreakdownPercentage = (value: number) => formatPercentage(value, { diff --git a/lib/dashboard/payment-overview-tabs.ts b/src/features/dashboard/payment-overview-tabs.ts similarity index 100% rename from lib/dashboard/payment-overview-tabs.ts rename to src/features/dashboard/payment-overview-tabs.ts diff --git a/lib/dashboard/payments/payment-conditions.ts b/src/features/dashboard/payments/payment-conditions-queries.ts similarity index 89% rename from lib/dashboard/payments/payment-conditions.ts rename to src/features/dashboard/payments/payment-conditions-queries.ts index 825a54e..079b19a 100644 --- a/lib/dashboard/payments/payment-conditions.ts +++ b/src/features/dashboard/payments/payment-conditions-queries.ts @@ -3,10 +3,10 @@ import { lancamentos } from "@/db/schema"; import { buildDashboardAdminPeriodFilters, excludeAutoGeneratedEntryNotes, -} from "@/lib/dashboard/lancamento-filters"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +} from "@/features/dashboard/lancamento-filters"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; export type PaymentConditionSummary = { condition: string; diff --git a/lib/dashboard/payments/payment-methods.ts b/src/features/dashboard/payments/payment-methods-queries.ts similarity index 89% rename from lib/dashboard/payments/payment-methods.ts rename to src/features/dashboard/payments/payment-methods-queries.ts index 7616568..0fd1094 100644 --- a/lib/dashboard/payments/payment-methods.ts +++ b/src/features/dashboard/payments/payment-methods-queries.ts @@ -3,10 +3,10 @@ import { lancamentos } from "@/db/schema"; import { buildDashboardAdminPeriodFilters, excludeAutoGeneratedEntryNotes, -} from "@/lib/dashboard/lancamento-filters"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +} from "@/features/dashboard/lancamento-filters"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; export type PaymentMethodSummary = { paymentMethod: string; diff --git a/lib/dashboard/payments/payment-status.ts b/src/features/dashboard/payments/payment-status-queries.ts similarity index 89% rename from lib/dashboard/payments/payment-status.ts rename to src/features/dashboard/payments/payment-status-queries.ts index 8cec7dd..f573a0d 100644 --- a/lib/dashboard/payments/payment-status.ts +++ b/src/features/dashboard/payments/payment-status-queries.ts @@ -3,10 +3,10 @@ import { lancamentos } from "@/db/schema"; import { buildDashboardAdminPeriodFilters, excludeAutoInvoiceEntries, -} from "@/lib/dashboard/lancamento-filters"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +} from "@/features/dashboard/lancamento-filters"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; export type PaymentStatusCategory = { total: number; diff --git a/app/(dashboard)/dashboard/data.ts b/src/features/dashboard/preferences-queries.ts similarity index 73% rename from app/(dashboard)/dashboard/data.ts rename to src/features/dashboard/preferences-queries.ts index 9c2f8b9..88b7d58 100644 --- a/app/(dashboard)/dashboard/data.ts +++ b/src/features/dashboard/preferences-queries.ts @@ -1,8 +1,9 @@ import { eq } from "drizzle-orm"; -import { db, schema } from "@/lib/db"; +import type { WidgetPreferences } from "@/features/dashboard/widgets/actions"; +import { db, schema } from "@/shared/lib/db"; export interface UserDashboardPreferences { - dashboardWidgets: string | null; + dashboardWidgets: WidgetPreferences | null; } export async function fetchUserDashboardPreferences( diff --git a/lib/dashboard/purchases-by-category.ts b/src/features/dashboard/purchases-by-category-queries.ts similarity index 93% rename from lib/dashboard/purchases-by-category.ts rename to src/features/dashboard/purchases-by-category-queries.ts index ffc0500..81077ac 100644 --- a/lib/dashboard/purchases-by-category.ts +++ b/src/features/dashboard/purchases-by-category-queries.ts @@ -3,10 +3,10 @@ import { cartoes, categorias, contas, lancamentos } from "@/db/schema"; import { buildDashboardAdminPeriodFilters, excludeAutoGeneratedEntryNotes, -} from "@/lib/dashboard/lancamento-filters"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +} from "@/features/dashboard/lancamento-filters"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; export type CategoryOption = { id: string; diff --git a/src/features/dashboard/recurring/recurring-series-queries.ts b/src/features/dashboard/recurring/recurring-series-queries.ts new file mode 100644 index 0000000..ee72579 --- /dev/null +++ b/src/features/dashboard/recurring/recurring-series-queries.ts @@ -0,0 +1,100 @@ +import { and, eq, inArray } from "drizzle-orm"; +import type { RecurringSeriesTemplate } from "@/db/schema"; +import { categorias, recurringSeries } from "@/db/schema"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; +import { addMonthsToPeriod } from "@/shared/utils/period"; + +export type RecurringSeriesItem = { + id: string; + name: string; + amount: number; + categoryName: string | null; + categoryIcon: string | null; + paymentMethod: string; + dayOfMonth: number; + status: "active" | "paused" | "cancelled"; + nextPeriod: string; + lastGeneratedPeriod: string; +}; + +export type RecurringSeriesData = { + series: RecurringSeriesItem[]; +}; + +export async function fetchRecurringSeries( + userId: string, +): Promise { + const adminPagadorId = await getAdminPagadorId(userId); + + const rows = await db + .select({ + id: recurringSeries.id, + status: recurringSeries.status, + dayOfMonth: recurringSeries.dayOfMonth, + lastGeneratedPeriod: recurringSeries.lastGeneratedPeriod, + templateData: recurringSeries.templateData, + }) + .from(recurringSeries) + .where( + and( + eq(recurringSeries.userId, userId), + inArray(recurringSeries.status, ["active", "paused"]), + ), + ); + + if (rows.length === 0) { + return { series: [] }; + } + + // Fetch category names for all series in one query + const categoryIds = rows + .map((r) => (r.templateData as RecurringSeriesTemplate).categoriaId) + .filter((id): id is string => id !== null); + + const categoryMap = new Map(); + if (categoryIds.length > 0) { + const cats = await db + .select({ + id: categorias.id, + name: categorias.name, + icon: categorias.icon, + }) + .from(categorias) + .where(inArray(categorias.id, categoryIds)); + for (const cat of cats) { + categoryMap.set(cat.id, { name: cat.name, icon: cat.icon }); + } + } + + const series = rows + .filter((row) => { + // If admin pagador exists, only show series belonging to admin + if (!adminPagadorId) return true; + const template = row.templateData as RecurringSeriesTemplate; + return ( + template.pagadorId === adminPagadorId || template.pagadorId === null + ); + }) + .map((row): RecurringSeriesItem => { + const template = row.templateData as RecurringSeriesTemplate; + const category = template.categoriaId + ? categoryMap.get(template.categoriaId) + : null; + return { + id: row.id, + name: template.name, + amount: Math.abs(toNumber(template.amount)), + categoryName: category?.name ?? null, + categoryIcon: category?.icon ?? null, + paymentMethod: template.paymentMethod, + dayOfMonth: row.dayOfMonth, + status: row.status as "active" | "paused", + nextPeriod: addMonthsToPeriod(row.lastGeneratedPeriod, 1), + lastGeneratedPeriod: row.lastGeneratedPeriod, + }; + }); + + return { series }; +} diff --git a/lib/dashboard/top-establishments.ts b/src/features/dashboard/top-establishments-queries.ts similarity index 90% rename from lib/dashboard/top-establishments.ts rename to src/features/dashboard/top-establishments-queries.ts index 3fd9d62..6a8c69f 100644 --- a/lib/dashboard/top-establishments.ts +++ b/src/features/dashboard/top-establishments-queries.ts @@ -3,10 +3,10 @@ import { cartoes, contas, lancamentos } from "@/db/schema"; import { buildDashboardAdminPeriodFilters, excludeAutoGeneratedEntryNotes, -} from "@/lib/dashboard/lancamento-filters"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +} from "@/features/dashboard/lancamento-filters"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; export type TopEstablishment = { id: string; diff --git a/lib/dashboard/use-bill-widget-controller.ts b/src/features/dashboard/use-bill-widget-controller.ts similarity index 78% rename from lib/dashboard/use-bill-widget-controller.ts rename to src/features/dashboard/use-bill-widget-controller.ts index 6a31463..5d53449 100644 --- a/lib/dashboard/use-bill-widget-controller.ts +++ b/src/features/dashboard/use-bill-widget-controller.ts @@ -1,16 +1,16 @@ "use client"; -import { toggleLancamentoSettlementAction } from "@/app/(dashboard)/lancamentos/actions"; -import type { DashboardBill } from "@/lib/dashboard/bills"; import { type BillDialogState, getCurrentBillDateString, markBillAsSettled, -} from "@/lib/dashboard/bills-helpers"; +} from "@/features/dashboard/bills-helpers"; +import type { DashboardBill } from "@/features/dashboard/bills-queries"; import { type PaymentDialogController, usePaymentDialogController, -} from "@/lib/dashboard/use-payment-dialog-controller"; +} from "@/features/dashboard/use-payment-dialog-controller"; +import { toggleLancamentoSettlementAction } from "@/features/transactions/actions"; const EMPTY_BILLS: DashboardBill[] = []; diff --git a/lib/dashboard/use-goals-progress-widget-controller.ts b/src/features/dashboard/use-goals-progress-widget-controller.ts similarity index 86% rename from lib/dashboard/use-goals-progress-widget-controller.ts rename to src/features/dashboard/use-goals-progress-widget-controller.ts index 7f3f50d..63f68be 100644 --- a/lib/dashboard/use-goals-progress-widget-controller.ts +++ b/src/features/dashboard/use-goals-progress-widget-controller.ts @@ -1,15 +1,18 @@ "use client"; import { useMemo, useState } from "react"; -import type { Budget, BudgetCategory } from "@/components/orcamentos/types"; import type { - GoalProgressItem, - GoalsProgressData, -} from "@/lib/dashboard/goals-progress"; + Budget, + BudgetCategory, +} from "@/features/budgets/components/types"; import { mapGoalProgressCategoriesToBudgetCategories, mapGoalProgressItemToBudget, -} from "@/lib/dashboard/goals-progress-helpers"; +} from "@/features/dashboard/goals-progress-helpers"; +import type { + GoalProgressItem, + GoalsProgressData, +} from "@/features/dashboard/goals-progress-queries"; export type GoalsProgressWidgetController = { selectedBudget: Budget | null; diff --git a/lib/dashboard/use-invoices-widget-controller.ts b/src/features/dashboard/use-invoices-widget-controller.ts similarity index 75% rename from lib/dashboard/use-invoices-widget-controller.ts rename to src/features/dashboard/use-invoices-widget-controller.ts index 7d5c74c..2003568 100644 --- a/lib/dashboard/use-invoices-widget-controller.ts +++ b/src/features/dashboard/use-invoices-widget-controller.ts @@ -1,18 +1,18 @@ "use client"; -import { updateInvoicePaymentStatusAction } from "@/app/(dashboard)/cartoes/[cartaoId]/fatura/actions"; -import type { DashboardInvoice } from "@/lib/dashboard/invoices"; import { getCurrentDateString, type InvoiceDialogState, isInvoicePaid, markInvoiceAsPaid, -} from "@/lib/dashboard/invoices-helpers"; +} from "@/features/dashboard/invoices-helpers"; +import type { DashboardInvoice } from "@/features/dashboard/invoices-queries"; import { type PaymentDialogController, usePaymentDialogController, -} from "@/lib/dashboard/use-payment-dialog-controller"; -import { INVOICE_PAYMENT_STATUS } from "@/lib/faturas"; +} from "@/features/dashboard/use-payment-dialog-controller"; +import { updateInvoicePaymentStatusAction } from "@/features/invoices/actions"; +import { INVOICE_PAYMENT_STATUS } from "@/shared/lib/invoices"; export type InvoicesWidgetController = Omit< PaymentDialogController, diff --git a/lib/dashboard/use-notes-widget-controller.ts b/src/features/dashboard/use-notes-widget-controller.ts similarity index 86% rename from lib/dashboard/use-notes-widget-controller.ts rename to src/features/dashboard/use-notes-widget-controller.ts index 29f4ebc..b89d023 100644 --- a/lib/dashboard/use-notes-widget-controller.ts +++ b/src/features/dashboard/use-notes-widget-controller.ts @@ -1,9 +1,9 @@ "use client"; import { useMemo, useState } from "react"; -import type { Note } from "@/components/anotacoes/types"; -import type { DashboardNote } from "@/lib/dashboard/notes"; -import { mapDashboardNotesToNotes } from "@/lib/dashboard/notes-mappers"; +import { mapDashboardNotesToNotes } from "@/features/dashboard/notes-mappers"; +import type { DashboardNote } from "@/features/dashboard/notes-queries"; +import type { Note } from "@/features/notes/components/types"; export type NotesWidgetController = { mappedNotes: Note[]; diff --git a/lib/dashboard/use-payment-dialog-controller.ts b/src/features/dashboard/use-payment-dialog-controller.ts similarity index 97% rename from lib/dashboard/use-payment-dialog-controller.ts rename to src/features/dashboard/use-payment-dialog-controller.ts index 1980861..adbda8c 100644 --- a/lib/dashboard/use-payment-dialog-controller.ts +++ b/src/features/dashboard/use-payment-dialog-controller.ts @@ -3,7 +3,7 @@ import { useRouter } from "next/navigation"; import { useEffect, useMemo, useState, useTransition } from "react"; import { toast } from "sonner"; -import type { ActionResult } from "@/lib/types/actions"; +import type { ActionResult } from "@/shared/lib/types/actions"; export type PaymentDialogState = "idle" | "processing" | "success"; diff --git a/lib/dashboard/use-payment-overview-widget-controller.ts b/src/features/dashboard/use-payment-overview-widget-controller.ts similarity index 91% rename from lib/dashboard/use-payment-overview-widget-controller.ts rename to src/features/dashboard/use-payment-overview-widget-controller.ts index 2596a31..583559f 100644 --- a/lib/dashboard/use-payment-overview-widget-controller.ts +++ b/src/features/dashboard/use-payment-overview-widget-controller.ts @@ -5,7 +5,7 @@ import { DEFAULT_PAYMENT_OVERVIEW_TAB, type PaymentOverviewTab, parsePaymentOverviewTab, -} from "@/lib/dashboard/payment-overview-tabs"; +} from "@/features/dashboard/payment-overview-tabs"; export type PaymentOverviewWidgetController = { activeTab: PaymentOverviewTab; diff --git a/lib/dashboard/widgets/actions.ts b/src/features/dashboard/widgets/actions.ts similarity index 94% rename from lib/dashboard/widgets/actions.ts rename to src/features/dashboard/widgets/actions.ts index 7fd0f18..a316242 100644 --- a/lib/dashboard/widgets/actions.ts +++ b/src/features/dashboard/widgets/actions.ts @@ -2,8 +2,8 @@ import { eq } from "drizzle-orm"; import { revalidatePath } from "next/cache"; -import { getUser } from "@/lib/auth/server"; -import { db, schema } from "@/lib/db"; +import { getUser } from "@/shared/lib/auth/server"; +import { db, schema } from "@/shared/lib/db"; export type WidgetPreferences = { order: string[]; diff --git a/lib/dashboard/widgets/widgets-config.tsx b/src/features/dashboard/widgets/widgets-config.tsx similarity index 74% rename from lib/dashboard/widgets/widgets-config.tsx rename to src/features/dashboard/widgets/widgets-config.tsx index 08aa4f2..8eb78a9 100644 --- a/lib/dashboard/widgets/widgets-config.tsx +++ b/src/features/dashboard/widgets/widgets-config.tsx @@ -16,21 +16,22 @@ import { } from "@remixicon/react"; import Link from "next/link"; import type { ReactNode } from "react"; -import { BillWidget } from "@/components/dashboard/bill-widget"; -import { ExpensesByCategoryWidgetWithChart } from "@/components/dashboard/expenses-by-category-widget-with-chart"; -import { GoalsProgressWidget } from "@/components/dashboard/goals-progress-widget"; -import { IncomeByCategoryWidgetWithChart } from "@/components/dashboard/income-by-category-widget-with-chart"; -import { IncomeExpenseBalanceWidget } from "@/components/dashboard/income-expense-balance-widget"; -import { InstallmentExpensesWidget } from "@/components/dashboard/installment-expenses-widget"; -import { InvoicesWidget } from "@/components/dashboard/invoices-widget"; -import { MyAccountsWidget } from "@/components/dashboard/my-accounts-widget"; -import { NotesWidget } from "@/components/dashboard/notes-widget"; -import { PayersWidget } from "@/components/dashboard/payers-widget"; -import { PaymentOverviewWidget } from "@/components/dashboard/payment-overview-widget"; -import { PaymentStatusWidget } from "@/components/dashboard/payment-status-widget"; -import { PurchasesByCategoryWidget } from "@/components/dashboard/purchases-by-category-widget"; -import { RecurringExpensesWidget } from "@/components/dashboard/recurring-expenses-widget"; -import { SpendingOverviewWidget } from "@/components/dashboard/spending-overview-widget"; +import { BillWidget } from "@/features/dashboard/components/bill-widget"; +import { ExpensesByCategoryWidgetWithChart } from "@/features/dashboard/components/expenses-by-category-widget-with-chart"; +import { GoalsProgressWidget } from "@/features/dashboard/components/goals-progress-widget"; +import { IncomeByCategoryWidgetWithChart } from "@/features/dashboard/components/income-by-category-widget-with-chart"; +import { IncomeExpenseBalanceWidget } from "@/features/dashboard/components/income-expense-balance-widget"; +import { InstallmentExpensesWidget } from "@/features/dashboard/components/installment-expenses-widget"; +import { InvoicesWidget } from "@/features/dashboard/components/invoices-widget"; +import { MyAccountsWidget } from "@/features/dashboard/components/my-accounts-widget"; +import { NotesWidget } from "@/features/dashboard/components/notes-widget"; +import { PayersWidget } from "@/features/dashboard/components/payers-widget"; +import { PaymentOverviewWidget } from "@/features/dashboard/components/payment-overview-widget"; +import { PaymentStatusWidget } from "@/features/dashboard/components/payment-status-widget"; +import { PurchasesByCategoryWidget } from "@/features/dashboard/components/purchases-by-category-widget"; +import { RecurringExpensesWidget } from "@/features/dashboard/components/recurring-expenses-widget"; +import { RecurringSeriesWidget } from "@/features/dashboard/components/recurring-series-widget"; +import { SpendingOverviewWidget } from "@/features/dashboard/components/spending-overview-widget"; import type { DashboardData } from "../fetch-dashboard-data"; export type WidgetConfig = { @@ -100,7 +101,7 @@ export const widgetsConfig: WidgetConfig[] = [ ), action: ( Ver todos @@ -116,7 +117,7 @@ export const widgetsConfig: WidgetConfig[] = [ component: ({ data }) => , action: ( Ver todas @@ -134,7 +135,7 @@ export const widgetsConfig: WidgetConfig[] = [ ), action: ( Ver todos @@ -163,6 +164,15 @@ export const widgetsConfig: WidgetConfig[] = [ ), }, + { + id: "recurring-series", + title: "Séries Recorrentes", + subtitle: "Gerencie seus lançamentos recorrentes", + icon: , + component: ({ data }) => ( + + ), + }, { id: "installment-expenses", title: "Lançamentos Parcelados", diff --git a/app/(dashboard)/pre-lancamentos/actions.ts b/src/features/inbox/actions.ts similarity index 96% rename from app/(dashboard)/pre-lancamentos/actions.ts rename to src/features/inbox/actions.ts index ac08f42..8b55778 100644 --- a/app/(dashboard)/pre-lancamentos/actions.ts +++ b/src/features/inbox/actions.ts @@ -3,10 +3,13 @@ import { and, eq, inArray } from "drizzle-orm"; import { z } from "zod"; import { preLancamentos } from "@/db/schema"; -import { handleActionError, revalidateForEntity } from "@/lib/actions/helpers"; -import type { ActionResult } from "@/lib/types/actions"; -import { getUser } from "@/lib/auth/server"; -import { db } from "@/lib/db"; +import { + handleActionError, + revalidateForEntity, +} from "@/shared/lib/actions/helpers"; +import { getUser } from "@/shared/lib/auth/server"; +import { db } from "@/shared/lib/db"; +import type { ActionResult } from "@/shared/lib/types/actions"; const markProcessedSchema = z.object({ inboxItemId: z.string().uuid("ID do item inválido"), diff --git a/components/pre-lancamentos/inbox-card.tsx b/src/features/inbox/components/inbox-card.tsx similarity index 95% rename from components/pre-lancamentos/inbox-card.tsx rename to src/features/inbox/components/inbox-card.tsx index d7d2d83..bdd8a3e 100644 --- a/components/pre-lancamentos/inbox-card.tsx +++ b/src/features/inbox/components/inbox-card.tsx @@ -10,9 +10,9 @@ import { import { format, formatDistanceToNow } from "date-fns"; import { ptBR } from "date-fns/locale"; import Image from "next/image"; -import MoneyValues from "@/components/shared/money-values"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +import MoneyValues from "@/shared/components/money-values"; +import { Badge } from "@/shared/components/ui/badge"; +import { Button } from "@/shared/components/ui/button"; import { Card, CardAction, @@ -20,14 +20,14 @@ import { CardFooter, CardHeader, CardTitle, -} from "@/components/ui/card"; +} from "@/shared/components/ui/card"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { resolveLogoSrc } from "@/lib/logo"; +} from "@/shared/components/ui/dropdown-menu"; +import { resolveLogoSrc } from "@/shared/lib/logo"; import type { InboxItem } from "./types"; interface InboxCardProps { diff --git a/components/pre-lancamentos/inbox-details-dialog.tsx b/src/features/inbox/components/inbox-details-dialog.tsx similarity index 91% rename from components/pre-lancamentos/inbox-details-dialog.tsx rename to src/features/inbox/components/inbox-details-dialog.tsx index 3ff7bdb..2e2fb12 100644 --- a/components/pre-lancamentos/inbox-details-dialog.tsx +++ b/src/features/inbox/components/inbox-details-dialog.tsx @@ -2,9 +2,9 @@ import { format } from "date-fns"; import { ptBR } from "date-fns/locale"; -import MoneyValues from "@/components/shared/money-values"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +import MoneyValues from "@/shared/components/money-values"; +import { Badge } from "@/shared/components/ui/badge"; +import { Button } from "@/shared/components/ui/button"; import { Dialog, DialogClose, @@ -12,8 +12,8 @@ import { DialogFooter, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import { Separator } from "@/components/ui/separator"; +} from "@/shared/components/ui/dialog"; +import { Separator } from "@/shared/components/ui/separator"; import type { InboxItem } from "./types"; interface InboxDetailsDialogProps { diff --git a/components/pre-lancamentos/inbox-page.tsx b/src/features/inbox/components/inbox-page.tsx similarity index 96% rename from components/pre-lancamentos/inbox-page.tsx rename to src/features/inbox/components/inbox-page.tsx index 4d1183b..2f42587 100644 --- a/components/pre-lancamentos/inbox-page.tsx +++ b/src/features/inbox/components/inbox-page.tsx @@ -9,13 +9,18 @@ import { discardInboxItemAction, markInboxAsProcessedAction, restoreDiscardedInboxItemAction, -} from "@/app/(dashboard)/pre-lancamentos/actions"; -import { LancamentoDialog } from "@/components/lancamentos/dialogs/lancamento-dialog/lancamento-dialog"; -import { ConfirmActionDialog } from "@/components/shared/confirm-action-dialog"; -import { EmptyState } from "@/components/shared/empty-state"; -import { Button } from "@/components/ui/button"; -import { Card } from "@/components/ui/card"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +} from "@/features/inbox/actions"; +import { LancamentoDialog } from "@/features/transactions/components/dialogs/transaction-dialog/transaction-dialog"; +import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog"; +import { EmptyState } from "@/shared/components/empty-state"; +import { Button } from "@/shared/components/ui/button"; +import { Card } from "@/shared/components/ui/card"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/shared/components/ui/tabs"; import { InboxCard } from "./inbox-card"; import { InboxDetailsDialog } from "./inbox-details-dialog"; import type { InboxItem, SelectOption } from "./types"; diff --git a/components/pre-lancamentos/types.ts b/src/features/inbox/components/types.ts similarity index 82% rename from components/pre-lancamentos/types.ts rename to src/features/inbox/components/types.ts index ebf25f3..7bdbb5b 100644 --- a/components/pre-lancamentos/types.ts +++ b/src/features/inbox/components/types.ts @@ -1,4 +1,4 @@ -import type { SelectOption as LancamentoSelectOption } from "@/components/lancamentos/types"; +import type { SelectOption as LancamentoSelectOption } from "@/features/transactions/components/types"; export interface InboxItem { id: string; diff --git a/app/(dashboard)/pre-lancamentos/data.ts b/src/features/inbox/queries.ts similarity index 76% rename from app/(dashboard)/pre-lancamentos/data.ts rename to src/features/inbox/queries.ts index 1cbb206..7a10fc7 100644 --- a/app/(dashboard)/pre-lancamentos/data.ts +++ b/src/features/inbox/queries.ts @@ -1,21 +1,18 @@ -import { and, desc, eq, gte } from "drizzle-orm"; +import { and, desc, eq } from "drizzle-orm"; +import { cartoes, categorias, contas, preLancamentos } from "@/db/schema"; import type { InboxItem, SelectOption, -} from "@/components/pre-lancamentos/types"; -import { - cartoes, - categorias, - contas, - lancamentos, - preLancamentos, -} from "@/db/schema"; -import { db } from "@/lib/db"; +} from "@/features/inbox/components/types"; import { buildOptionSets, buildSluggedFilters, +} from "@/features/transactions/page-helpers"; +import { fetchLancamentoFilterSources, -} from "@/lib/lancamentos/page-helpers"; + fetchRecentEstablishments, +} from "@/features/transactions/queries"; +import { db } from "@/shared/lib/db"; export async function fetchInboxItems( userId: string, @@ -154,34 +151,7 @@ export async function fetchInboxDialogData(userId: string): Promise<{ pagadorRows: filterSources.pagadorRows, }); - // Fetch recent establishments (same approach as getRecentEstablishmentsAction) - const threeMonthsAgo = new Date(); - threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3); - - const recentEstablishments = await db - .select({ name: lancamentos.name }) - .from(lancamentos) - .where( - and( - eq(lancamentos.userId, userId), - gte(lancamentos.purchaseDate, threeMonthsAgo), - ), - ) - .orderBy(desc(lancamentos.purchaseDate)); - - // Remove duplicates and filter empty names - const filteredNames: string[] = recentEstablishments - .map((r: { name: string }) => r.name) - .filter( - (name: string | null): name is string => - name != null && - name.trim().length > 0 && - !name.toLowerCase().startsWith("pagamento fatura"), - ); - const estabelecimentos = Array.from(new Set(filteredNames)).slice( - 0, - 100, - ); + const estabelecimentos = await fetchRecentEstablishments(userId); return { pagadorOptions, diff --git a/app/(dashboard)/insights/actions.ts b/src/features/insights/actions.ts similarity index 98% rename from app/(dashboard)/insights/actions.ts rename to src/features/insights/actions.ts index 73d138d..8b48a87 100644 --- a/app/(dashboard)/insights/actions.ts +++ b/src/features/insights/actions.ts @@ -16,16 +16,16 @@ import { orcamentos, pagadores, } from "@/db/schema"; -import { getUser } from "@/lib/auth/server"; -import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; +import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants"; +import { getUser } from "@/shared/lib/auth/server"; +import { db } from "@/shared/lib/db"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; import { type InsightsResponse, InsightsResponseSchema, -} from "@/lib/schemas/insights"; -import { getPreviousPeriod } from "@/lib/utils/period"; -import { AVAILABLE_MODELS, INSIGHTS_SYSTEM_PROMPT } from "./data"; +} from "@/shared/lib/schemas/insights"; +import { getPreviousPeriod } from "@/shared/utils/period"; +import { AVAILABLE_MODELS, INSIGHTS_SYSTEM_PROMPT } from "./constants"; const TRANSFERENCIA = "Transferência"; diff --git a/components/insights/insights-grid.tsx b/src/features/insights/components/insights-grid.tsx similarity index 90% rename from components/insights/insights-grid.tsx rename to src/features/insights/components/insights-grid.tsx index b67ec06..caa415e 100644 --- a/components/insights/insights-grid.tsx +++ b/src/features/insights/components/insights-grid.tsx @@ -6,14 +6,19 @@ import { RiLightbulbLine, RiRocketLine, } from "@remixicon/react"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; import type { InsightCategoryId, InsightsResponse, -} from "@/lib/schemas/insights"; -import { INSIGHT_CATEGORIES } from "@/lib/schemas/insights"; -import { displayPeriod } from "@/lib/utils/period"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/lib/schemas/insights"; +import { INSIGHT_CATEGORIES } from "@/shared/lib/schemas/insights"; +import { displayPeriod } from "@/shared/utils/period"; +import { cn } from "@/shared/utils/ui"; interface InsightsGridProps { insights: InsightsResponse; diff --git a/components/insights/insights-page.tsx b/src/features/insights/components/insights-page.tsx similarity index 93% rename from components/insights/insights-page.tsx rename to src/features/insights/components/insights-page.tsx index 8e3d5ca..a9df324 100644 --- a/components/insights/insights-page.tsx +++ b/src/features/insights/components/insights-page.tsx @@ -15,14 +15,14 @@ import { generateInsightsAction, loadSavedInsightsAction, saveInsightsAction, -} from "@/app/(dashboard)/insights/actions"; -import { DEFAULT_MODEL } from "@/app/(dashboard)/insights/data"; -import { EmptyState } from "@/components/shared/empty-state"; -import { Alert, AlertDescription } from "@/components/ui/alert"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; -import type { InsightsResponse } from "@/lib/schemas/insights"; +} from "@/features/insights/actions"; +import { DEFAULT_MODEL } from "@/features/insights/constants"; +import { EmptyState } from "@/shared/components/empty-state"; +import { Alert, AlertDescription } from "@/shared/components/ui/alert"; +import { Button } from "@/shared/components/ui/button"; +import { Card, CardContent, CardHeader } from "@/shared/components/ui/card"; +import { Skeleton } from "@/shared/components/ui/skeleton"; +import type { InsightsResponse } from "@/shared/lib/schemas/insights"; import { InsightsGrid } from "./insights-grid"; import { ModelSelector } from "./model-selector"; diff --git a/components/insights/model-selector.tsx b/src/features/insights/components/model-selector.tsx similarity index 95% rename from components/insights/model-selector.tsx rename to src/features/insights/components/model-selector.tsx index 5f8df8c..dcff8df 100644 --- a/components/insights/model-selector.tsx +++ b/src/features/insights/components/model-selector.tsx @@ -8,18 +8,18 @@ import { AVAILABLE_MODELS, DEFAULT_PROVIDER, PROVIDERS, -} from "@/app/(dashboard)/insights/data"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +} from "@/features/insights/constants"; +import { Card } from "@/shared/components/ui/card"; +import { Input } from "@/shared/components/ui/input"; +import { Label } from "@/shared/components/ui/label"; +import { RadioGroup, RadioGroupItem } from "@/shared/components/ui/radio-group"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { Card } from "../ui/card"; +} from "@/shared/components/ui/select"; interface ModelSelectorProps { value: string; diff --git a/app/(dashboard)/insights/data.ts b/src/features/insights/constants.ts similarity index 100% rename from app/(dashboard)/insights/data.ts rename to src/features/insights/constants.ts diff --git a/app/(dashboard)/cartoes/[cartaoId]/fatura/actions.ts b/src/features/invoices/actions.ts similarity index 94% rename from app/(dashboard)/cartoes/[cartaoId]/fatura/actions.ts rename to src/features/invoices/actions.ts index 73e85e6..89bd271 100644 --- a/app/(dashboard)/cartoes/[cartaoId]/fatura/actions.ts +++ b/src/features/invoices/actions.ts @@ -9,18 +9,21 @@ import { lancamentos, pagadores, } from "@/db/schema"; -import { revalidateForEntity } from "@/lib/actions/helpers"; -import { getUser } from "@/lib/auth/server"; -import { buildInvoicePaymentNote } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; +import { buildInvoicePaymentNote } from "@/shared/lib/accounts/constants"; +import { revalidateForEntity } from "@/shared/lib/actions/helpers"; +import { getUser } from "@/shared/lib/auth/server"; +import { db } from "@/shared/lib/db"; import { INVOICE_PAYMENT_STATUS, INVOICE_STATUS_VALUES, type InvoicePaymentStatus, PERIOD_FORMAT_REGEX, -} from "@/lib/faturas"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; -import { getBusinessTodayDate, parseLocalDateString } from "@/lib/utils/date"; +} from "@/shared/lib/invoices"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { + getBusinessTodayDate, + parseLocalDateString, +} from "@/shared/utils/date"; const isValidPaymentDate = (value: string) => !Number.isNaN(parseLocalDateString(value).getTime()); diff --git a/components/faturas/edit-payment-date-dialog.tsx b/src/features/invoices/components/edit-payment-date-dialog.tsx similarity index 88% rename from components/faturas/edit-payment-date-dialog.tsx rename to src/features/invoices/components/edit-payment-date-dialog.tsx index f7e8870..ec50605 100644 --- a/components/faturas/edit-payment-date-dialog.tsx +++ b/src/features/invoices/components/edit-payment-date-dialog.tsx @@ -1,8 +1,8 @@ "use client"; import { useState } from "react"; -import { Button } from "@/components/ui/button"; -import { DatePicker } from "@/components/ui/date-picker"; +import { Button } from "@/shared/components/ui/button"; +import { DatePicker } from "@/shared/components/ui/date-picker"; import { Dialog, DialogContent, @@ -11,8 +11,8 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; -import { Label } from "@/components/ui/label"; +} from "@/shared/components/ui/dialog"; +import { Label } from "@/shared/components/ui/label"; type EditPaymentDateDialogProps = { trigger: React.ReactNode; diff --git a/components/faturas/invoice-summary-card.tsx b/src/features/invoices/components/invoice-summary-card.tsx similarity index 92% rename from components/faturas/invoice-summary-card.tsx rename to src/features/invoices/components/invoice-summary-card.tsx index 184ec55..a8501db 100644 --- a/components/faturas/invoice-summary-card.tsx +++ b/src/features/invoices/components/invoice-summary-card.tsx @@ -8,23 +8,28 @@ import { toast } from "sonner"; import { updateInvoicePaymentStatusAction, updatePaymentDateAction, -} from "@/app/(dashboard)/cartoes/[cartaoId]/fatura/actions"; -import MoneyValues from "@/components/shared/money-values"; -import StatusDot from "@/components/shared/status-dot"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { resolveCardBrandAsset } from "@/lib/cartoes/brand-assets"; +} from "@/features/invoices/actions"; +import MoneyValues from "@/shared/components/money-values"; +import StatusDot from "@/shared/components/status-dot"; +import { Badge } from "@/shared/components/ui/badge"; +import { Button } from "@/shared/components/ui/button"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; +import { resolveCardBrandAsset } from "@/shared/lib/cards/brand-assets"; import { INVOICE_PAYMENT_STATUS, INVOICE_STATUS_BADGE_VARIANT, INVOICE_STATUS_DESCRIPTION, INVOICE_STATUS_LABEL, type InvoicePaymentStatus, -} from "@/lib/faturas"; -import { resolveLogoSrc } from "@/lib/logo"; -import { formatCurrency } from "@/lib/utils/currency"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/lib/invoices"; +import { resolveLogoSrc } from "@/shared/lib/logo"; +import { formatCurrency } from "@/shared/utils/currency"; +import { cn } from "@/shared/utils/ui"; import { EditPaymentDateDialog } from "./edit-payment-date-dialog"; type InvoiceSummaryCardProps = { diff --git a/app/(dashboard)/cartoes/[cartaoId]/fatura/data.ts b/src/features/invoices/queries.ts similarity index 95% rename from app/(dashboard)/cartoes/[cartaoId]/fatura/data.ts rename to src/features/invoices/queries.ts index 6162543..05d0674 100644 --- a/app/(dashboard)/cartoes/[cartaoId]/fatura/data.ts +++ b/src/features/invoices/queries.ts @@ -1,11 +1,11 @@ import { and, desc, eq, type SQL, sum } from "drizzle-orm"; import { cartoes, faturas, lancamentos } from "@/db/schema"; -import { buildInvoicePaymentNote } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; +import { buildInvoicePaymentNote } from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; import { INVOICE_PAYMENT_STATUS, type InvoicePaymentStatus, -} from "@/lib/faturas"; +} from "@/shared/lib/invoices"; const toNumber = (value: string | number | null | undefined) => { if (typeof value === "number") { diff --git a/components/landing/animate-on-scroll.tsx b/src/features/landing/components/animate-on-scroll.tsx similarity index 100% rename from components/landing/animate-on-scroll.tsx rename to src/features/landing/components/animate-on-scroll.tsx diff --git a/components/landing/mobile-nav.tsx b/src/features/landing/components/mobile-nav.tsx similarity index 94% rename from components/landing/mobile-nav.tsx rename to src/features/landing/components/mobile-nav.tsx index b90c25d..4afa55c 100644 --- a/components/landing/mobile-nav.tsx +++ b/src/features/landing/components/mobile-nav.tsx @@ -3,14 +3,14 @@ import { RiArrowRightSLine, RiMenuLine } from "@remixicon/react"; import Link from "next/link"; import { useState } from "react"; -import { Logo } from "@/components/shared/logo"; -import { Button } from "@/components/ui/button"; +import { Logo } from "@/shared/components/logo"; +import { Button } from "@/shared/components/ui/button"; import { Sheet, SheetContent, SheetHeader, SheetTitle, -} from "@/components/ui/sheet"; +} from "@/shared/components/ui/sheet"; const navLinks = [ { href: "#telas", label: "Conheça as telas" }, diff --git a/components/landing/setup-tabs.tsx b/src/features/landing/components/setup-tabs.tsx similarity index 95% rename from components/landing/setup-tabs.tsx rename to src/features/landing/components/setup-tabs.tsx index 7766fa9..7a3be04 100644 --- a/components/landing/setup-tabs.tsx +++ b/src/features/landing/components/setup-tabs.tsx @@ -1,7 +1,12 @@ "use client"; -import { Card, CardContent } from "@/components/ui/card"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Card, CardContent } from "@/shared/components/ui/card"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/shared/components/ui/tabs"; export function SetupTabs() { return ( diff --git a/app/(dashboard)/anotacoes/actions.ts b/src/features/notes/actions.ts similarity index 93% rename from app/(dashboard)/anotacoes/actions.ts rename to src/features/notes/actions.ts index 69e68ac..d62ee92 100644 --- a/app/(dashboard)/anotacoes/actions.ts +++ b/src/features/notes/actions.ts @@ -3,11 +3,14 @@ import { and, eq } from "drizzle-orm"; import { z } from "zod"; import { anotacoes } from "@/db/schema"; -import { handleActionError, revalidateForEntity } from "@/lib/actions/helpers"; -import type { ActionResult } from "@/lib/types/actions"; -import { getUser } from "@/lib/auth/server"; -import { db } from "@/lib/db"; -import { uuidSchema } from "@/lib/schemas/common"; +import { + handleActionError, + revalidateForEntity, +} from "@/shared/lib/actions/helpers"; +import { getUser } from "@/shared/lib/auth/server"; +import { db } from "@/shared/lib/db"; +import { uuidSchema } from "@/shared/lib/schemas/common"; +import type { ActionResult } from "@/shared/lib/types/actions"; const taskSchema = z.object({ id: z.string(), diff --git a/components/anotacoes/note-card.tsx b/src/features/notes/components/note-card.tsx similarity index 95% rename from components/anotacoes/note-card.tsx rename to src/features/notes/components/note-card.tsx index cde103b..5ba8ae8 100644 --- a/components/anotacoes/note-card.tsx +++ b/src/features/notes/components/note-card.tsx @@ -8,9 +8,9 @@ import { RiInboxUnarchiveLine, RiPencilLine, } from "@remixicon/react"; -import { Badge } from "@/components/ui/badge"; -import { Card, CardContent, CardFooter } from "@/components/ui/card"; -import { buildNoteDisplayTitle } from "@/lib/notes/formatters"; +import { buildNoteDisplayTitle } from "@/features/notes/lib/formatters"; +import { Badge } from "@/shared/components/ui/badge"; +import { Card, CardContent, CardFooter } from "@/shared/components/ui/card"; import { type Note, sortTasksByStatus } from "./types"; interface NoteCardProps { diff --git a/components/anotacoes/note-details-dialog.tsx b/src/features/notes/components/note-details-dialog.tsx similarity index 91% rename from components/anotacoes/note-details-dialog.tsx rename to src/features/notes/components/note-details-dialog.tsx index 82b8f6d..58510ac 100644 --- a/components/anotacoes/note-details-dialog.tsx +++ b/src/features/notes/components/note-details-dialog.tsx @@ -1,8 +1,13 @@ "use client"; import { RiCheckLine } from "@remixicon/react"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +import { + buildNoteDisplayTitle, + formatNoteCreatedAtLong, +} from "@/features/notes/lib/formatters"; +import { Badge } from "@/shared/components/ui/badge"; +import { Button } from "@/shared/components/ui/button"; +import { Card } from "@/shared/components/ui/card"; import { Dialog, DialogClose, @@ -11,12 +16,7 @@ import { DialogFooter, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import { - buildNoteDisplayTitle, - formatNoteCreatedAtLong, -} from "@/lib/notes/formatters"; -import { Card } from "../ui/card"; +} from "@/shared/components/ui/dialog"; import { type Note, sortTasksByStatus } from "./types"; interface NoteDetailsDialogProps { diff --git a/components/anotacoes/note-dialog.tsx b/src/features/notes/components/note-dialog.tsx similarity index 94% rename from components/anotacoes/note-dialog.tsx rename to src/features/notes/components/note-dialog.tsx index d583229..7a23000 100644 --- a/components/anotacoes/note-dialog.tsx +++ b/src/features/notes/components/note-dialog.tsx @@ -10,12 +10,9 @@ import { useTransition, } from "react"; import { toast } from "sonner"; -import { - createNoteAction, - updateNoteAction, -} from "@/app/(dashboard)/anotacoes/actions"; -import { Button } from "@/components/ui/button"; -import { Checkbox } from "@/components/ui/checkbox"; +import { createNoteAction, updateNoteAction } from "@/features/notes/actions"; +import { Button } from "@/shared/components/ui/button"; +import { Checkbox } from "@/shared/components/ui/checkbox"; import { Dialog, DialogContent, @@ -24,13 +21,13 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; -import { Textarea } from "@/components/ui/textarea"; -import { useControlledState } from "@/lib/hooks/use-controlled-state"; -import { useFormState } from "@/lib/hooks/use-form-state"; +} from "@/shared/components/ui/dialog"; +import { Input } from "@/shared/components/ui/input"; +import { Label } from "@/shared/components/ui/label"; +import { RadioGroup, RadioGroupItem } from "@/shared/components/ui/radio-group"; +import { Textarea } from "@/shared/components/ui/textarea"; +import { useControlledState } from "@/shared/hooks/use-controlled-state"; +import { useFormState } from "@/shared/hooks/use-form-state"; import { type Note, type NoteFormValues, diff --git a/components/anotacoes/notes-page.tsx b/src/features/notes/components/notes-page.tsx similarity index 94% rename from components/anotacoes/notes-page.tsx rename to src/features/notes/components/notes-page.tsx index d4b610e..89a6cfb 100644 --- a/components/anotacoes/notes-page.tsx +++ b/src/features/notes/components/notes-page.tsx @@ -6,12 +6,17 @@ import { toast } from "sonner"; import { arquivarAnotacaoAction, deleteNoteAction, -} from "@/app/(dashboard)/anotacoes/actions"; -import { ConfirmActionDialog } from "@/components/shared/confirm-action-dialog"; -import { EmptyState } from "@/components/shared/empty-state"; -import { Button } from "@/components/ui/button"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { Card } from "../ui/card"; +} from "@/features/notes/actions"; +import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog"; +import { EmptyState } from "@/shared/components/empty-state"; +import { Button } from "@/shared/components/ui/button"; +import { Card } from "@/shared/components/ui/card"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/shared/components/ui/tabs"; import { NoteCard } from "./note-card"; import { NoteDetailsDialog } from "./note-details-dialog"; import { NoteDialog } from "./note-dialog"; diff --git a/components/anotacoes/types.ts b/src/features/notes/components/types.ts similarity index 100% rename from components/anotacoes/types.ts rename to src/features/notes/components/types.ts diff --git a/lib/notes/formatters.ts b/src/features/notes/lib/formatters.ts similarity index 100% rename from lib/notes/formatters.ts rename to src/features/notes/lib/formatters.ts diff --git a/app/(dashboard)/anotacoes/data.ts b/src/features/notes/queries.ts similarity index 98% rename from app/(dashboard)/anotacoes/data.ts rename to src/features/notes/queries.ts index 4697516..b6e2561 100644 --- a/app/(dashboard)/anotacoes/data.ts +++ b/src/features/notes/queries.ts @@ -1,6 +1,6 @@ import { and, eq } from "drizzle-orm"; import { type Anotacao, anotacoes } from "@/db/schema"; -import { db } from "@/lib/db"; +import { db } from "@/shared/lib/db"; export type Task = { id: string; diff --git a/app/(dashboard)/pagadores/actions.ts b/src/features/payers/actions.ts similarity index 93% rename from app/(dashboard)/pagadores/actions.ts rename to src/features/payers/actions.ts index ec1b45b..e59df27 100644 --- a/app/(dashboard)/pagadores/actions.ts +++ b/src/features/payers/actions.ts @@ -5,19 +5,22 @@ import { and, eq } from "drizzle-orm"; import { revalidatePath } from "next/cache"; import { z } from "zod"; import { compartilhamentosPagador, pagadores, user } from "@/db/schema"; -import { handleActionError, revalidateForEntity } from "@/lib/actions/helpers"; -import type { ActionResult } from "@/lib/types/actions"; -import { getUser } from "@/lib/auth/server"; -import { db } from "@/lib/db"; +import { + handleActionError, + revalidateForEntity, +} from "@/shared/lib/actions/helpers"; +import { getUser } from "@/shared/lib/auth/server"; +import { db } from "@/shared/lib/db"; import { DEFAULT_PAGADOR_AVATAR, PAGADOR_ROLE_ADMIN, PAGADOR_ROLE_TERCEIRO, PAGADOR_STATUS_OPTIONS, -} from "@/lib/pagadores/constants"; -import { normalizeAvatarPath } from "@/lib/pagadores/utils"; -import { noteSchema, uuidSchema } from "@/lib/schemas/common"; -import { normalizeOptionalString } from "@/lib/utils/string"; +} from "@/shared/lib/payers/constants"; +import { normalizeAvatarPath } from "@/shared/lib/payers/utils"; +import { noteSchema, uuidSchema } from "@/shared/lib/schemas/common"; +import type { ActionResult } from "@/shared/lib/types/actions"; +import { normalizeOptionalString } from "@/shared/utils/string"; const statusEnum = z.enum(PAGADOR_STATUS_OPTIONS as [string, ...string[]], { errorMap: () => ({ @@ -292,7 +295,7 @@ export async function deletePagadorShareAction( .where(eq(compartilhamentosPagador.id, data.shareId)); revalidate(); - revalidatePath(`/pagadores/${existing.pagadorId}`); + revalidatePath(`/payers/${existing.pagadorId}`); return { success: true, message: "Compartilhamento removido." }; } catch (error) { @@ -334,7 +337,7 @@ export async function regeneratePagadorShareCodeAction( ); revalidate(); - revalidatePath(`/pagadores/${data.pagadorId}`); + revalidatePath(`/payers/${data.pagadorId}`); return { success: true, message: "Código atualizado com sucesso.", diff --git a/components/pagadores/details/pagador-card-usage-card.tsx b/src/features/payers/components/details/payer-card-usage-card.tsx similarity index 88% rename from components/pagadores/details/pagador-card-usage-card.tsx rename to src/features/payers/components/details/payer-card-usage-card.tsx index 94ea70b..3bd878e 100644 --- a/components/pagadores/details/pagador-card-usage-card.tsx +++ b/src/features/payers/components/details/payer-card-usage-card.tsx @@ -1,10 +1,10 @@ import { RiBankCard2Line } from "@remixicon/react"; import Image from "next/image"; -import MoneyValues from "@/components/shared/money-values"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; -import { CardContent } from "@/components/ui/card"; -import { resolveLogoSrc } from "@/lib/logo"; -import type { PagadorCardUsageItem } from "@/lib/pagadores/details"; +import MoneyValues from "@/shared/components/money-values"; +import { CardContent } from "@/shared/components/ui/card"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; +import { resolveLogoSrc } from "@/shared/lib/logo"; +import type { PagadorCardUsageItem } from "@/shared/lib/payers/details"; const buildInitials = (value: string) => { const parts = value.trim().split(/\s+/).filter(Boolean); diff --git a/components/pagadores/details/pagador-header-card.tsx b/src/features/payers/components/details/payer-header-card.tsx similarity index 95% rename from components/pagadores/details/pagador-header-card.tsx rename to src/features/payers/components/details/payer-header-card.tsx index 3ab26f9..64a046d 100644 --- a/components/pagadores/details/pagador-header-card.tsx +++ b/src/features/payers/components/details/payer-header-card.tsx @@ -13,15 +13,15 @@ import Link from "next/link"; import { useRouter } from "next/navigation"; import { useState, useTransition } from "react"; import { toast } from "sonner"; -import { sendPagadorSummaryAction } from "@/app/(dashboard)/pagadores/[pagadorId]/actions"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +import { sendPagadorSummaryAction } from "@/features/payers/detail-actions"; +import { Badge } from "@/shared/components/ui/badge"; +import { Button } from "@/shared/components/ui/button"; import { Card, CardDescription, CardHeader, CardTitle, -} from "@/components/ui/card"; +} from "@/shared/components/ui/card"; import { Dialog, DialogContent, @@ -29,11 +29,11 @@ import { DialogFooter, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; -import { getAvatarSrc } from "@/lib/pagadores/utils"; -import { formatCurrency } from "@/lib/utils/currency"; -import { formatDateTime } from "@/lib/utils/date"; +} from "@/shared/components/ui/dialog"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { getAvatarSrc } from "@/shared/lib/payers/utils"; +import { formatCurrency } from "@/shared/utils/currency"; +import { formatDateTime } from "@/shared/utils/date"; import type { PagadorInfo, PagadorSummaryPreview } from "./types"; type PagadorHeaderCardProps = { diff --git a/components/pagadores/details/pagador-history-card.tsx b/src/features/payers/components/details/payer-history-card.tsx similarity index 88% rename from components/pagadores/details/pagador-history-card.tsx rename to src/features/payers/components/details/payer-history-card.tsx index 1854e58..b5c979a 100644 --- a/components/pagadores/details/pagador-history-card.tsx +++ b/src/features/payers/components/details/payer-history-card.tsx @@ -9,15 +9,20 @@ import { type LabelProps, XAxis, } from "recharts"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; import { ChartContainer, ChartTooltip, ChartTooltipContent, -} from "@/components/ui/chart"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; -import { currencyFormatter } from "@/lib/lancamentos/formatting-helpers"; -import type { PagadorHistoryPoint } from "@/lib/pagadores/details"; +} from "@/shared/components/ui/chart"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; +import type { PagadorHistoryPoint } from "@/shared/lib/payers/details"; +import { currencyFormatter } from "@/shared/utils/currency"; const chartConfig = { despesas: { diff --git a/components/pagadores/details/pagador-info-card.tsx b/src/features/payers/components/details/payer-info-card.tsx similarity index 92% rename from components/pagadores/details/pagador-info-card.tsx rename to src/features/payers/components/details/payer-info-card.tsx index fb06151..02eb85c 100644 --- a/components/pagadores/details/pagador-info-card.tsx +++ b/src/features/payers/components/details/payer-info-card.tsx @@ -1,16 +1,16 @@ import { RiUser3Line } from "@remixicon/react"; import type { ReactNode } from "react"; -import { Badge } from "@/components/ui/badge"; +import { Badge } from "@/shared/components/ui/badge"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, -} from "@/components/ui/card"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; -import { formatDateTime } from "@/lib/utils/date"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/card"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { formatDateTime } from "@/shared/utils/date"; +import { cn } from "@/shared/utils/ui"; import type { PagadorInfo } from "./types"; type PagadorInfoCardProps = { diff --git a/components/pagadores/details/pagador-leave-share-card.tsx b/src/features/payers/components/details/payer-leave-share-card.tsx similarity index 90% rename from components/pagadores/details/pagador-leave-share-card.tsx rename to src/features/payers/components/details/payer-leave-share-card.tsx index f065d5d..6f164f3 100644 --- a/components/pagadores/details/pagador-leave-share-card.tsx +++ b/src/features/payers/components/details/payer-leave-share-card.tsx @@ -4,10 +4,15 @@ import { RiLogoutBoxLine } from "@remixicon/react"; import { useRouter } from "next/navigation"; import { useState, useTransition } from "react"; import { toast } from "sonner"; -import { deletePagadorShareAction } from "@/app/(dashboard)/pagadores/actions"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { formatDateTime } from "@/lib/utils/date"; +import { deletePagadorShareAction } from "@/features/payers/actions"; +import { Button } from "@/shared/components/ui/button"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; +import { formatDateTime } from "@/shared/utils/date"; interface PagadorLeaveShareCardProps { shareId: string; @@ -34,7 +39,7 @@ export function PagadorLeaveShareCard({ } toast.success("Você saiu do compartilhamento."); - router.push("/pagadores"); + router.push("/payers"); }); }; diff --git a/components/pagadores/details/pagador-monthly-summary-card.tsx b/src/features/payers/components/details/payer-monthly-summary-card.tsx similarity index 91% rename from components/pagadores/details/pagador-monthly-summary-card.tsx rename to src/features/payers/components/details/payer-monthly-summary-card.tsx index 2d3c3f1..9181e01 100644 --- a/components/pagadores/details/pagador-monthly-summary-card.tsx +++ b/src/features/payers/components/details/payer-monthly-summary-card.tsx @@ -1,8 +1,13 @@ import type { CSSProperties } from "react"; -import MoneyValues from "@/components/shared/money-values"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import type { PagadorMonthlyBreakdown } from "@/lib/pagadores/details"; -import { cn } from "@/lib/utils/ui"; +import MoneyValues from "@/shared/components/money-values"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; +import type { PagadorMonthlyBreakdown } from "@/shared/lib/payers/details"; +import { cn } from "@/shared/utils/ui"; const segmentConfig = { card: { diff --git a/components/pagadores/details/pagador-payment-method-cards.tsx b/src/features/payers/components/details/payer-payment-method-cards.tsx similarity index 88% rename from components/pagadores/details/pagador-payment-method-cards.tsx rename to src/features/payers/components/details/payer-payment-method-cards.tsx index f6841be..85ca511 100644 --- a/components/pagadores/details/pagador-payment-method-cards.tsx +++ b/src/features/payers/components/details/payer-payment-method-cards.tsx @@ -4,17 +4,17 @@ import { RiHourglass2Line, RiWallet3Line, } from "@remixicon/react"; -import { EstabelecimentoLogo } from "@/components/lancamentos/shared/estabelecimento-logo"; -import MoneyValues from "@/components/shared/money-values"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; -import { CardContent } from "@/components/ui/card"; -import { Progress } from "@/components/ui/progress"; -import { buildBillStatusLabel } from "@/lib/dashboard/bills-helpers"; +import { buildBillStatusLabel } from "@/features/dashboard/bills-helpers"; +import { EstabelecimentoLogo } from "@/features/transactions/components/shared/establishment-logo"; +import MoneyValues from "@/shared/components/money-values"; +import { CardContent } from "@/shared/components/ui/card"; +import { Progress } from "@/shared/components/ui/progress"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; import type { PagadorBoletoItem, PagadorPaymentStatusData, -} from "@/lib/pagadores/details"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/lib/payers/details"; +import { cn } from "@/shared/utils/ui"; // --- PagadorBoletoCard --- diff --git a/components/pagadores/details/pagador-sharing-card.tsx b/src/features/payers/components/details/payer-sharing-card.tsx similarity index 95% rename from components/pagadores/details/pagador-sharing-card.tsx rename to src/features/payers/components/details/payer-sharing-card.tsx index 0a1675b..8771c3e 100644 --- a/components/pagadores/details/pagador-sharing-card.tsx +++ b/src/features/payers/components/details/payer-sharing-card.tsx @@ -7,9 +7,14 @@ import { toast } from "sonner"; import { deletePagadorShareAction, regeneratePagadorShareCodeAction, -} from "@/app/(dashboard)/pagadores/actions"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +} from "@/features/payers/actions"; +import { Button } from "@/shared/components/ui/button"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; type PagadorShare = { id: string; diff --git a/components/pagadores/details/types.ts b/src/features/payers/components/details/types.ts similarity index 100% rename from components/pagadores/details/types.ts rename to src/features/payers/components/details/types.ts diff --git a/components/pagadores/pagador-card.tsx b/src/features/payers/components/payer-card.tsx similarity index 91% rename from components/pagadores/pagador-card.tsx rename to src/features/payers/components/payer-card.tsx index 26c6aee..9288262 100644 --- a/components/pagadores/pagador-card.tsx +++ b/src/features/payers/components/payer-card.tsx @@ -9,10 +9,10 @@ import { } from "@remixicon/react"; import Image from "next/image"; import Link from "next/link"; -import { Badge } from "@/components/ui/badge"; -import { Card } from "@/components/ui/card"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; -import { getAvatarSrc } from "@/lib/pagadores/utils"; +import { Badge } from "@/shared/components/ui/badge"; +import { Card } from "@/shared/components/ui/card"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { getAvatarSrc } from "@/shared/lib/payers/utils"; import type { Pagador } from "./types"; interface PagadorCardProps { @@ -93,7 +93,7 @@ export function PagadorCard({ pagador, onEdit, onRemove }: PagadorCardProps) { ) : null} diff --git a/components/pagadores/pagador-dialog.tsx b/src/features/payers/components/payer-dialog.tsx similarity index 93% rename from components/pagadores/pagador-dialog.tsx rename to src/features/payers/components/payer-dialog.tsx index d8505d5..85c8517 100644 --- a/components/pagadores/pagador-dialog.tsx +++ b/src/features/payers/components/payer-dialog.tsx @@ -5,9 +5,9 @@ import { toast } from "sonner"; import { createPagadorAction, updatePagadorAction, -} from "@/app/(dashboard)/pagadores/actions"; -import { Button } from "@/components/ui/button"; -import { Checkbox } from "@/components/ui/checkbox"; +} from "@/features/payers/actions"; +import { Button } from "@/shared/components/ui/button"; +import { Checkbox } from "@/shared/components/ui/checkbox"; import { Dialog, DialogContent, @@ -16,25 +16,25 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; +} from "@/shared/components/ui/dialog"; +import { Input } from "@/shared/components/ui/input"; +import { Label } from "@/shared/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { useControlledState } from "@/lib/hooks/use-controlled-state"; -import { useFormState } from "@/lib/hooks/use-form-state"; +} from "@/shared/components/ui/select"; +import { useControlledState } from "@/shared/hooks/use-controlled-state"; +import { useFormState } from "@/shared/hooks/use-form-state"; import { DEFAULT_PAGADOR_AVATAR, PAGADOR_STATUS_OPTIONS, type PagadorStatus, -} from "@/lib/pagadores/constants"; -import { getAvatarSrc } from "@/lib/pagadores/utils"; -import { StatusSelectContent } from "./pagador-select-items"; +} from "@/shared/lib/payers/constants"; +import { getAvatarSrc } from "@/shared/lib/payers/utils"; +import { StatusSelectContent } from "./payer-select-items"; import type { Pagador, PagadorFormValues } from "./types"; interface PagadorDialogProps { diff --git a/components/pagadores/pagador-select-items.tsx b/src/features/payers/components/payer-select-items.tsx similarity index 84% rename from components/pagadores/pagador-select-items.tsx rename to src/features/payers/components/payer-select-items.tsx index 1595965..1774100 100644 --- a/components/pagadores/pagador-select-items.tsx +++ b/src/features/payers/components/payer-select-items.tsx @@ -1,6 +1,6 @@ "use client"; -import StatusDot from "@/components/shared/status-dot"; +import StatusDot from "@/shared/components/status-dot"; export function StatusSelectContent({ label }: { label: string }) { const isActive = label === "Ativo"; diff --git a/components/pagadores/pagadores-page.tsx b/src/features/payers/components/payers-page.tsx similarity index 92% rename from components/pagadores/pagadores-page.tsx rename to src/features/payers/components/payers-page.tsx index 10e3a8c..cd01cd6 100644 --- a/components/pagadores/pagadores-page.tsx +++ b/src/features/payers/components/payers-page.tsx @@ -7,13 +7,13 @@ import { toast } from "sonner"; import { deletePagadorAction, joinPagadorByShareCodeAction, -} from "@/app/(dashboard)/pagadores/actions"; -import { PagadorCard } from "@/components/pagadores/pagador-card"; -import { PagadorDialog } from "@/components/pagadores/pagador-dialog"; -import { ConfirmActionDialog } from "@/components/shared/confirm-action-dialog"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; +} from "@/features/payers/actions"; +import { PagadorCard } from "@/features/payers/components/payer-card"; +import { PagadorDialog } from "@/features/payers/components/payer-dialog"; +import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog"; +import { Button } from "@/shared/components/ui/button"; +import { Input } from "@/shared/components/ui/input"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; import type { Pagador } from "./types"; interface PagadoresPageProps { diff --git a/components/pagadores/types.ts b/src/features/payers/components/types.ts similarity index 88% rename from components/pagadores/types.ts rename to src/features/payers/components/types.ts index 8956496..f7429b4 100644 --- a/components/pagadores/types.ts +++ b/src/features/payers/components/types.ts @@ -1,4 +1,4 @@ -import type { PagadorStatus } from "@/lib/pagadores/constants"; +import type { PagadorStatus } from "@/shared/lib/payers/constants"; export type Pagador = { id: string; diff --git a/app/(dashboard)/pagadores/[pagadorId]/actions.ts b/src/features/payers/detail-actions.ts similarity index 98% rename from app/(dashboard)/pagadores/[pagadorId]/actions.ts rename to src/features/payers/detail-actions.ts index bf7e06e..c0845b2 100644 --- a/app/(dashboard)/pagadores/[pagadorId]/actions.ts +++ b/src/features/payers/detail-actions.ts @@ -5,18 +5,18 @@ import { revalidatePath } from "next/cache"; import { Resend } from "resend"; import { z } from "zod"; import { lancamentos, pagadores } from "@/db/schema"; -import { getUser } from "@/lib/auth/server"; -import { db } from "@/lib/db"; -import { getResendFromEmail } from "@/lib/email/resend"; +import { getUser } from "@/shared/lib/auth/server"; +import { db } from "@/shared/lib/db"; +import { getResendFromEmail } from "@/shared/lib/email/resend"; import { fetchPagadorBoletoStats, fetchPagadorCardUsage, fetchPagadorHistory, fetchPagadorMonthlyBreakdown, -} from "@/lib/pagadores/details"; -import { formatCurrency } from "@/lib/utils/currency"; -import { formatDateTime } from "@/lib/utils/date"; -import { displayPeriod } from "@/lib/utils/period"; +} from "@/shared/lib/payers/details"; +import { formatCurrency } from "@/shared/utils/currency"; +import { formatDateTime } from "@/shared/utils/date"; +import { displayPeriod } from "@/shared/utils/period"; const inputSchema = z.object({ pagadorId: z.string().uuid("Pagador inválido."), @@ -594,7 +594,7 @@ export async function sendPagadorSummaryAction( and(eq(pagadores.id, pagadorRow.id), eq(pagadores.userId, user.id)), ); - revalidatePath(`/pagadores/${pagadorRow.id}`); + revalidatePath(`/payers/${pagadorRow.id}`); return { success: true, message: "Resumo enviado com sucesso." }; } catch (error) { diff --git a/app/(dashboard)/pagadores/[pagadorId]/data.ts b/src/features/payers/detail-queries.ts similarity index 98% rename from app/(dashboard)/pagadores/[pagadorId]/data.ts rename to src/features/payers/detail-queries.ts index 4afb298..e3c97d8 100644 --- a/app/(dashboard)/pagadores/[pagadorId]/data.ts +++ b/src/features/payers/detail-queries.ts @@ -8,7 +8,7 @@ import { pagadores, user as usersTable, } from "@/db/schema"; -import { db } from "@/lib/db"; +import { db } from "@/shared/lib/db"; export type ShareData = { id: string; diff --git a/lib/avatar/options.ts b/src/features/payers/lib/avatar-options.ts similarity index 84% rename from lib/avatar/options.ts rename to src/features/payers/lib/avatar-options.ts index 20b414e..f72d7cd 100644 --- a/lib/avatar/options.ts +++ b/src/features/payers/lib/avatar-options.ts @@ -1,12 +1,12 @@ import { readdir } from "node:fs/promises"; import path from "node:path"; -import { DEFAULT_PAGADOR_AVATAR } from "@/lib/pagadores/constants"; +import { DEFAULT_PAGADOR_AVATAR } from "@/shared/lib/payers/constants"; -const AVATAR_DIRECTORY = path.join(process.cwd(), "public", "avatares"); +const AVATAR_DIRECTORY = path.join(process.cwd(), "public", "avatars"); const AVATAR_EXTENSIONS = new Set([".png", ".jpg", ".jpeg", ".svg", ".webp"]); /** - * Loads available avatar files from the public/avatares directory + * Loads available avatar files from the public/avatars directory * @returns Array of unique avatar filenames sorted alphabetically */ export async function loadAvatarOptions() { diff --git a/src/features/payers/lib/build-readonly-option-sets.ts b/src/features/payers/lib/build-readonly-option-sets.ts new file mode 100644 index 0000000..65c64ec --- /dev/null +++ b/src/features/payers/lib/build-readonly-option-sets.ts @@ -0,0 +1,97 @@ +import type { pagadores } from "@/db/schema"; +import type { + ContaCartaoFilterOption, + LancamentoFilterOption, + LancamentoItem, + SelectOption, +} from "@/features/transactions/components/types"; +import type { buildOptionSets } from "@/features/transactions/page-helpers"; + +type OptionSet = ReturnType; + +const normalizeOptionLabel = ( + value: string | null | undefined, + fallback: string, +) => (value?.trim().length ? value.trim() : fallback); + +export function buildReadOnlyOptionSets( + items: LancamentoItem[], + pagador: typeof pagadores.$inferSelect, +): OptionSet { + const pagadorLabel = normalizeOptionLabel(pagador.name, "Pagador"); + const pagadorOptions: SelectOption[] = [ + { + value: pagador.id, + label: pagadorLabel, + slug: pagador.id, + }, + ]; + + const contaOptionsMap = new Map(); + const cartaoOptionsMap = new Map(); + const categoriaOptionsMap = new Map(); + + items.forEach((item) => { + if (item.contaId && !contaOptionsMap.has(item.contaId)) { + contaOptionsMap.set(item.contaId, { + value: item.contaId, + label: normalizeOptionLabel(item.contaName, "Conta sem nome"), + slug: item.contaId, + }); + } + if (item.cartaoId && !cartaoOptionsMap.has(item.cartaoId)) { + cartaoOptionsMap.set(item.cartaoId, { + value: item.cartaoId, + label: normalizeOptionLabel(item.cartaoName, "Cartão sem nome"), + slug: item.cartaoId, + }); + } + if (item.categoriaId && !categoriaOptionsMap.has(item.categoriaId)) { + categoriaOptionsMap.set(item.categoriaId, { + value: item.categoriaId, + label: normalizeOptionLabel(item.categoriaName, "Categoria"), + slug: item.categoriaId, + }); + } + }); + + const contaOptions = Array.from(contaOptionsMap.values()); + const cartaoOptions = Array.from(cartaoOptionsMap.values()); + const categoriaOptions = Array.from(categoriaOptionsMap.values()); + + const pagadorFilterOptions: LancamentoFilterOption[] = [ + { slug: pagador.id, label: pagadorLabel }, + ]; + + const categoriaFilterOptions: LancamentoFilterOption[] = categoriaOptions.map( + (option) => ({ + slug: option.value, + label: option.label, + }), + ); + + const contaCartaoFilterOptions: ContaCartaoFilterOption[] = [ + ...contaOptions.map((option) => ({ + slug: option.value, + label: option.label, + kind: "conta" as const, + })), + ...cartaoOptions.map((option) => ({ + slug: option.value, + label: option.label, + kind: "cartao" as const, + })), + ]; + + return { + pagadorOptions, + splitPagadorOptions: [], + defaultPagadorId: pagador.id, + contaOptions, + cartaoOptions, + categoriaOptions, + pagadorFilterOptions, + categoriaFilterOptions, + contaCartaoFilterOptions, + }; +} diff --git a/app/(dashboard)/pagadores/data.ts b/src/features/payers/queries.ts similarity index 87% rename from app/(dashboard)/pagadores/data.ts rename to src/features/payers/queries.ts index 1f53dec..02f8058 100644 --- a/app/(dashboard)/pagadores/data.ts +++ b/src/features/payers/queries.ts @@ -1,13 +1,13 @@ import { eq } from "drizzle-orm"; import { user } from "@/db/schema"; -import { loadAvatarOptions } from "@/lib/avatar/options"; -import { db } from "@/lib/db"; -import { fetchPagadoresWithAccess } from "@/lib/pagadores/access"; -import type { PagadorStatus } from "@/lib/pagadores/constants"; +import { loadAvatarOptions } from "@/features/payers/lib/avatar-options"; +import { db } from "@/shared/lib/db"; +import { fetchPagadoresWithAccess } from "@/shared/lib/payers/access"; +import type { PagadorStatus } from "@/shared/lib/payers/constants"; import { PAGADOR_ROLE_ADMIN, PAGADOR_STATUS_OPTIONS, -} from "@/lib/pagadores/constants"; +} from "@/shared/lib/payers/constants"; export type PagadorData = { id: string; diff --git a/src/features/recurring/actions.ts b/src/features/recurring/actions.ts new file mode 100644 index 0000000..af7f0a6 --- /dev/null +++ b/src/features/recurring/actions.ts @@ -0,0 +1,144 @@ +"use server"; + +import { and, eq } from "drizzle-orm"; +import { recurringSeries } from "@/db/schema"; +import { generateRecurringTransactions } from "@/features/recurring/generate-recurring"; +import { + handleActionError, + revalidateForEntity, +} from "@/shared/lib/actions/helpers"; +import { getUser } from "@/shared/lib/auth/server"; +import { db } from "@/shared/lib/db"; +import { recurringSeriesActionSchema } from "@/shared/lib/schemas/recurring-series"; +import type { ActionResult } from "@/shared/lib/types/actions"; + +const revalidate = () => revalidateForEntity("recorrentes"); + +async function findRecurringSeriesForUser(userId: string, seriesId: string) { + const [series] = await db + .select({ + id: recurringSeries.id, + status: recurringSeries.status, + }) + .from(recurringSeries) + .where( + and(eq(recurringSeries.id, seriesId), eq(recurringSeries.userId, userId)), + ) + .limit(1); + + return series ?? null; +} + +export async function pauseRecurringSeriesAction(input: { + seriesId: string; +}): Promise { + try { + const user = await getUser(); + const data = recurringSeriesActionSchema.parse(input); + + const existing = await findRecurringSeriesForUser(user.id, data.seriesId); + + if (!existing) { + return { success: false, error: "Série recorrente não encontrada." }; + } + + if (existing.status !== "active") { + return { + success: false, + error: "Apenas séries ativas podem ser pausadas.", + }; + } + + await db + .update(recurringSeries) + .set({ status: "paused", updatedAt: new Date() }) + .where( + and( + eq(recurringSeries.id, data.seriesId), + eq(recurringSeries.userId, user.id), + ), + ); + + revalidate(); + return { success: true, message: "Série recorrente pausada." }; + } catch (error) { + return handleActionError(error); + } +} + +export async function resumeRecurringSeriesAction(input: { + seriesId: string; +}): Promise { + try { + const user = await getUser(); + const data = recurringSeriesActionSchema.parse(input); + + const existing = await findRecurringSeriesForUser(user.id, data.seriesId); + + if (!existing) { + return { success: false, error: "Série recorrente não encontrada." }; + } + + if (existing.status !== "paused") { + return { + success: false, + error: "Apenas séries pausadas podem ser retomadas.", + }; + } + + await db + .update(recurringSeries) + .set({ status: "active", updatedAt: new Date() }) + .where( + and( + eq(recurringSeries.id, data.seriesId), + eq(recurringSeries.userId, user.id), + ), + ); + + // Trigger catch-up generation for missed months + await generateRecurringTransactions(user.id); + + revalidate(); + return { success: true, message: "Série recorrente retomada." }; + } catch (error) { + return handleActionError(error); + } +} + +export async function cancelRecurringSeriesAction(input: { + seriesId: string; +}): Promise { + try { + const user = await getUser(); + const data = recurringSeriesActionSchema.parse(input); + + const existing = await findRecurringSeriesForUser(user.id, data.seriesId); + + if (!existing) { + return { success: false, error: "Série recorrente não encontrada." }; + } + + if (existing.status === "cancelled") { + return { + success: false, + error: "Esta série já está cancelada.", + }; + } + + await db + .update(recurringSeries) + .set({ status: "cancelled", updatedAt: new Date() }) + .where( + and( + eq(recurringSeries.id, data.seriesId), + eq(recurringSeries.userId, user.id), + ), + ); + + revalidate(); + return { success: true, message: "Série recorrente cancelada." }; + } catch (error) { + return handleActionError(error); + } +} diff --git a/src/features/recurring/generate-recurring.ts b/src/features/recurring/generate-recurring.ts new file mode 100644 index 0000000..a01c12f --- /dev/null +++ b/src/features/recurring/generate-recurring.ts @@ -0,0 +1,126 @@ +import { and, eq } from "drizzle-orm"; +import { lancamentos, recurringSeries } from "@/db/schema"; +import { db } from "@/shared/lib/db"; +import { + addMonthsToPeriod, + comparePeriods, + getCurrentPeriod, + getNextPeriod, + parsePeriod, +} from "@/shared/utils/period"; + +/** + * Computes the purchase date for a given period and day of month. + * Clamps to last day of month for short months (e.g., Feb 30 → Feb 28). + */ +function computePurchaseDate(period: string, dayOfMonth: number): Date { + const { year, month } = parsePeriod(period); + // month is 1-indexed, Date constructor expects 0-indexed + const lastDayOfMonth = new Date(year, month, 0).getDate(); + const clampedDay = Math.min(dayOfMonth, lastDayOfMonth); + return new Date(year, month - 1, clampedDay); +} + +/** + * Generates missing recurring transactions for a single user. + * + * For each active recurring series: + * 1. Determines which months are missing between lastGeneratedPeriod and current month + * 2. Creates lancamento rows for each missing month using the template data + * 3. Updates lastGeneratedPeriod on the series + * + * Uses a DB transaction for atomicity. + */ +export async function generateRecurringTransactions( + userId: string, +): Promise<{ generated: number }> { + const currentPeriod = getCurrentPeriod(); + + // Fetch all active recurring series for this user + const activeSeries = await db + .select() + .from(recurringSeries) + .where( + and( + eq(recurringSeries.userId, userId), + eq(recurringSeries.status, "active"), + ), + ); + + if (activeSeries.length === 0) { + return { generated: 0 }; + } + + let totalGenerated = 0; + + for (const series of activeSeries) { + // Determine missing periods: from lastGeneratedPeriod + 1 to currentPeriod + const startPeriod = getNextPeriod(series.lastGeneratedPeriod); + + // If startPeriod is already past the current period, nothing to generate + if (comparePeriods(startPeriod, currentPeriod) > 0) { + continue; + } + + // Build list of periods to generate + const periodsToGenerate: string[] = []; + let iterPeriod = startPeriod; + while (comparePeriods(iterPeriod, currentPeriod) <= 0) { + periodsToGenerate.push(iterPeriod); + iterPeriod = addMonthsToPeriod(iterPeriod, 1); + } + + if (periodsToGenerate.length === 0) { + continue; + } + + const template = series.templateData; + + // Create all lancamentos for missing periods in a transaction + await db.transaction(async (tx: typeof db) => { + const records = periodsToGenerate.map((period) => { + const purchaseDate = computePurchaseDate(period, series.dayOfMonth); + return { + name: template.name, + amount: template.amount, + transactionType: template.transactionType, + paymentMethod: template.paymentMethod, + condition: "Recorrente" as const, + categoriaId: template.categoriaId, + contaId: template.contaId, + cartaoId: template.cartaoId, + pagadorId: template.pagadorId, + note: template.note, + purchaseDate, + period, + isSettled: false, + recurrenceCount: null, + installmentCount: null, + currentInstallment: null, + isDivided: false, + userId, + seriesId: series.id, + recurringSeriesId: series.id, + }; + }); + + await tx.insert(lancamentos).values(records); + + // Update lastGeneratedPeriod to the last period we generated + const lastPeriod = + periodsToGenerate[periodsToGenerate.length - 1] ?? + series.lastGeneratedPeriod; + await tx + .update(recurringSeries) + .set({ + lastGeneratedPeriod: lastPeriod, + updatedAt: new Date(), + }) + .where(eq(recurringSeries.id, series.id)); + }); + + totalGenerated += periodsToGenerate.length; + } + + return { generated: totalGenerated }; +} diff --git a/src/features/recurring/trigger-recurring-generation.ts b/src/features/recurring/trigger-recurring-generation.ts new file mode 100644 index 0000000..a2240a8 --- /dev/null +++ b/src/features/recurring/trigger-recurring-generation.ts @@ -0,0 +1,23 @@ +import { cache } from "react"; +import { generateRecurringTransactions } from "./generate-recurring"; + +/** + * Triggers recurring transaction generation for a user. + * Deduped per-request via React.cache to avoid multiple calls + * during the same server render (layout + page). + * + * Call this at the top of dashboard and lancamentos page server components. + */ +export const triggerRecurringGeneration = cache( + async (userId: string): Promise => { + try { + await generateRecurringTransactions(userId); + } catch (error) { + // Log but don't throw — generation failure should not block page render + console.error( + "[RecurringGeneration] Failed to generate recurring transactions:", + error, + ); + } + }, +); diff --git a/src/features/recurring/types.ts b/src/features/recurring/types.ts new file mode 100644 index 0000000..3626973 --- /dev/null +++ b/src/features/recurring/types.ts @@ -0,0 +1,4 @@ +// Re-export from schema for convenience +export type { RecurringSeriesTemplate } from "@/db/schema"; + +export type RecurringSeriesStatus = "active" | "paused" | "cancelled"; diff --git a/lib/relatorios/cartoes-report.ts b/src/features/reports/cards-report-queries.ts similarity index 97% rename from lib/relatorios/cartoes-report.ts rename to src/features/reports/cards-report-queries.ts index 7984f55..b271256 100644 --- a/lib/relatorios/cartoes-report.ts +++ b/src/features/reports/cards-report-queries.ts @@ -18,15 +18,15 @@ import { lancamentos, pagadores, } from "@/db/schema"; -import { db } from "@/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; -import { formatDateOnly } from "@/lib/utils/date"; -import { safeToNumber } from "@/lib/utils/number"; +import { db } from "@/shared/lib/db"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { formatDateOnly } from "@/shared/utils/date"; +import { safeToNumber } from "@/shared/utils/number"; import { buildPeriodWindow, formatCompactPeriodLabel, getPreviousPeriod, -} from "@/lib/utils/period"; +} from "@/shared/utils/period"; const DESPESA = "Despesa"; diff --git a/lib/relatorios/fetch-category-chart-data.ts b/src/features/reports/category-chart-queries.ts similarity index 92% rename from lib/relatorios/fetch-category-chart-data.ts rename to src/features/reports/category-chart-queries.ts index ba89091..5ea8f86 100644 --- a/lib/relatorios/fetch-category-chart-data.ts +++ b/src/features/reports/category-chart-queries.ts @@ -1,10 +1,10 @@ import { and, eq, inArray, isNull, or, sql } from "drizzle-orm"; import { categorias, lancamentos } from "@/db/schema"; -import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; -import { formatPeriodMonthShort } from "@/lib/utils/period"; +import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; +import { formatPeriodMonthShort } from "@/shared/utils/period"; import { generatePeriodRange } from "./utils"; export type CategoryChartData = { diff --git a/lib/relatorios/fetch-category-report.ts b/src/features/reports/category-report-queries.ts similarity index 95% rename from lib/relatorios/fetch-category-report.ts rename to src/features/reports/category-report-queries.ts index 7097339..797cc22 100644 --- a/lib/relatorios/fetch-category-report.ts +++ b/src/features/reports/category-report-queries.ts @@ -1,9 +1,9 @@ import { and, eq, inArray, isNull, or, sql } from "drizzle-orm"; import { categorias, lancamentos } from "@/db/schema"; -import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { getAdminPagadorId } from "@/lib/pagadores/get-admin-id"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; +import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; import type { CategoryReportData, CategoryReportFilters, diff --git a/app/(dashboard)/relatorios/tendencias/data.ts b/src/features/reports/category-trends-queries.ts similarity index 88% rename from app/(dashboard)/relatorios/tendencias/data.ts rename to src/features/reports/category-trends-queries.ts index bae4ce2..89d78e4 100644 --- a/app/(dashboard)/relatorios/tendencias/data.ts +++ b/src/features/reports/category-trends-queries.ts @@ -1,6 +1,6 @@ import { asc, eq } from "drizzle-orm"; import { type Categoria, categorias } from "@/db/schema"; -import { db } from "@/lib/db"; +import { db } from "@/shared/lib/db"; export async function fetchUserCategories( userId: string, diff --git a/components/relatorios/cartoes/card-category-breakdown.tsx b/src/features/reports/components/cards/card-category-breakdown.tsx similarity index 84% rename from components/relatorios/cartoes/card-category-breakdown.tsx rename to src/features/reports/components/cards/card-category-breakdown.tsx index b9e26ff..09032d8 100644 --- a/components/relatorios/cartoes/card-category-breakdown.tsx +++ b/src/features/reports/components/cards/card-category-breakdown.tsx @@ -1,12 +1,17 @@ "use client"; import { RiPieChartLine } from "@remixicon/react"; -import { CategoryIconBadge } from "@/components/categorias/category-icon-badge"; -import MoneyValues from "@/components/shared/money-values"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Progress } from "@/components/ui/progress"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; -import type { CardDetailData } from "@/lib/relatorios/cartoes-report"; +import { CategoryIconBadge } from "@/features/categories/components/category-icon-badge"; +import type { CardDetailData } from "@/features/reports/cards-report-queries"; +import MoneyValues from "@/shared/components/money-values"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; +import { Progress } from "@/shared/components/ui/progress"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; type CardCategoryBreakdownProps = { data: CardDetailData["categoryBreakdown"]; diff --git a/components/relatorios/cartoes/card-invoice-status.tsx b/src/features/reports/components/cards/card-invoice-status.tsx similarity index 84% rename from components/relatorios/cartoes/card-invoice-status.tsx rename to src/features/reports/components/cards/card-invoice-status.tsx index 2a28aa9..84adca0 100644 --- a/components/relatorios/cartoes/card-invoice-status.tsx +++ b/src/features/reports/components/cards/card-invoice-status.tsx @@ -1,17 +1,22 @@ "use client"; import { RiCalendarCheckLine } from "@remixicon/react"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import type { CardDetailData } from "@/features/reports/cards-report-queries"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, -} from "@/components/ui/tooltip"; -import type { CardDetailData } from "@/lib/relatorios/cartoes-report"; -import { cn } from "@/lib/utils"; -import { formatCurrency } from "@/lib/utils/currency"; -import { formatPeriodMonthShort } from "@/lib/utils/period"; +} from "@/shared/components/ui/tooltip"; +import { cn } from "@/shared/utils"; +import { formatCurrency } from "@/shared/utils/currency"; +import { formatPeriodMonthShort } from "@/shared/utils/period"; type CardInvoiceStatusProps = { data: CardDetailData["invoiceStatus"]; diff --git a/components/relatorios/cartoes/card-top-expenses.tsx b/src/features/reports/components/cards/card-top-expenses.tsx similarity index 87% rename from components/relatorios/cartoes/card-top-expenses.tsx rename to src/features/reports/components/cards/card-top-expenses.tsx index 0593e8c..551b080 100644 --- a/components/relatorios/cartoes/card-top-expenses.tsx +++ b/src/features/reports/components/cards/card-top-expenses.tsx @@ -1,12 +1,17 @@ "use client"; import { RiShoppingBag3Line } from "@remixicon/react"; -import MoneyValues from "@/components/shared/money-values"; -import { Badge } from "@/components/ui/badge"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Progress } from "@/components/ui/progress"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; -import type { CardDetailData } from "@/lib/relatorios/cartoes-report"; +import type { CardDetailData } from "@/features/reports/cards-report-queries"; +import MoneyValues from "@/shared/components/money-values"; +import { Badge } from "@/shared/components/ui/badge"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; +import { Progress } from "@/shared/components/ui/progress"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; type CardTopExpensesProps = { data: CardDetailData["topExpenses"]; diff --git a/components/relatorios/cartoes/card-usage-chart.tsx b/src/features/reports/components/cards/card-usage-chart.tsx similarity index 91% rename from components/relatorios/cartoes/card-usage-chart.tsx rename to src/features/reports/components/cards/card-usage-chart.tsx index aa89606..261d809 100644 --- a/components/relatorios/cartoes/card-usage-chart.tsx +++ b/src/features/reports/components/cards/card-usage-chart.tsx @@ -10,16 +10,21 @@ import { XAxis, YAxis, } from "recharts"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import type { CardDetailData } from "@/features/reports/cards-report-queries"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; import { type ChartConfig, ChartContainer, ChartTooltip, -} from "@/components/ui/chart"; -import { resolveLogoSrc } from "@/lib/logo"; -import type { CardDetailData } from "@/lib/relatorios/cartoes-report"; -import { formatCurrency, formatCurrencyCompact } from "@/lib/utils/currency"; -import { formatPercentage } from "@/lib/utils/percentage"; +} from "@/shared/components/ui/chart"; +import { resolveLogoSrc } from "@/shared/lib/logo"; +import { formatCurrency, formatCurrencyCompact } from "@/shared/utils/currency"; +import { formatPercentage } from "@/shared/utils/percentage"; type CardUsageChartProps = { data: CardDetailData["monthlyUsage"]; diff --git a/components/relatorios/cartoes/cards-overview.tsx b/src/features/reports/components/cards/cards-overview.tsx similarity index 87% rename from components/relatorios/cartoes/cards-overview.tsx rename to src/features/reports/components/cards/cards-overview.tsx index b3eb1b6..99fc189 100644 --- a/components/relatorios/cartoes/cards-overview.tsx +++ b/src/features/reports/components/cards/cards-overview.tsx @@ -4,15 +4,15 @@ import { RiBankCard2Line } from "@remixicon/react"; import Image from "next/image"; import Link from "next/link"; import { useSearchParams } from "next/navigation"; -import MoneyValues from "@/components/shared/money-values"; -import { Card, CardContent } from "@/components/ui/card"; -import { Progress } from "@/components/ui/progress"; -import { resolveCardBrandAsset } from "@/lib/cartoes/brand-assets"; -import { resolveLogoSrc } from "@/lib/logo"; -import type { CartoesReportData } from "@/lib/relatorios/cartoes-report"; -import { cn } from "@/lib/utils"; -import { formatCurrency } from "@/lib/utils/currency"; -import { formatPercentage } from "@/lib/utils/percentage"; +import type { CartoesReportData } from "@/features/reports/cards-report-queries"; +import MoneyValues from "@/shared/components/money-values"; +import { Card, CardContent } from "@/shared/components/ui/card"; +import { Progress } from "@/shared/components/ui/progress"; +import { resolveCardBrandAsset } from "@/shared/lib/cards/brand-assets"; +import { resolveLogoSrc } from "@/shared/lib/logo"; +import { cn } from "@/shared/utils"; +import { formatCurrency } from "@/shared/utils/currency"; +import { formatPercentage } from "@/shared/utils/percentage"; type CardsOverviewProps = { data: CartoesReportData; @@ -32,7 +32,7 @@ export function CardsOverview({ data }: CardsOverviewProps) { const params = new URLSearchParams(); if (periodoParam) params.set("periodo", periodoParam); params.set("cartao", cardId); - return `/relatorios/uso-cartoes?${params.toString()}`; + return `/reports/card-usage?${params.toString()}`; }; const summaryCards = [ diff --git a/components/relatorios/category-cell.tsx b/src/features/reports/components/category-cell.tsx similarity index 92% rename from components/relatorios/category-cell.tsx rename to src/features/reports/components/category-cell.tsx index 82f9d44..32f124b 100644 --- a/components/relatorios/category-cell.tsx +++ b/src/features/reports/components/category-cell.tsx @@ -1,14 +1,14 @@ "use client"; import { RiArrowDownSFill, RiArrowUpSFill } from "@remixicon/react"; +import { formatPercentageChange } from "@/features/reports/utils"; import { Tooltip, TooltipContent, TooltipTrigger, -} from "@/components/ui/tooltip"; -import { formatCurrency } from "@/lib/lancamentos/formatting-helpers"; -import { formatPercentageChange } from "@/lib/relatorios/utils"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/tooltip"; +import { formatCurrency } from "@/shared/utils/currency"; +import { cn } from "@/shared/utils/ui"; interface CategoryCellProps { value: number; diff --git a/components/relatorios/category-report-cards.tsx b/src/features/reports/components/category-report-cards.tsx similarity index 90% rename from components/relatorios/category-report-cards.tsx rename to src/features/reports/components/category-report-cards.tsx index f359f63..812e366 100644 --- a/components/relatorios/category-report-cards.tsx +++ b/src/features/reports/components/category-report-cards.tsx @@ -2,15 +2,20 @@ import Link from "next/link"; import { useMemo } from "react"; -import { CategoryIconBadge } from "@/components/categorias/category-icon-badge"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { formatCurrency } from "@/lib/lancamentos/formatting-helpers"; +import { CategoryIconBadge } from "@/features/categories/components/category-icon-badge"; +import { formatPeriodLabel } from "@/features/reports/utils"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; import type { CategoryReportData, CategoryReportItem, -} from "@/lib/types/relatorios"; -import { formatPeriodLabel } from "@/lib/relatorios/utils"; -import { formatPeriodForUrl } from "@/lib/utils/period"; +} from "@/shared/lib/types/reports"; +import { formatCurrency } from "@/shared/utils/currency"; +import { formatPeriodForUrl } from "@/shared/utils/period"; import { CategoryCell } from "./category-cell"; interface CategoryReportCardsProps { @@ -43,7 +48,7 @@ function CategoryCard({ colorIndex={colorIndex} /> {category.name} diff --git a/components/relatorios/category-report-chart.tsx b/src/features/reports/components/category-report-chart.tsx similarity index 93% rename from components/relatorios/category-report-chart.tsx rename to src/features/reports/components/category-report-chart.tsx index 574cf1f..3393e20 100644 --- a/components/relatorios/category-report-chart.tsx +++ b/src/features/reports/components/category-report-chart.tsx @@ -9,31 +9,31 @@ import { type TooltipProps, XAxis, } from "recharts"; -import { EmptyState } from "@/components/shared/empty-state"; +import type { CategoryChartData } from "@/features/reports/category-chart-queries"; +import { EmptyState } from "@/shared/components/empty-state"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, -} from "@/components/ui/card"; +} from "@/shared/components/ui/card"; import { type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, -} from "@/components/ui/chart"; +} from "@/shared/components/ui/chart"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { currencyFormatter } from "@/lib/lancamentos/formatting-helpers"; -import type { CategoryChartData } from "@/lib/relatorios/fetch-category-chart-data"; -import { CATEGORY_COLORS } from "@/lib/utils/category-colors"; +} from "@/shared/components/ui/select"; +import { CATEGORY_COLORS } from "@/shared/utils/category-colors"; +import { currencyFormatter } from "@/shared/utils/currency"; function AreaTooltip({ active, payload, label }: TooltipProps) { if (!active || !payload?.length) return null; diff --git a/components/relatorios/category-report-export.tsx b/src/features/reports/components/category-report-export.tsx similarity index 95% rename from components/relatorios/category-report-export.tsx rename to src/features/reports/components/category-report-export.tsx index 9e9a697..9ef5f7f 100644 --- a/components/relatorios/category-report-export.tsx +++ b/src/features/reports/components/category-report-export.tsx @@ -11,24 +11,24 @@ import autoTable from "jspdf-autotable"; import { useState } from "react"; import { toast } from "sonner"; import * as XLSX from "xlsx"; -import { Button } from "@/components/ui/button"; +import { + formatPercentageChange, + formatPeriodLabel, +} from "@/features/reports/utils"; +import { Button } from "@/shared/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { formatCurrency } from "@/lib/lancamentos/formatting-helpers"; -import { - formatPercentageChange, - formatPeriodLabel, -} from "@/lib/relatorios/utils"; -import type { CategoryReportData } from "@/lib/types/relatorios"; -import { formatDateTime } from "@/lib/utils/date"; +} from "@/shared/components/ui/dropdown-menu"; +import type { CategoryReportData } from "@/shared/lib/types/reports"; +import { formatCurrency } from "@/shared/utils/currency"; +import { formatDateTime } from "@/shared/utils/date"; import { getPrimaryPdfColor, loadExportLogoDataUrl, -} from "@/lib/utils/export-branding"; +} from "@/shared/utils/export-branding"; import type { FilterState } from "./types"; interface CategoryReportExportProps { @@ -202,8 +202,8 @@ export function CategoryReportExport({ const doc = new jsPDF({ orientation: "landscape" }); const primaryColor = getPrimaryPdfColor(); const [smallLogoDataUrl, textLogoDataUrl] = await Promise.all([ - loadExportLogoDataUrl("/imagens/logo_small.png"), - loadExportLogoDataUrl("/imagens/logo_text.png"), + loadExportLogoDataUrl("/images/logo_small.png"), + loadExportLogoDataUrl("/images/logo_text.png"), ]); let brandingEndX = 14; diff --git a/components/relatorios/category-report-filters.tsx b/src/features/reports/components/category-report-filters.tsx similarity index 95% rename from components/relatorios/category-report-filters.tsx rename to src/features/reports/components/category-report-filters.tsx index ae2d3d9..4a227e0 100644 --- a/components/relatorios/category-report-filters.tsx +++ b/src/features/reports/components/category-report-filters.tsx @@ -7,7 +7,8 @@ import { } from "@remixicon/react"; import type { ReactNode } from "react"; import { useMemo, useState } from "react"; -import { Button } from "@/components/ui/button"; +import { validateDateRange } from "@/features/reports/utils"; +import { Button } from "@/shared/components/ui/button"; import { Command, CommandEmpty, @@ -15,22 +16,21 @@ import { CommandInput, CommandItem, CommandList, -} from "@/components/ui/command"; -import { MonthPicker } from "@/components/ui/month-picker"; +} from "@/shared/components/ui/command"; +import { MonthPicker } from "@/shared/components/ui/month-picker"; import { Popover, PopoverContent, PopoverTrigger, -} from "@/components/ui/popover"; -import { validateDateRange } from "@/lib/relatorios/utils"; -import { getIconComponent } from "@/lib/utils/icons"; +} from "@/shared/components/ui/popover"; +import { getIconComponent } from "@/shared/utils/icons"; import { addMonthsToPeriod, dateToPeriod, formatShortPeriodLabel, getCurrentPeriod, periodToDate, -} from "@/lib/utils/period"; +} from "@/shared/utils/period"; import type { CategoryReportFiltersProps } from "./types"; /** diff --git a/components/relatorios/category-report-page.tsx b/src/features/reports/components/category-report-page.tsx similarity index 92% rename from components/relatorios/category-report-page.tsx rename to src/features/reports/components/category-report-page.tsx index 36df08b..fcf24c7 100644 --- a/components/relatorios/category-report-page.tsx +++ b/src/features/reports/components/category-report-page.tsx @@ -7,12 +7,17 @@ import { } from "@remixicon/react"; import { useRouter, useSearchParams } from "next/navigation"; import { useEffect, useRef, useState, useTransition } from "react"; -import { EmptyState } from "@/components/shared/empty-state"; -import { CategoryReportSkeleton } from "@/components/shared/skeletons/category-report-skeleton"; -import { Card } from "@/components/ui/card"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import type { CategoryChartData } from "@/lib/relatorios/fetch-category-chart-data"; -import type { CategoryReportData } from "@/lib/types/relatorios"; +import type { CategoryChartData } from "@/features/reports/category-chart-queries"; +import { EmptyState } from "@/shared/components/empty-state"; +import { CategoryReportSkeleton } from "@/shared/components/skeletons/category-report-skeleton"; +import { Card } from "@/shared/components/ui/card"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/shared/components/ui/tabs"; +import type { CategoryReportData } from "@/shared/lib/types/reports"; import { CategoryReportCards } from "./category-report-cards"; import { CategoryReportChart } from "./category-report-chart"; import { CategoryReportExport } from "./category-report-export"; diff --git a/components/relatorios/category-report-table.tsx b/src/features/reports/components/category-report-table.tsx similarity index 96% rename from components/relatorios/category-report-table.tsx rename to src/features/reports/components/category-report-table.tsx index c72a1b3..a44266c 100644 --- a/components/relatorios/category-report-table.tsx +++ b/src/features/reports/components/category-report-table.tsx @@ -4,7 +4,7 @@ import { useMemo } from "react"; import type { CategoryReportData, CategoryReportItem, -} from "@/lib/types/relatorios"; +} from "@/shared/lib/types/reports"; import { CategoryTable } from "./category-table"; interface CategoryReportTableProps { diff --git a/components/relatorios/category-table.tsx b/src/features/reports/components/category-table.tsx similarity index 88% rename from components/relatorios/category-table.tsx rename to src/features/reports/components/category-table.tsx index dfd9e7a..e58d0fe 100644 --- a/components/relatorios/category-table.tsx +++ b/src/features/reports/components/category-table.tsx @@ -2,8 +2,10 @@ import Link from "next/link"; import { useMemo } from "react"; -import { CategoryIconBadge } from "@/components/categorias/category-icon-badge"; -import StatusDot from "@/components/shared/status-dot"; +import { CategoryIconBadge } from "@/features/categories/components/category-icon-badge"; +import { formatPeriodLabel } from "@/features/reports/utils"; +import StatusDot from "@/shared/components/status-dot"; +import { Card } from "@/shared/components/ui/card"; import { Table, TableBody, @@ -12,12 +14,10 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; -import { formatCurrency } from "@/lib/lancamentos/formatting-helpers"; -import { formatPeriodLabel } from "@/lib/relatorios/utils"; -import type { CategoryReportItem } from "@/lib/types/relatorios"; -import { formatPeriodForUrl } from "@/lib/utils/period"; -import { Card } from "../ui/card"; +} from "@/shared/components/ui/table"; +import type { CategoryReportItem } from "@/shared/lib/types/reports"; +import { formatCurrency } from "@/shared/utils/currency"; +import { formatPeriodForUrl } from "@/shared/utils/period"; import { CategoryCell } from "./category-cell"; export interface CategoryTableProps { @@ -107,7 +107,7 @@ export function CategoryTable({ colorIndex={colorIndex} /> {category.name} diff --git a/components/relatorios/estabelecimentos/establishments-list.tsx b/src/features/reports/components/establishments/establishments-list.tsx similarity index 89% rename from components/relatorios/estabelecimentos/establishments-list.tsx rename to src/features/reports/components/establishments/establishments-list.tsx index af5c189..8179dd0 100644 --- a/components/relatorios/estabelecimentos/establishments-list.tsx +++ b/src/features/reports/components/establishments/establishments-list.tsx @@ -1,12 +1,17 @@ "use client"; import { RiStore2Line } from "@remixicon/react"; -import MoneyValues from "@/components/shared/money-values"; -import { Badge } from "@/components/ui/badge"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Progress } from "@/components/ui/progress"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; -import type { TopEstabelecimentosData } from "@/lib/relatorios/estabelecimentos/fetch-data"; +import type { TopEstabelecimentosData } from "@/features/reports/establishments/queries"; +import MoneyValues from "@/shared/components/money-values"; +import { Badge } from "@/shared/components/ui/badge"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; +import { Progress } from "@/shared/components/ui/progress"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; type EstablishmentsListProps = { establishments: TopEstabelecimentosData["establishments"]; diff --git a/components/relatorios/estabelecimentos/highlights-cards.tsx b/src/features/reports/components/establishments/highlights-cards.tsx similarity index 91% rename from components/relatorios/estabelecimentos/highlights-cards.tsx rename to src/features/reports/components/establishments/highlights-cards.tsx index 2f72fdb..ee08a2f 100644 --- a/components/relatorios/estabelecimentos/highlights-cards.tsx +++ b/src/features/reports/components/establishments/highlights-cards.tsx @@ -1,8 +1,8 @@ "use client"; import { RiFireLine, RiTrophyLine } from "@remixicon/react"; -import { Card, CardContent } from "@/components/ui/card"; -import type { TopEstabelecimentosData } from "@/lib/relatorios/estabelecimentos/fetch-data"; +import type { TopEstabelecimentosData } from "@/features/reports/establishments/queries"; +import { Card, CardContent } from "@/shared/components/ui/card"; type HighlightsCardsProps = { summary: TopEstabelecimentosData["summary"]; diff --git a/components/relatorios/estabelecimentos/period-filter.tsx b/src/features/reports/components/establishments/period-filter.tsx similarity index 82% rename from components/relatorios/estabelecimentos/period-filter.tsx rename to src/features/reports/components/establishments/period-filter.tsx index ee2421b..bd03ea5 100644 --- a/components/relatorios/estabelecimentos/period-filter.tsx +++ b/src/features/reports/components/establishments/period-filter.tsx @@ -1,9 +1,9 @@ "use client"; import { useRouter, useSearchParams } from "next/navigation"; -import { Button } from "@/components/ui/button"; -import type { PeriodFilter } from "@/lib/relatorios/estabelecimentos/fetch-data"; -import { cn } from "@/lib/utils"; +import type { PeriodFilter } from "@/features/reports/establishments/queries"; +import { Button } from "@/shared/components/ui/button"; +import { cn } from "@/shared/utils"; type PeriodFilterProps = { currentFilter: PeriodFilter; @@ -22,7 +22,7 @@ export function PeriodFilterButtons({ currentFilter }: PeriodFilterProps) { const handleFilterChange = (filter: PeriodFilter) => { const params = new URLSearchParams(searchParams.toString()); params.set("meses", filter); - router.push(`/relatorios/estabelecimentos?${params.toString()}`); + router.push(`/reports/establishments?${params.toString()}`); }; return ( diff --git a/components/relatorios/estabelecimentos/summary-cards.tsx b/src/features/reports/components/establishments/summary-cards.tsx similarity index 89% rename from components/relatorios/estabelecimentos/summary-cards.tsx rename to src/features/reports/components/establishments/summary-cards.tsx index e124321..2920c2d 100644 --- a/components/relatorios/estabelecimentos/summary-cards.tsx +++ b/src/features/reports/components/establishments/summary-cards.tsx @@ -6,9 +6,9 @@ import { RiRepeatLine, RiStore2Line, } from "@remixicon/react"; -import MoneyValues from "@/components/shared/money-values"; -import { Card, CardContent } from "@/components/ui/card"; -import type { TopEstabelecimentosData } from "@/lib/relatorios/estabelecimentos/fetch-data"; +import type { TopEstabelecimentosData } from "@/features/reports/establishments/queries"; +import MoneyValues from "@/shared/components/money-values"; +import { Card, CardContent } from "@/shared/components/ui/card"; type SummaryCardsProps = { summary: TopEstabelecimentosData["summary"]; diff --git a/components/relatorios/estabelecimentos/top-categories.tsx b/src/features/reports/components/establishments/top-categories.tsx similarity index 85% rename from components/relatorios/estabelecimentos/top-categories.tsx rename to src/features/reports/components/establishments/top-categories.tsx index d61ba37..d1f92b1 100644 --- a/components/relatorios/estabelecimentos/top-categories.tsx +++ b/src/features/reports/components/establishments/top-categories.tsx @@ -1,12 +1,17 @@ "use client"; import { RiPriceTag3Line } from "@remixicon/react"; -import { CategoryIconBadge } from "@/components/categorias/category-icon-badge"; -import MoneyValues from "@/components/shared/money-values"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Progress } from "@/components/ui/progress"; -import { WidgetEmptyState } from "@/components/shared/widget-empty-state"; -import type { TopEstabelecimentosData } from "@/lib/relatorios/estabelecimentos/fetch-data"; +import { CategoryIconBadge } from "@/features/categories/components/category-icon-badge"; +import type { TopEstabelecimentosData } from "@/features/reports/establishments/queries"; +import MoneyValues from "@/shared/components/money-values"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/shared/components/ui/card"; +import { Progress } from "@/shared/components/ui/progress"; +import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; type TopCategoriesProps = { categories: TopEstabelecimentosData["topCategories"]; diff --git a/components/relatorios/types.ts b/src/features/reports/components/types.ts similarity index 100% rename from components/relatorios/types.ts rename to src/features/reports/components/types.ts diff --git a/lib/relatorios/estabelecimentos/fetch-data.ts b/src/features/reports/establishments/queries.ts similarity index 96% rename from lib/relatorios/estabelecimentos/fetch-data.ts rename to src/features/reports/establishments/queries.ts index 2f33241..50031c1 100644 --- a/lib/relatorios/estabelecimentos/fetch-data.ts +++ b/src/features/reports/establishments/queries.ts @@ -17,11 +17,11 @@ import { categorias, contas, lancamentos, pagadores } from "@/db/schema"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX, INITIAL_BALANCE_NOTE, -} from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; -import { safeToNumber } from "@/lib/utils/number"; -import { getPreviousPeriod } from "@/lib/utils/period"; +} from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { safeToNumber } from "@/shared/utils/number"; +import { getPreviousPeriod } from "@/shared/utils/period"; const DESPESA = "Despesa"; const TRANSFERENCIA = "Transferência"; diff --git a/lib/relatorios/types.ts b/src/features/reports/types.ts similarity index 75% rename from lib/relatorios/types.ts rename to src/features/reports/types.ts index b59f437..fd7c1a0 100644 --- a/lib/relatorios/types.ts +++ b/src/features/reports/types.ts @@ -4,4 +4,4 @@ export type { CategoryReportItem, DateRangeValidation, MonthlyData, -} from "@/lib/types/relatorios"; +} from "@/shared/lib/types/reports"; diff --git a/lib/relatorios/utils.ts b/src/features/reports/utils.ts similarity index 92% rename from lib/relatorios/utils.ts rename to src/features/reports/utils.ts index 661e8c6..46c57ad 100644 --- a/lib/relatorios/utils.ts +++ b/src/features/reports/utils.ts @@ -1,11 +1,11 @@ -import type { DateRangeValidation } from "@/lib/types/relatorios"; -import { calculatePercentageChange } from "@/lib/utils/math"; -import { formatPercentageChange as formatPercentageChangeValue } from "@/lib/utils/percentage"; +import type { DateRangeValidation } from "@/shared/lib/types/reports"; +import { calculatePercentageChange } from "@/shared/utils/math"; +import { formatPercentageChange as formatPercentageChangeValue } from "@/shared/utils/percentage"; import { buildPeriodRange, formatShortPeriodLabel, parsePeriod, -} from "@/lib/utils/period"; +} from "@/shared/utils/period"; // Re-export for convenience export { calculatePercentageChange }; diff --git a/app/(dashboard)/ajustes/actions.ts b/src/features/settings/actions.ts similarity index 98% rename from app/(dashboard)/ajustes/actions.ts rename to src/features/settings/actions.ts index f1aeab6..0186873 100644 --- a/app/(dashboard)/ajustes/actions.ts +++ b/src/features/settings/actions.ts @@ -7,10 +7,10 @@ import { revalidatePath } from "next/cache"; import { headers } from "next/headers"; import { z } from "zod"; import { account, pagadores, tokensApi } from "@/db/schema"; -import { auth } from "@/lib/auth/config"; -import { db, schema } from "@/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; import { DEFAULT_FONT_KEY, FONT_KEYS } from "@/public/fonts/font_index"; +import { auth } from "@/shared/lib/auth/config"; +import { db, schema } from "@/shared/lib/db"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; type ActionResponse = { success: boolean; @@ -99,7 +99,7 @@ export async function updateNameAction( // Revalidar o layout do dashboard para atualizar a sidebar revalidatePath("/", "layout"); - revalidatePath("/pagadores"); + revalidatePath("/payers"); return { success: true, @@ -497,7 +497,7 @@ export async function createApiTokenAction( }) .returning({ id: tokensApi.id }); - revalidatePath("/ajustes"); + revalidatePath("/settings"); return { success: true, @@ -568,7 +568,7 @@ export async function revokeApiTokenAction( }) .where(eq(tokensApi.id, validated.tokenId)); - revalidatePath("/ajustes"); + revalidatePath("/settings"); return { success: true, diff --git a/components/ajustes/api-tokens-form.tsx b/src/features/settings/components/api-tokens-form.tsx similarity index 95% rename from components/ajustes/api-tokens-form.tsx rename to src/features/settings/components/api-tokens-form.tsx index 60d551d..1288fee 100644 --- a/components/ajustes/api-tokens-form.tsx +++ b/src/features/settings/components/api-tokens-form.tsx @@ -14,7 +14,7 @@ import { useState } from "react"; import { createApiTokenAction, revokeApiTokenAction, -} from "@/app/(dashboard)/ajustes/actions"; +} from "@/features/settings/actions"; import { AlertDialog, AlertDialogAction, @@ -24,9 +24,9 @@ import { AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, -} from "@/components/ui/alert-dialog"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +} from "@/shared/components/ui/alert-dialog"; +import { Badge } from "@/shared/components/ui/badge"; +import { Button } from "@/shared/components/ui/button"; import { Dialog, DialogContent, @@ -35,10 +35,10 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { formatDateTime } from "@/lib/utils/date"; +} from "@/shared/components/ui/dialog"; +import { Input } from "@/shared/components/ui/input"; +import { Label } from "@/shared/components/ui/label"; +import { formatDateTime } from "@/shared/utils/date"; interface ApiToken { id: string; diff --git a/components/ajustes/changelog-tab.tsx b/src/features/settings/components/changelog-tab.tsx similarity index 92% rename from components/ajustes/changelog-tab.tsx rename to src/features/settings/components/changelog-tab.tsx index e462af2..8390a04 100644 --- a/components/ajustes/changelog-tab.tsx +++ b/src/features/settings/components/changelog-tab.tsx @@ -1,7 +1,7 @@ import Link from "next/link"; -import { Badge } from "@/components/ui/badge"; -import { Card } from "@/components/ui/card"; -import type { ChangelogVersion } from "@/lib/changelog/parse-changelog"; +import type { ChangelogVersion } from "@/features/settings/lib/parse-changelog"; +import { Badge } from "@/shared/components/ui/badge"; +import { Card } from "@/shared/components/ui/card"; /** Converte "[texto](url)" em link; texto simples fica como está */ function parseContributorLine(content: string) { diff --git a/components/ajustes/companion-tab.tsx b/src/features/settings/components/companion-tab.tsx similarity index 98% rename from components/ajustes/companion-tab.tsx rename to src/features/settings/components/companion-tab.tsx index 1a80922..12c5828 100644 --- a/components/ajustes/companion-tab.tsx +++ b/src/features/settings/components/companion-tab.tsx @@ -9,7 +9,7 @@ import { RiShieldCheckLine, } from "@remixicon/react"; import type { ReactNode } from "react"; -import { Card } from "@/components/ui/card"; +import { Card } from "@/shared/components/ui/card"; import { ApiTokensForm } from "./api-tokens-form"; interface ApiToken { diff --git a/components/ajustes/delete-account-form.tsx b/src/features/settings/components/delete-account-form.tsx similarity index 90% rename from components/ajustes/delete-account-form.tsx rename to src/features/settings/components/delete-account-form.tsx index 06f6faa..43a373b 100644 --- a/components/ajustes/delete-account-form.tsx +++ b/src/features/settings/components/delete-account-form.tsx @@ -2,8 +2,8 @@ import { useRouter } from "next/navigation"; import { useState, useTransition } from "react"; import { toast } from "sonner"; -import { deleteAccountAction } from "@/app/(dashboard)/ajustes/actions"; -import { Button } from "@/components/ui/button"; +import { deleteAccountAction } from "@/features/settings/actions"; +import { Button } from "@/shared/components/ui/button"; import { Dialog, DialogContent, @@ -11,10 +11,10 @@ import { DialogFooter, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { authClient } from "@/lib/auth/client"; +} from "@/shared/components/ui/dialog"; +import { Input } from "@/shared/components/ui/input"; +import { Label } from "@/shared/components/ui/label"; +import { authClient } from "@/shared/lib/auth/client"; export function DeleteAccountForm() { const router = useRouter(); diff --git a/components/ajustes/passkeys-form.tsx b/src/features/settings/components/passkeys-form.tsx similarity index 97% rename from components/ajustes/passkeys-form.tsx rename to src/features/settings/components/passkeys-form.tsx index 8695e73..10f7130 100644 --- a/components/ajustes/passkeys-form.tsx +++ b/src/features/settings/components/passkeys-form.tsx @@ -20,8 +20,8 @@ import { AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, -} from "@/components/ui/alert-dialog"; -import { Button } from "@/components/ui/button"; +} from "@/shared/components/ui/alert-dialog"; +import { Button } from "@/shared/components/ui/button"; import { Dialog, DialogContent, @@ -30,10 +30,10 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { authClient } from "@/lib/auth/client"; +} from "@/shared/components/ui/dialog"; +import { Input } from "@/shared/components/ui/input"; +import { Label } from "@/shared/components/ui/label"; +import { authClient } from "@/shared/lib/auth/client"; interface Passkey { id: string; diff --git a/components/ajustes/preferences-form.tsx b/src/features/settings/components/preferences-form.tsx similarity index 94% rename from components/ajustes/preferences-form.tsx rename to src/features/settings/components/preferences-form.tsx index 706f355..e75748d 100644 --- a/components/ajustes/preferences-form.tsx +++ b/src/features/settings/components/preferences-form.tsx @@ -20,23 +20,23 @@ import { RiDragMove2Line } from "@remixicon/react"; import { useRouter } from "next/navigation"; import { useEffect, useState, useTransition } from "react"; import { toast } from "sonner"; -import { updatePreferencesAction } from "@/app/(dashboard)/ajustes/actions"; -import { useFont } from "@/components/providers/font-provider"; -import { Button } from "@/components/ui/button"; -import { Label } from "@/components/ui/label"; +import { updatePreferencesAction } from "@/features/settings/actions"; +import { + DEFAULT_LANCAMENTOS_COLUMN_ORDER, + LANCAMENTOS_COLUMN_LABELS, +} from "@/features/transactions/column-order"; +import { FONT_OPTIONS } from "@/public/fonts/font_index"; +import { useFont } from "@/shared/components/providers/font-provider"; +import { Button } from "@/shared/components/ui/button"; +import { Label } from "@/shared/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { Switch } from "@/components/ui/switch"; -import { - DEFAULT_LANCAMENTOS_COLUMN_ORDER, - LANCAMENTOS_COLUMN_LABELS, -} from "@/lib/lancamentos/column-order"; -import { FONT_OPTIONS } from "@/public/fonts/font_index"; +} from "@/shared/components/ui/select"; +import { Switch } from "@/shared/components/ui/switch"; interface PreferencesFormProps { extratoNoteAsColumn: boolean; diff --git a/components/ajustes/update-email-form.tsx b/src/features/settings/components/update-email-form.tsx similarity index 96% rename from components/ajustes/update-email-form.tsx rename to src/features/settings/components/update-email-form.tsx index de96a9e..c76cebf 100644 --- a/components/ajustes/update-email-form.tsx +++ b/src/features/settings/components/update-email-form.tsx @@ -8,10 +8,10 @@ import { } from "@remixicon/react"; import { useState, useTransition } from "react"; import { toast } from "sonner"; -import { updateEmailAction } from "@/app/(dashboard)/ajustes/actions"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; +import { updateEmailAction } from "@/features/settings/actions"; +import { Button } from "@/shared/components/ui/button"; +import { Input } from "@/shared/components/ui/input"; +import { Label } from "@/shared/components/ui/label"; type UpdateEmailFormProps = { currentEmail: string; diff --git a/components/ajustes/update-name-form.tsx b/src/features/settings/components/update-name-form.tsx similarity index 88% rename from components/ajustes/update-name-form.tsx rename to src/features/settings/components/update-name-form.tsx index 0606d39..6ea721e 100644 --- a/components/ajustes/update-name-form.tsx +++ b/src/features/settings/components/update-name-form.tsx @@ -2,10 +2,10 @@ import { useState, useTransition } from "react"; import { toast } from "sonner"; -import { updateNameAction } from "@/app/(dashboard)/ajustes/actions"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; +import { updateNameAction } from "@/features/settings/actions"; +import { Button } from "@/shared/components/ui/button"; +import { Input } from "@/shared/components/ui/input"; +import { Label } from "@/shared/components/ui/label"; type UpdateNameFormProps = { currentName: string; diff --git a/components/ajustes/update-password-form.tsx b/src/features/settings/components/update-password-form.tsx similarity index 97% rename from components/ajustes/update-password-form.tsx rename to src/features/settings/components/update-password-form.tsx index 514a6b0..e8a3321 100644 --- a/components/ajustes/update-password-form.tsx +++ b/src/features/settings/components/update-password-form.tsx @@ -9,11 +9,11 @@ import { } from "@remixicon/react"; import { useState, useTransition } from "react"; import { toast } from "sonner"; -import { updatePasswordAction } from "@/app/(dashboard)/ajustes/actions"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { cn } from "@/lib/utils/ui"; +import { updatePasswordAction } from "@/features/settings/actions"; +import { Button } from "@/shared/components/ui/button"; +import { Input } from "@/shared/components/ui/input"; +import { Label } from "@/shared/components/ui/label"; +import { cn } from "@/shared/utils/ui"; interface PasswordValidation { hasLowercase: boolean; diff --git a/lib/changelog/parse-changelog.ts b/src/features/settings/lib/parse-changelog.ts similarity index 100% rename from lib/changelog/parse-changelog.ts rename to src/features/settings/lib/parse-changelog.ts diff --git a/app/(dashboard)/ajustes/data.ts b/src/features/settings/queries.ts similarity index 97% rename from app/(dashboard)/ajustes/data.ts rename to src/features/settings/queries.ts index eaab79a..8d32fd1 100644 --- a/app/(dashboard)/ajustes/data.ts +++ b/src/features/settings/queries.ts @@ -1,7 +1,7 @@ import { desc, eq } from "drizzle-orm"; import { tokensApi } from "@/db/schema"; -import { db, schema } from "@/lib/db"; import { type FontKey, normalizeFontKey } from "@/public/fonts/font_index"; +import { db, schema } from "@/shared/lib/db"; export interface UserPreferences { extratoNoteAsColumn: boolean; diff --git a/app/(dashboard)/lancamentos/actions.ts b/src/features/transactions/actions.ts similarity index 92% rename from app/(dashboard)/lancamentos/actions.ts rename to src/features/transactions/actions.ts index dfc2173..4894086 100644 --- a/app/(dashboard)/lancamentos/actions.ts +++ b/src/features/transactions/actions.ts @@ -1,38 +1,46 @@ "use server"; import { randomUUID } from "node:crypto"; -import { and, asc, desc, eq, gte, inArray, sql } from "drizzle-orm"; +import { and, asc, eq, inArray, sql } from "drizzle-orm"; import { z } from "zod"; +import type { RecurringSeriesTemplate } from "@/db/schema"; import { cartoes, categorias, contas, lancamentos, pagadores, + recurringSeries, } from "@/db/schema"; -import { handleActionError, revalidateForEntity } from "@/lib/actions/helpers"; -import { getUser } from "@/lib/auth/server"; +import { + LANCAMENTO_CONDITIONS, + LANCAMENTO_PAYMENT_METHODS, + LANCAMENTO_TRANSACTION_TYPES, +} from "@/features/transactions/constants"; import { INITIAL_BALANCE_CONDITION, INITIAL_BALANCE_NOTE, INITIAL_BALANCE_PAYMENT_METHOD, INITIAL_BALANCE_TRANSACTION_TYPE, -} from "@/lib/contas/constants"; -import { db } from "@/lib/db"; +} from "@/shared/lib/accounts/constants"; import { - LANCAMENTO_CONDITIONS, - LANCAMENTO_PAYMENT_METHODS, - LANCAMENTO_TRANSACTION_TYPES, -} from "@/lib/lancamentos/constants"; + handleActionError, + revalidateForEntity, +} from "@/shared/lib/actions/helpers"; +import { getUser } from "@/shared/lib/auth/server"; +import { db } from "@/shared/lib/db"; import { buildEntriesByPagador, sendPagadorAutoEmails, -} from "@/lib/pagadores/notifications"; -import { noteSchema, uuidSchema } from "@/lib/schemas/common"; -import type { ActionResult } from "@/lib/types/actions"; -import { formatDecimalForDbRequired } from "@/lib/utils/currency"; -import { getBusinessTodayDate, parseLocalDateString } from "@/lib/utils/date"; -import { addMonthsToPeriod } from "@/lib/utils/period"; +} from "@/shared/lib/payers/notifications"; +import { noteSchema, uuidSchema } from "@/shared/lib/schemas/common"; +import type { ActionResult } from "@/shared/lib/types/actions"; +import { formatDecimalForDbRequired } from "@/shared/utils/currency"; +import { + getBusinessTodayDate, + parseLocalDateString, +} from "@/shared/utils/date"; +import { addMonthsToPeriod } from "@/shared/utils/period"; // ============================================================================ // Authorization Validation Functions @@ -226,22 +234,6 @@ const refineLancamento = ( } } - if (data.condition === "Recorrente") { - if (!data.recurrenceCount) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - path: ["recurrenceCount"], - message: "Informe por quantos meses a recorrência acontecerá.", - }); - } else if (data.recurrenceCount < 2) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - path: ["recurrenceCount"], - message: "A recorrência deve ter ao menos dois meses.", - }); - } - } - if (data.isSplit) { if (!data.pagadorId) { ctx.addIssue({ @@ -523,33 +515,23 @@ const buildLancamentoRecords = ({ } if (data.condition === "Recorrente") { - const recurrenceTotal = data.recurrenceCount ?? 0; - - for (let index = 0; index < recurrenceTotal; index += 1) { - const recurrencePeriod = addMonthsToPeriod(period, index); - const recurrencePurchaseDate = addMonthsToDate(purchaseDate, index); - const recurrenceDueDate = dueDate - ? addMonthsToDate(dueDate, index) - : null; - - shares.forEach((share) => { - const settled = resolveSettledValue(index); - records.push({ - ...basePayload, - amount: centsToDecimalString(share.amountCents * amountSign), - pagadorId: share.pagadorId, - purchaseDate: recurrencePurchaseDate, - period: recurrencePeriod, - isSettled: settled, - recurrenceCount: recurrenceTotal, - dueDate: recurrenceDueDate, - boletoPaymentDate: - data.paymentMethod === "Boleto" && settled - ? boletoPaymentDate - : null, - }); + // For the new recurring model, only create 1 row (the current month) + // Future rows will be generated lazily by generateRecurringTransactions + shares.forEach((share) => { + const settled = resolveSettledValue(0); + records.push({ + ...basePayload, + amount: centsToDecimalString(share.amountCents * amountSign), + pagadorId: share.pagadorId, + purchaseDate, + period, + isSettled: settled, + recurrenceCount: null, + dueDate, + boletoPaymentDate: + data.paymentMethod === "Boleto" && settled ? boletoPaymentDate : null, }); - } + }); return records; } @@ -677,6 +659,39 @@ export async function createLancamentoAction( } await db.transaction(async (tx: typeof db) => { + // If creating a recurring series, insert the series row first + if (data.condition === "Recorrente" && seriesId) { + const templateData: RecurringSeriesTemplate = { + name: data.name, + amount: centsToDecimalString( + Math.round(Math.abs(data.amount) * 100) * + (data.transactionType === "Despesa" ? -1 : 1), + ), + transactionType: data.transactionType, + paymentMethod: data.paymentMethod, + categoriaId: data.categoriaId ?? null, + contaId: data.contaId ?? null, + cartaoId: data.cartaoId ?? null, + pagadorId: data.pagadorId ?? null, + note: data.note ?? null, + condition: "Recorrente", + }; + + await tx.insert(recurringSeries).values({ + id: seriesId, + userId: user.id, + status: "active", + dayOfMonth: purchaseDate.getDate(), + lastGeneratedPeriod: period, + templateData, + }); + + // Link lancamento records to the recurring series + for (const record of records) { + record.recurringSeriesId = seriesId; + } + } + await tx.insert(lancamentos).values(records); }); @@ -1625,46 +1640,3 @@ export async function deleteMultipleLancamentosAction( return handleActionError(error); } } - -// Get unique establishment names from the last 3 months -export async function getRecentEstablishmentsAction(): Promise { - try { - const user = await getUser(); - - // Calculate date 3 months ago - const threeMonthsAgo = new Date(); - threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3); - - // Fetch establishment names from the last 3 months - const results = await db - .select({ name: lancamentos.name }) - .from(lancamentos) - .where( - and( - eq(lancamentos.userId, user.id), - gte(lancamentos.purchaseDate, threeMonthsAgo), - ), - ) - .orderBy(desc(lancamentos.purchaseDate)); - - // Remove duplicates and filter empty names - const uniqueNames = Array.from( - new Set( - results - .map((r: (typeof results)[number]) => r.name) - .filter( - (name: string | null): name is string => - name != null && - name.trim().length > 0 && - !name.toLowerCase().startsWith("pagamento fatura"), - ), - ), - ); - - // Return top 50 most recent unique establishments - return uniqueNames.slice(0, 100); - } catch (error) { - console.error("Error fetching recent establishments:", error); - return []; - } -} diff --git a/app/(dashboard)/lancamentos/anticipation-actions.ts b/src/features/transactions/anticipation-actions.ts similarity index 94% rename from app/(dashboard)/lancamentos/anticipation-actions.ts rename to src/features/transactions/anticipation-actions.ts index 4f9d288..fd5590f 100644 --- a/app/(dashboard)/lancamentos/anticipation-actions.ts +++ b/src/features/transactions/anticipation-actions.ts @@ -8,22 +8,25 @@ import { lancamentos, pagadores, } from "@/db/schema"; -import { handleActionError, revalidateForEntity } from "@/lib/actions/helpers"; -import type { ActionResult } from "@/lib/types/actions"; -import { getUser } from "@/lib/auth/server"; -import { db } from "@/lib/db"; +import { + handleActionError, + revalidateForEntity, +} from "@/shared/lib/actions/helpers"; +import { getUser } from "@/shared/lib/auth/server"; +import { db } from "@/shared/lib/db"; import { generateAnticipationDescription, generateAnticipationNote, -} from "@/lib/installments/anticipation-helpers"; +} from "@/shared/lib/installments/anticipation-helpers"; import type { - InstallmentAnticipationWithRelations, CancelAnticipationInput, CreateAnticipationInput, EligibleInstallment, -} from "@/lib/installments/anticipation-types"; -import { uuidSchema } from "@/lib/schemas/common"; -import { formatDecimalForDbRequired } from "@/lib/utils/currency"; + InstallmentAnticipationWithRelations, +} from "@/shared/lib/installments/anticipation-types"; +import { uuidSchema } from "@/shared/lib/schemas/common"; +import type { ActionResult } from "@/shared/lib/types/actions"; +import { formatDecimalForDbRequired } from "@/shared/utils/currency"; /** * Schema de validação para criar antecipação @@ -94,7 +97,7 @@ export async function getEligibleInstallmentsAction( }, }); - const eligibleInstallments: EligibleInstallment[] = rows.map((row: any) => ({ + const eligibleInstallments: EligibleInstallment[] = rows.map((row) => ({ id: row.id, name: row.name, amount: row.amount, @@ -155,7 +158,7 @@ export async function createInstallmentAnticipationAction( // 2. Calcular valor total const totalAmountCents = installments.reduce( - (sum: number, inst: any) => sum + Number(inst.amount) * 100, + (sum, inst) => sum + Number(inst.amount) * 100, 0, ); const totalAmount = totalAmountCents / 100; @@ -182,7 +185,7 @@ export async function createInstallmentAnticipationAction( const firstInstallment = installments[0]; // 4. Criar lançamento e antecipação em transação - await db.transaction(async (tx: any) => { + await db.transaction(async (tx: typeof db) => { // 4.1. Criar o lançamento de antecipação (com desconto aplicado) const [newLancamento] = await tx .insert(lancamentos) @@ -206,7 +209,7 @@ export async function createInstallmentAnticipationAction( note: data.note || generateAnticipationNote( - installments.map((inst: any) => ({ + installments.map((inst) => ({ id: inst.id, name: inst.name, amount: inst.amount, @@ -334,9 +337,9 @@ export async function getInstallmentAnticipationsAction( data: anticipations, }; } catch (error) { - return handleActionError( - error, - ) as ActionResult; + return handleActionError(error) as ActionResult< + InstallmentAnticipationWithRelations[] + >; } } @@ -351,7 +354,7 @@ export async function cancelInstallmentAnticipationAction( const user = await getUser(); const data = cancelAnticipationSchema.parse(input); - await db.transaction(async (tx: any) => { + await db.transaction(async (tx: typeof db) => { // 1. Buscar antecipação usando query builder const anticipationRows = await tx .select({ diff --git a/lib/lancamentos/categoria-helpers.ts b/src/features/transactions/categoria-helpers.ts similarity index 87% rename from lib/lancamentos/categoria-helpers.ts rename to src/features/transactions/categoria-helpers.ts index 82741cc..855c0aa 100644 --- a/lib/lancamentos/categoria-helpers.ts +++ b/src/features/transactions/categoria-helpers.ts @@ -1,13 +1,5 @@ -import type { SelectOption } from "@/components/lancamentos/types"; - -/** - * Capitalizes the first letter of a string - */ -function capitalize(value: string): string { - return value.length > 0 - ? value[0]?.toUpperCase().concat(value.slice(1)) - : value; -} +import type { SelectOption } from "@/features/transactions/components/types"; +import { capitalize } from "@/shared/utils/string"; /** * Group label for categorias diff --git a/lib/lancamentos/column-order.ts b/src/features/transactions/column-order.ts similarity index 100% rename from lib/lancamentos/column-order.ts rename to src/features/transactions/column-order.ts diff --git a/components/lancamentos/dialogs/anticipate-installments-dialog/anticipate-installments-dialog.tsx b/src/features/transactions/components/dialogs/anticipate-installments-dialog/anticipate-installments-dialog.tsx similarity index 93% rename from components/lancamentos/dialogs/anticipate-installments-dialog/anticipate-installments-dialog.tsx rename to src/features/transactions/components/dialogs/anticipate-installments-dialog/anticipate-installments-dialog.tsx index 5e3c5a5..2dbe6d7 100644 --- a/components/lancamentos/dialogs/anticipate-installments-dialog/anticipate-installments-dialog.tsx +++ b/src/features/transactions/components/dialogs/anticipate-installments-dialog/anticipate-installments-dialog.tsx @@ -3,15 +3,15 @@ import { RiLoader4Line } from "@remixicon/react"; import { useEffect, useMemo, useState, useTransition } from "react"; import { toast } from "sonner"; +import { CategoryIcon } from "@/features/categories/components/category-icon"; import { createInstallmentAnticipationAction, getEligibleInstallmentsAction, -} from "@/app/(dashboard)/lancamentos/anticipation-actions"; -import { CategoryIcon } from "@/components/categorias/category-icon"; -import MoneyValues from "@/components/shared/money-values"; -import { PeriodPicker } from "@/components/shared/period-picker"; -import { Button } from "@/components/ui/button"; -import { CurrencyInput } from "@/components/ui/currency-input"; +} from "@/features/transactions/anticipation-actions"; +import MoneyValues from "@/shared/components/money-values"; +import { PeriodPicker } from "@/shared/components/period-picker"; +import { Button } from "@/shared/components/ui/button"; +import { CurrencyInput } from "@/shared/components/ui/currency-input"; import { Dialog, DialogContent, @@ -20,25 +20,25 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; +} from "@/shared/components/ui/dialog"; import { Field, FieldContent, FieldGroup, FieldLabel, FieldLegend, -} from "@/components/ui/field"; +} from "@/shared/components/ui/field"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { Textarea } from "@/components/ui/textarea"; -import { useControlledState } from "@/lib/hooks/use-controlled-state"; -import { useFormState } from "@/lib/hooks/use-form-state"; -import type { EligibleInstallment } from "@/lib/installments/anticipation-types"; +} from "@/shared/components/ui/select"; +import { Textarea } from "@/shared/components/ui/textarea"; +import { useControlledState } from "@/shared/hooks/use-controlled-state"; +import { useFormState } from "@/shared/hooks/use-form-state"; +import type { EligibleInstallment } from "@/shared/lib/installments/anticipation-types"; import { InstallmentSelectionTable } from "./installment-selection-table"; interface AnticipateInstallmentsDialogProps { diff --git a/components/lancamentos/dialogs/anticipate-installments-dialog/anticipation-history-dialog.tsx b/src/features/transactions/components/dialogs/anticipate-installments-dialog/anticipation-history-dialog.tsx similarity index 91% rename from components/lancamentos/dialogs/anticipate-installments-dialog/anticipation-history-dialog.tsx rename to src/features/transactions/components/dialogs/anticipate-installments-dialog/anticipation-history-dialog.tsx index 87c575f..3a157e1 100644 --- a/components/lancamentos/dialogs/anticipate-installments-dialog/anticipation-history-dialog.tsx +++ b/src/features/transactions/components/dialogs/anticipate-installments-dialog/anticipation-history-dialog.tsx @@ -3,7 +3,7 @@ import { RiCalendarCheckLine, RiLoader4Line } from "@remixicon/react"; import { useCallback, useEffect, useState } from "react"; import { toast } from "sonner"; -import { getInstallmentAnticipationsAction } from "@/app/(dashboard)/lancamentos/anticipation-actions"; +import { getInstallmentAnticipationsAction } from "@/features/transactions/anticipation-actions"; import { Dialog, DialogContent, @@ -11,16 +11,16 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; +} from "@/shared/components/ui/dialog"; import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, -} from "@/components/ui/empty"; -import { useControlledState } from "@/lib/hooks/use-controlled-state"; -import type { InstallmentAnticipationWithRelations } from "@/lib/installments/anticipation-types"; +} from "@/shared/components/ui/empty"; +import { useControlledState } from "@/shared/hooks/use-controlled-state"; +import type { InstallmentAnticipationWithRelations } from "@/shared/lib/installments/anticipation-types"; import { AnticipationCard } from "../../shared/anticipation-card"; interface AnticipationHistoryDialogProps { diff --git a/components/lancamentos/dialogs/anticipate-installments-dialog/installment-selection-table.tsx b/src/features/transactions/components/dialogs/anticipate-installments-dialog/installment-selection-table.tsx similarity index 89% rename from components/lancamentos/dialogs/anticipate-installments-dialog/installment-selection-table.tsx rename to src/features/transactions/components/dialogs/anticipate-installments-dialog/installment-selection-table.tsx index f1437fb..0f102e6 100644 --- a/components/lancamentos/dialogs/anticipate-installments-dialog/installment-selection-table.tsx +++ b/src/features/transactions/components/dialogs/anticipate-installments-dialog/installment-selection-table.tsx @@ -2,9 +2,9 @@ import { format } from "date-fns"; import { ptBR } from "date-fns/locale"; -import MoneyValues from "@/components/shared/money-values"; -import { Badge } from "@/components/ui/badge"; -import { Checkbox } from "@/components/ui/checkbox"; +import MoneyValues from "@/shared/components/money-values"; +import { Badge } from "@/shared/components/ui/badge"; +import { Checkbox } from "@/shared/components/ui/checkbox"; import { Table, TableBody, @@ -12,11 +12,11 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; -import type { EligibleInstallment } from "@/lib/installments/anticipation-types"; -import { formatCurrentInstallment } from "@/lib/installments/utils"; -import { formatShortPeriodLabel } from "@/lib/utils/period"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/table"; +import type { EligibleInstallment } from "@/shared/lib/installments/anticipation-types"; +import { formatCurrentInstallment } from "@/shared/lib/installments/utils"; +import { formatShortPeriodLabel } from "@/shared/utils/period"; +import { cn } from "@/shared/utils/ui"; interface InstallmentSelectionTableProps { installments: EligibleInstallment[]; diff --git a/components/lancamentos/dialogs/bulk-action-dialog.tsx b/src/features/transactions/components/dialogs/bulk-action-dialog.tsx similarity index 94% rename from components/lancamentos/dialogs/bulk-action-dialog.tsx rename to src/features/transactions/components/dialogs/bulk-action-dialog.tsx index 0d9aed6..f3ebb4d 100644 --- a/components/lancamentos/dialogs/bulk-action-dialog.tsx +++ b/src/features/transactions/components/dialogs/bulk-action-dialog.tsx @@ -1,7 +1,7 @@ "use client"; import { useState } from "react"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/shared/components/ui/button"; import { Dialog, DialogContent, @@ -9,9 +9,9 @@ import { DialogFooter, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import { Label } from "@/components/ui/label"; -import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +} from "@/shared/components/ui/dialog"; +import { Label } from "@/shared/components/ui/label"; +import { RadioGroup, RadioGroupItem } from "@/shared/components/ui/radio-group"; export type BulkActionScope = "current" | "future" | "all"; diff --git a/components/lancamentos/dialogs/bulk-import-dialog.tsx b/src/features/transactions/components/dialogs/bulk-import-dialog.tsx similarity index 96% rename from components/lancamentos/dialogs/bulk-import-dialog.tsx rename to src/features/transactions/components/dialogs/bulk-import-dialog.tsx index ec6eda6..c488466 100644 --- a/components/lancamentos/dialogs/bulk-import-dialog.tsx +++ b/src/features/transactions/components/dialogs/bulk-import-dialog.tsx @@ -2,8 +2,9 @@ import { useMemo, useState, useTransition } from "react"; import { toast } from "sonner"; -import { createLancamentoAction } from "@/app/(dashboard)/lancamentos/actions"; -import { Button } from "@/components/ui/button"; +import { createLancamentoAction } from "@/features/transactions/actions"; +import { groupAndSortCategorias } from "@/features/transactions/categoria-helpers"; +import { Button } from "@/shared/components/ui/button"; import { Dialog, DialogContent, @@ -11,8 +12,8 @@ import { DialogFooter, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import { Label } from "@/components/ui/label"; +} from "@/shared/components/ui/dialog"; +import { Label } from "@/shared/components/ui/label"; import { Select, SelectContent, @@ -21,8 +22,7 @@ import { SelectLabel, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { groupAndSortCategorias } from "@/lib/lancamentos/categoria-helpers"; +} from "@/shared/components/ui/select"; import { CategoriaSelectContent, ContaCartaoSelectContent, diff --git a/components/lancamentos/dialogs/mass-add-dialog.tsx b/src/features/transactions/components/dialogs/mass-add-dialog.tsx similarity index 94% rename from components/lancamentos/dialogs/mass-add-dialog.tsx rename to src/features/transactions/components/dialogs/mass-add-dialog.tsx index 17bebb0..e21b5c4 100644 --- a/components/lancamentos/dialogs/mass-add-dialog.tsx +++ b/src/features/transactions/components/dialogs/mass-add-dialog.tsx @@ -3,9 +3,14 @@ import { RiAddLine, RiDeleteBinLine } from "@remixicon/react"; import { useMemo, useState } from "react"; import { toast } from "sonner"; -import { Button } from "@/components/ui/button"; -import { CurrencyInput } from "@/components/ui/currency-input"; -import { DatePicker } from "@/components/ui/date-picker"; +import { groupAndSortCategorias } from "@/features/transactions/categoria-helpers"; +import { + LANCAMENTO_PAYMENT_METHODS, + type LANCAMENTO_TRANSACTION_TYPES, +} from "@/features/transactions/constants"; +import { Button } from "@/shared/components/ui/button"; +import { CurrencyInput } from "@/shared/components/ui/currency-input"; +import { DatePicker } from "@/shared/components/ui/date-picker"; import { Dialog, DialogContent, @@ -13,14 +18,14 @@ import { DialogFooter, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import { Label } from "@/components/ui/label"; -import { MonthPicker } from "@/components/ui/month-picker"; +} from "@/shared/components/ui/dialog"; +import { Label } from "@/shared/components/ui/label"; +import { MonthPicker } from "@/shared/components/ui/month-picker"; import { Popover, PopoverContent, PopoverTrigger, -} from "@/components/ui/popover"; +} from "@/shared/components/ui/popover"; import { Select, SelectContent, @@ -29,16 +34,15 @@ import { SelectLabel, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { Separator } from "@/components/ui/separator"; -import { Spinner } from "@/components/ui/spinner"; -import { groupAndSortCategorias } from "@/lib/lancamentos/categoria-helpers"; +} from "@/shared/components/ui/select"; +import { Separator } from "@/shared/components/ui/separator"; +import { Spinner } from "@/shared/components/ui/spinner"; +import { getTodayDateString } from "@/shared/utils/date"; import { - LANCAMENTO_PAYMENT_METHODS, - type LANCAMENTO_TRANSACTION_TYPES, -} from "@/lib/lancamentos/constants"; -import { getTodayDateString } from "@/lib/utils/date"; -import { dateToPeriod, displayPeriod, periodToDate } from "@/lib/utils/period"; + dateToPeriod, + displayPeriod, + periodToDate, +} from "@/shared/utils/period"; import { CategoriaSelectContent, ContaCartaoSelectContent, @@ -46,7 +50,7 @@ import { PaymentMethodSelectContent, TransactionTypeSelectContent, } from "../select-items"; -import { EstabelecimentoInput } from "../shared/estabelecimento-input"; +import { EstabelecimentoInput } from "../shared/establishment-input"; import type { SelectOption } from "../types"; /** Payment methods sem Boleto para este modal */ @@ -106,7 +110,7 @@ interface MassAddDialogProps { } export type MassAddFormData = Parameters< - typeof import("@/app/(dashboard)/lancamentos/actions").createMassLancamentosAction + typeof import("@/features/transactions/actions").createMassLancamentosAction >[0]; interface TransactionRow { diff --git a/components/lancamentos/dialogs/lancamento-details-dialog.tsx b/src/features/transactions/components/dialogs/transaction-details-dialog.tsx similarity index 92% rename from components/lancamentos/dialogs/lancamento-details-dialog.tsx rename to src/features/transactions/components/dialogs/transaction-details-dialog.tsx index a6d3777..614d2a1 100644 --- a/components/lancamentos/dialogs/lancamento-details-dialog.tsx +++ b/src/features/transactions/components/dialogs/transaction-details-dialog.tsx @@ -1,25 +1,29 @@ "use client"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { CardContent, CardDescription, CardHeader } from "@/components/ui/card"; -import { - Dialog, - DialogClose, - DialogContent, - DialogFooter, - DialogTitle, -} from "@/components/ui/dialog"; -import { Separator } from "@/components/ui/separator"; import { currencyFormatter, formatCondition, formatDate, formatPeriod, getTransactionBadgeVariant, -} from "@/lib/lancamentos/formatting-helpers"; -import { parseLocalDateString } from "@/lib/utils/date"; -import { getPaymentMethodIcon } from "@/lib/utils/icons"; +} from "@/features/transactions/formatting-helpers"; +import { Badge } from "@/shared/components/ui/badge"; +import { Button } from "@/shared/components/ui/button"; +import { + CardContent, + CardDescription, + CardHeader, +} from "@/shared/components/ui/card"; +import { + Dialog, + DialogClose, + DialogContent, + DialogFooter, + DialogTitle, +} from "@/shared/components/ui/dialog"; +import { Separator } from "@/shared/components/ui/separator"; +import { parseLocalDateString } from "@/shared/utils/date"; +import { getPaymentMethodIcon } from "@/shared/utils/icons"; import { InstallmentTimeline } from "../shared/installment-timeline"; import type { LancamentoItem } from "../types"; diff --git a/components/lancamentos/dialogs/lancamento-dialog/basic-fields-section.tsx b/src/features/transactions/components/dialogs/transaction-dialog/basic-fields-section.tsx similarity index 79% rename from components/lancamentos/dialogs/lancamento-dialog/basic-fields-section.tsx rename to src/features/transactions/components/dialogs/transaction-dialog/basic-fields-section.tsx index 765ffe0..0eb36d1 100644 --- a/components/lancamentos/dialogs/lancamento-dialog/basic-fields-section.tsx +++ b/src/features/transactions/components/dialogs/transaction-dialog/basic-fields-section.tsx @@ -1,12 +1,12 @@ "use client"; import { RiCalculatorLine } from "@remixicon/react"; -import { CalculatorDialogButton } from "@/components/calculadora/calculator-dialog"; -import { CurrencyInput } from "@/components/ui/currency-input"; -import { DatePicker } from "@/components/ui/date-picker"; -import { Label } from "@/components/ui/label"; -import { EstabelecimentoInput } from "../../shared/estabelecimento-input"; -import type { BasicFieldsSectionProps } from "./lancamento-dialog-types"; +import { CalculatorDialogButton } from "@/shared/components/calculator/calculator-dialog"; +import { CurrencyInput } from "@/shared/components/ui/currency-input"; +import { DatePicker } from "@/shared/components/ui/date-picker"; +import { Label } from "@/shared/components/ui/label"; +import { EstabelecimentoInput } from "../../shared/establishment-input"; +import type { BasicFieldsSectionProps } from "./transaction-dialog-types"; export function BasicFieldsSection({ formState, diff --git a/components/lancamentos/dialogs/lancamento-dialog/boleto-fields-section.tsx b/src/features/transactions/components/dialogs/transaction-dialog/boleto-fields-section.tsx similarity index 80% rename from components/lancamentos/dialogs/lancamento-dialog/boleto-fields-section.tsx rename to src/features/transactions/components/dialogs/transaction-dialog/boleto-fields-section.tsx index 5a94ef3..bcccb78 100644 --- a/components/lancamentos/dialogs/lancamento-dialog/boleto-fields-section.tsx +++ b/src/features/transactions/components/dialogs/transaction-dialog/boleto-fields-section.tsx @@ -1,9 +1,9 @@ "use client"; -import { DatePicker } from "@/components/ui/date-picker"; -import { Label } from "@/components/ui/label"; -import { cn } from "@/lib/utils/ui"; -import type { BoletoFieldsSectionProps } from "./lancamento-dialog-types"; +import { DatePicker } from "@/shared/components/ui/date-picker"; +import { Label } from "@/shared/components/ui/label"; +import { cn } from "@/shared/utils/ui"; +import type { BoletoFieldsSectionProps } from "./transaction-dialog-types"; export function BoletoFieldsSection({ formState, diff --git a/components/lancamentos/dialogs/lancamento-dialog/category-section.tsx b/src/features/transactions/components/dialogs/transaction-dialog/category-section.tsx similarity index 90% rename from components/lancamentos/dialogs/lancamento-dialog/category-section.tsx rename to src/features/transactions/components/dialogs/transaction-dialog/category-section.tsx index 7256144..5c780b5 100644 --- a/components/lancamentos/dialogs/lancamento-dialog/category-section.tsx +++ b/src/features/transactions/components/dialogs/transaction-dialog/category-section.tsx @@ -1,6 +1,7 @@ "use client"; -import { Label } from "@/components/ui/label"; +import { LANCAMENTO_TRANSACTION_TYPES } from "@/features/transactions/constants"; +import { Label } from "@/shared/components/ui/label"; import { Select, SelectContent, @@ -9,14 +10,13 @@ import { SelectLabel, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { LANCAMENTO_TRANSACTION_TYPES } from "@/lib/lancamentos/constants"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/select"; +import { cn } from "@/shared/utils/ui"; import { CategoriaSelectContent, TransactionTypeSelectContent, } from "../../select-items"; -import type { CategorySectionProps } from "./lancamento-dialog-types"; +import type { CategorySectionProps } from "./transaction-dialog-types"; export function CategorySection({ formState, diff --git a/components/lancamentos/dialogs/lancamento-dialog/condition-section.tsx b/src/features/transactions/components/dialogs/transaction-dialog/condition-section.tsx similarity index 69% rename from components/lancamentos/dialogs/lancamento-dialog/condition-section.tsx rename to src/features/transactions/components/dialogs/transaction-dialog/condition-section.tsx index d60c7a7..777b9a9 100644 --- a/components/lancamentos/dialogs/lancamento-dialog/condition-section.tsx +++ b/src/features/transactions/components/dialogs/transaction-dialog/condition-section.tsx @@ -1,18 +1,18 @@ "use client"; -import { Label } from "@/components/ui/label"; +import { LANCAMENTO_CONDITIONS } from "@/features/transactions/constants"; +import { Label } from "@/shared/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { LANCAMENTO_CONDITIONS } from "@/lib/lancamentos/constants"; -import { formatCurrency } from "@/lib/utils/currency"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/select"; +import { formatCurrency } from "@/shared/utils/currency"; +import { cn } from "@/shared/utils/ui"; import { ConditionSelectContent } from "../../select-items"; -import type { ConditionSectionProps } from "./lancamento-dialog-types"; +import type { ConditionSectionProps } from "./transaction-dialog-types"; export function ConditionSection({ formState, @@ -43,15 +43,6 @@ export function ConditionSection({ ? getInstallmentLabel(installmentCount) : null; - const recurrenceCount = Number(formState.recurrenceCount); - const recurrenceSummary = - showRecurrence && - formState.recurrenceCount && - !Number.isNaN(recurrenceCount) && - recurrenceCount > 0 - ? `Por ${recurrenceCount} meses` - : null; - return (
- - + Este lançamento será repetido todo mês automaticamente até ser + pausado ou cancelado. +

) : null}
diff --git a/components/lancamentos/dialogs/lancamento-dialog/note-section.tsx b/src/features/transactions/components/dialogs/transaction-dialog/note-section.tsx similarity index 70% rename from components/lancamentos/dialogs/lancamento-dialog/note-section.tsx rename to src/features/transactions/components/dialogs/transaction-dialog/note-section.tsx index c2fa9ae..1acb52c 100644 --- a/components/lancamentos/dialogs/lancamento-dialog/note-section.tsx +++ b/src/features/transactions/components/dialogs/transaction-dialog/note-section.tsx @@ -1,8 +1,8 @@ "use client"; -import { Label } from "@/components/ui/label"; -import { Textarea } from "@/components/ui/textarea"; -import type { NoteSectionProps } from "./lancamento-dialog-types"; +import { Label } from "@/shared/components/ui/label"; +import { Textarea } from "@/shared/components/ui/textarea"; +import type { NoteSectionProps } from "./transaction-dialog-types"; export function NoteSection({ formState, onFieldChange }: NoteSectionProps) { return ( diff --git a/components/lancamentos/dialogs/lancamento-dialog/pagador-section.tsx b/src/features/transactions/components/dialogs/transaction-dialog/pagador-section.tsx similarity index 94% rename from components/lancamentos/dialogs/lancamento-dialog/pagador-section.tsx rename to src/features/transactions/components/dialogs/transaction-dialog/pagador-section.tsx index d9405fc..45ae36e 100644 --- a/components/lancamentos/dialogs/lancamento-dialog/pagador-section.tsx +++ b/src/features/transactions/components/dialogs/transaction-dialog/pagador-section.tsx @@ -1,16 +1,16 @@ "use client"; -import { CurrencyInput } from "@/components/ui/currency-input"; -import { Label } from "@/components/ui/label"; +import { CurrencyInput } from "@/shared/components/ui/currency-input"; +import { Label } from "@/shared/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; +} from "@/shared/components/ui/select"; import { PagadorSelectContent } from "../../select-items"; -import type { PagadorSectionProps } from "./lancamento-dialog-types"; +import type { PagadorSectionProps } from "./transaction-dialog-types"; export function PagadorSection({ formState, diff --git a/components/lancamentos/dialogs/lancamento-dialog/payment-method-section.tsx b/src/features/transactions/components/dialogs/transaction-dialog/payment-method-section.tsx similarity index 95% rename from components/lancamentos/dialogs/lancamento-dialog/payment-method-section.tsx rename to src/features/transactions/components/dialogs/transaction-dialog/payment-method-section.tsx index 005046b..b8ad40c 100644 --- a/components/lancamentos/dialogs/lancamento-dialog/payment-method-section.tsx +++ b/src/features/transactions/components/dialogs/transaction-dialog/payment-method-section.tsx @@ -1,28 +1,32 @@ "use client"; import { useState } from "react"; -import { Label } from "@/components/ui/label"; -import { MonthPicker } from "@/components/ui/month-picker"; +import { LANCAMENTO_PAYMENT_METHODS } from "@/features/transactions/constants"; +import { Label } from "@/shared/components/ui/label"; +import { MonthPicker } from "@/shared/components/ui/month-picker"; import { Popover, PopoverContent, PopoverTrigger, -} from "@/components/ui/popover"; +} from "@/shared/components/ui/popover"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { LANCAMENTO_PAYMENT_METHODS } from "@/lib/lancamentos/constants"; -import { dateToPeriod, displayPeriod, periodToDate } from "@/lib/utils/period"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/select"; +import { + dateToPeriod, + displayPeriod, + periodToDate, +} from "@/shared/utils/period"; +import { cn } from "@/shared/utils/ui"; import { ContaCartaoSelectContent, PaymentMethodSelectContent, } from "../../select-items"; -import type { PaymentMethodSectionProps } from "./lancamento-dialog-types"; +import type { PaymentMethodSectionProps } from "./transaction-dialog-types"; function InlinePeriodPicker({ period, diff --git a/components/lancamentos/dialogs/lancamento-dialog/split-settlement-section.tsx b/src/features/transactions/components/dialogs/transaction-dialog/split-settlement-section.tsx similarity index 88% rename from components/lancamentos/dialogs/lancamento-dialog/split-settlement-section.tsx rename to src/features/transactions/components/dialogs/transaction-dialog/split-settlement-section.tsx index 818c130..0edac5a 100644 --- a/components/lancamentos/dialogs/lancamento-dialog/split-settlement-section.tsx +++ b/src/features/transactions/components/dialogs/transaction-dialog/split-settlement-section.tsx @@ -1,8 +1,8 @@ "use client"; -import { Checkbox } from "@/components/ui/checkbox"; -import { cn } from "@/lib/utils/ui"; -import type { SplitAndSettlementSectionProps } from "./lancamento-dialog-types"; +import { Checkbox } from "@/shared/components/ui/checkbox"; +import { cn } from "@/shared/utils/ui"; +import type { SplitAndSettlementSectionProps } from "./transaction-dialog-types"; export function SplitAndSettlementSection({ formState, diff --git a/components/lancamentos/dialogs/lancamento-dialog/lancamento-dialog-types.ts b/src/features/transactions/components/dialogs/transaction-dialog/transaction-dialog-types.ts similarity index 97% rename from components/lancamentos/dialogs/lancamento-dialog/lancamento-dialog-types.ts rename to src/features/transactions/components/dialogs/transaction-dialog/transaction-dialog-types.ts index a109b06..6993115 100644 --- a/components/lancamentos/dialogs/lancamento-dialog/lancamento-dialog-types.ts +++ b/src/features/transactions/components/dialogs/transaction-dialog/transaction-dialog-types.ts @@ -1,4 +1,4 @@ -import type { LancamentoFormState } from "@/lib/lancamentos/form-helpers"; +import type { LancamentoFormState } from "@/features/transactions/form-helpers"; import type { LancamentoItem, SelectOption } from "../../types"; export type FormState = LancamentoFormState; diff --git a/components/lancamentos/dialogs/lancamento-dialog/lancamento-dialog.tsx b/src/features/transactions/components/dialogs/transaction-dialog/transaction-dialog.tsx similarity index 96% rename from components/lancamentos/dialogs/lancamento-dialog/lancamento-dialog.tsx rename to src/features/transactions/components/dialogs/transaction-dialog/transaction-dialog.tsx index d5f28b5..1b9cb0b 100644 --- a/components/lancamentos/dialogs/lancamento-dialog/lancamento-dialog.tsx +++ b/src/features/transactions/components/dialogs/transaction-dialog/transaction-dialog.tsx @@ -5,13 +5,22 @@ import { toast } from "sonner"; import { createLancamentoAction, updateLancamentoAction, -} from "@/app/(dashboard)/lancamentos/actions"; -import { Button } from "@/components/ui/button"; +} from "@/features/transactions/actions"; +import { + filterSecondaryPagadorOptions, + groupAndSortCategorias, +} from "@/features/transactions/categoria-helpers"; +import { + applyFieldDependencies, + buildLancamentoInitialState, + deriveCreditCardPeriod, +} from "@/features/transactions/form-helpers"; +import { Button } from "@/shared/components/ui/button"; import { Collapsible, CollapsibleContent, CollapsibleTrigger, -} from "@/components/ui/collapsible"; +} from "@/shared/components/ui/collapsible"; import { Dialog, DialogContent, @@ -20,29 +29,20 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; -import { useControlledState } from "@/lib/hooks/use-controlled-state"; -import { - filterSecondaryPagadorOptions, - groupAndSortCategorias, -} from "@/lib/lancamentos/categoria-helpers"; -import { - applyFieldDependencies, - buildLancamentoInitialState, - deriveCreditCardPeriod, -} from "@/lib/lancamentos/form-helpers"; +} from "@/shared/components/ui/dialog"; +import { useControlledState } from "@/shared/hooks/use-controlled-state"; import { BasicFieldsSection } from "./basic-fields-section"; import { BoletoFieldsSection } from "./boleto-fields-section"; import { CategorySection } from "./category-section"; import { ConditionSection } from "./condition-section"; -import type { - FormState, - LancamentoDialogProps, -} from "./lancamento-dialog-types"; import { NoteSection } from "./note-section"; import { PagadorSection } from "./pagador-section"; import { PaymentMethodSection } from "./payment-method-section"; import { SplitAndSettlementSection } from "./split-settlement-section"; +import type { + FormState, + LancamentoDialogProps, +} from "./transaction-dialog-types"; export function LancamentoDialog({ mode, @@ -294,10 +294,7 @@ export function LancamentoDialog({ formState.condition === "Parcelado" && formState.installmentCount ? Number(formState.installmentCount) : undefined, - recurrenceCount: - formState.condition === "Recorrente" && formState.recurrenceCount - ? Number(formState.recurrenceCount) - : undefined, + recurrenceCount: undefined, dueDate: formState.paymentMethod === "Boleto" && formState.dueDate ? formState.dueDate diff --git a/components/lancamentos/page/lancamentos-page.tsx b/src/features/transactions/components/page/transactions-page.tsx similarity index 98% rename from components/lancamentos/page/lancamentos-page.tsx rename to src/features/transactions/components/page/transactions-page.tsx index 355ce0e..e85434e 100644 --- a/components/lancamentos/page/lancamentos-page.tsx +++ b/src/features/transactions/components/page/transactions-page.tsx @@ -9,8 +9,8 @@ import { deleteMultipleLancamentosAction, toggleLancamentoSettlementAction, updateLancamentoBulkAction, -} from "@/app/(dashboard)/lancamentos/actions"; -import { ConfirmActionDialog } from "@/components/shared/confirm-action-dialog"; +} from "@/features/transactions/actions"; +import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog"; import { AnticipateInstallmentsDialog } from "../dialogs/anticipate-installments-dialog/anticipate-installments-dialog"; import { AnticipationHistoryDialog } from "../dialogs/anticipate-installments-dialog/anticipation-history-dialog"; @@ -19,13 +19,13 @@ import { type BulkActionScope, } from "../dialogs/bulk-action-dialog"; import { BulkImportDialog } from "../dialogs/bulk-import-dialog"; -import { LancamentoDetailsDialog } from "../dialogs/lancamento-details-dialog"; -import { LancamentoDialog } from "../dialogs/lancamento-dialog/lancamento-dialog"; import { MassAddDialog, type MassAddFormData, } from "../dialogs/mass-add-dialog"; -import { LancamentosTable } from "../table/lancamentos-table"; +import { LancamentoDetailsDialog } from "../dialogs/transaction-details-dialog"; +import { LancamentoDialog } from "../dialogs/transaction-dialog/transaction-dialog"; +import { LancamentosTable } from "../table/transactions-table"; import type { ContaCartaoFilterOption, LancamentoFilterOption, diff --git a/components/lancamentos/select-items.tsx b/src/features/transactions/components/select-items.tsx similarity index 84% rename from components/lancamentos/select-items.tsx rename to src/features/transactions/components/select-items.tsx index f2e54e5..c0d3811 100644 --- a/components/lancamentos/select-items.tsx +++ b/src/features/transactions/components/select-items.tsx @@ -2,12 +2,16 @@ import { RiBankCard2Line, RiBankLine } from "@remixicon/react"; import Image from "next/image"; -import { CategoryIcon } from "@/components/categorias/category-icon"; -import StatusDot from "@/components/shared/status-dot"; -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; -import { resolveLogoSrc } from "@/lib/logo"; -import { getAvatarSrc } from "@/lib/pagadores/utils"; -import { getConditionIcon, getPaymentMethodIcon } from "@/lib/utils/icons"; +import { CategoryIcon } from "@/features/categories/components/category-icon"; +import StatusDot from "@/shared/components/status-dot"; +import { + Avatar, + AvatarFallback, + AvatarImage, +} from "@/shared/components/ui/avatar"; +import { resolveLogoSrc } from "@/shared/lib/logo"; +import { getAvatarSrc } from "@/shared/lib/payers/utils"; +import { getConditionIcon, getPaymentMethodIcon } from "@/shared/utils/icons"; type SelectItemContentProps = { label: string; diff --git a/components/lancamentos/shared/anticipation-card.tsx b/src/features/transactions/components/shared/anticipation-card.tsx similarity index 90% rename from components/lancamentos/shared/anticipation-card.tsx rename to src/features/transactions/components/shared/anticipation-card.tsx index c426630..c25c80e 100644 --- a/components/lancamentos/shared/anticipation-card.tsx +++ b/src/features/transactions/components/shared/anticipation-card.tsx @@ -5,11 +5,11 @@ import { format } from "date-fns"; import { ptBR } from "date-fns/locale"; import { useTransition } from "react"; import { toast } from "sonner"; -import { cancelInstallmentAnticipationAction } from "@/app/(dashboard)/lancamentos/anticipation-actions"; -import { ConfirmActionDialog } from "@/components/shared/confirm-action-dialog"; -import MoneyValues from "@/components/shared/money-values"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +import { cancelInstallmentAnticipationAction } from "@/features/transactions/anticipation-actions"; +import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog"; +import MoneyValues from "@/shared/components/money-values"; +import { Badge } from "@/shared/components/ui/badge"; +import { Button } from "@/shared/components/ui/button"; import { Card, CardContent, @@ -17,9 +17,9 @@ import { CardFooter, CardHeader, CardTitle, -} from "@/components/ui/card"; -import type { InstallmentAnticipationWithRelations } from "@/lib/installments/anticipation-types"; -import { displayPeriod } from "@/lib/utils/period"; +} from "@/shared/components/ui/card"; +import type { InstallmentAnticipationWithRelations } from "@/shared/lib/installments/anticipation-types"; +import { displayPeriod } from "@/shared/utils/period"; interface AnticipationCardProps { anticipation: InstallmentAnticipationWithRelations; diff --git a/components/lancamentos/shared/estabelecimento-input.tsx b/src/features/transactions/components/shared/establishment-input.tsx similarity index 95% rename from components/lancamentos/shared/estabelecimento-input.tsx rename to src/features/transactions/components/shared/establishment-input.tsx index 9fc41b2..41457d4 100644 --- a/components/lancamentos/shared/estabelecimento-input.tsx +++ b/src/features/transactions/components/shared/establishment-input.tsx @@ -9,13 +9,13 @@ import { CommandGroup, CommandItem, CommandList, -} from "@/components/ui/command"; -import { Input } from "@/components/ui/input"; +} from "@/shared/components/ui/command"; +import { Input } from "@/shared/components/ui/input"; import { Popover, PopoverContent, PopoverTrigger, -} from "@/components/ui/popover"; +} from "@/shared/components/ui/popover"; export interface EstabelecimentoInputProps { id?: string; diff --git a/components/lancamentos/shared/estabelecimento-logo.tsx b/src/features/transactions/components/shared/establishment-logo.tsx similarity index 97% rename from components/lancamentos/shared/estabelecimento-logo.tsx rename to src/features/transactions/components/shared/establishment-logo.tsx index d15ee14..2f61817 100644 --- a/components/lancamentos/shared/estabelecimento-logo.tsx +++ b/src/features/transactions/components/shared/establishment-logo.tsx @@ -1,4 +1,4 @@ -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; interface EstabelecimentoLogoProps { name: string; diff --git a/components/lancamentos/shared/installment-timeline.tsx b/src/features/transactions/components/shared/installment-timeline.tsx similarity index 98% rename from components/lancamentos/shared/installment-timeline.tsx rename to src/features/transactions/components/shared/installment-timeline.tsx index 3cfcd88..e74bbfe 100644 --- a/components/lancamentos/shared/installment-timeline.tsx +++ b/src/features/transactions/components/shared/installment-timeline.tsx @@ -1,10 +1,10 @@ import { RiArrowDownFill, RiCheckLine } from "@remixicon/react"; import { calculateLastInstallmentDate, - formatPurchaseDate, - formatLastInstallmentDate, formatCurrentInstallment, -} from "@/lib/installments/utils"; + formatLastInstallmentDate, + formatPurchaseDate, +} from "@/shared/lib/installments/utils"; type InstallmentTimelineProps = { purchaseDate: Date; diff --git a/components/lancamentos/table/lancamentos-filters.tsx b/src/features/transactions/components/table/transactions-filters.tsx similarity index 97% rename from components/lancamentos/table/lancamentos-filters.tsx rename to src/features/transactions/components/table/transactions-filters.tsx index f57dd36..8088ff1 100644 --- a/components/lancamentos/table/lancamentos-filters.tsx +++ b/src/features/transactions/components/table/transactions-filters.tsx @@ -13,7 +13,12 @@ import { useState, useTransition, } from "react"; -import { Button } from "@/components/ui/button"; +import { + LANCAMENTO_CONDITIONS, + LANCAMENTO_PAYMENT_METHODS, + LANCAMENTO_TRANSACTION_TYPES, +} from "@/features/transactions/constants"; +import { Button } from "@/shared/components/ui/button"; import { Command, CommandEmpty, @@ -21,7 +26,7 @@ import { CommandInput, CommandItem, CommandList, -} from "@/components/ui/command"; +} from "@/shared/components/ui/command"; import { Drawer, DrawerContent, @@ -30,13 +35,13 @@ import { DrawerHeader, DrawerTitle, DrawerTrigger, -} from "@/components/ui/drawer"; -import { Input } from "@/components/ui/input"; +} from "@/shared/components/ui/drawer"; +import { Input } from "@/shared/components/ui/input"; import { Popover, PopoverContent, PopoverTrigger, -} from "@/components/ui/popover"; +} from "@/shared/components/ui/popover"; import { Select, SelectContent, @@ -44,13 +49,8 @@ import { SelectItem, SelectLabel, SelectTrigger, -} from "@/components/ui/select"; -import { - LANCAMENTO_CONDITIONS, - LANCAMENTO_PAYMENT_METHODS, - LANCAMENTO_TRANSACTION_TYPES, -} from "@/lib/lancamentos/constants"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/select"; +import { cn } from "@/shared/utils/ui"; import { CategoriaSelectContent, ConditionSelectContent, diff --git a/components/lancamentos/table/lancamentos-table.tsx b/src/features/transactions/components/table/transactions-table.tsx similarity index 94% rename from components/lancamentos/table/lancamentos-table.tsx rename to src/features/transactions/components/table/transactions-table.tsx index b983b7c..e7448b4 100644 --- a/components/lancamentos/table/lancamentos-table.tsx +++ b/src/features/transactions/components/table/transactions-table.tsx @@ -30,30 +30,35 @@ import { import Image from "next/image"; import Link from "next/link"; import { useMemo, useState } from "react"; -import { CategoryIcon } from "@/components/categorias/category-icon"; -import { EmptyState } from "@/components/shared/empty-state"; -import MoneyValues from "@/components/shared/money-values"; -import { TypeBadge } from "@/components/shared/type-badge"; -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; -import { Checkbox } from "@/components/ui/checkbox"; +import { CategoryIcon } from "@/features/categories/components/category-icon"; +import { DEFAULT_LANCAMENTOS_COLUMN_ORDER } from "@/features/transactions/column-order"; +import { EmptyState } from "@/shared/components/empty-state"; +import MoneyValues from "@/shared/components/money-values"; +import { TypeBadge } from "@/shared/components/type-badge"; +import { + Avatar, + AvatarFallback, + AvatarImage, +} from "@/shared/components/ui/avatar"; +import { Badge } from "@/shared/components/ui/badge"; +import { Button } from "@/shared/components/ui/button"; +import { Card, CardContent } from "@/shared/components/ui/card"; +import { Checkbox } from "@/shared/components/ui/checkbox"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; +} from "@/shared/components/ui/dropdown-menu"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { Spinner } from "@/components/ui/spinner"; +} from "@/shared/components/ui/select"; +import { Spinner } from "@/shared/components/ui/spinner"; import { Table, TableBody, @@ -61,27 +66,26 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; +} from "@/shared/components/ui/table"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, -} from "@/components/ui/tooltip"; -import { DEFAULT_LANCAMENTOS_COLUMN_ORDER } from "@/lib/lancamentos/column-order"; -import { resolveLogoSrc } from "@/lib/logo"; -import { getAvatarSrc } from "@/lib/pagadores/utils"; -import { formatDate } from "@/lib/utils/date"; -import { getConditionIcon, getPaymentMethodIcon } from "@/lib/utils/icons"; -import { cn } from "@/lib/utils/ui"; -import { LancamentosExport } from "../lancamentos-export"; -import { EstabelecimentoLogo } from "../shared/estabelecimento-logo"; +} from "@/shared/components/ui/tooltip"; +import { resolveLogoSrc } from "@/shared/lib/logo"; +import { getAvatarSrc } from "@/shared/lib/payers/utils"; +import { formatDate } from "@/shared/utils/date"; +import { getConditionIcon, getPaymentMethodIcon } from "@/shared/utils/icons"; +import { cn } from "@/shared/utils/ui"; +import { EstabelecimentoLogo } from "../shared/establishment-logo"; +import { LancamentosExport } from "../transactions-export"; import type { ContaCartaoFilterOption, LancamentoFilterOption, LancamentoItem, } from "../types"; -import { LancamentosFilters } from "./lancamentos-filters"; +import { LancamentosFilters } from "./transactions-filters"; type BuildColumnsArgs = { currentUserId: string; @@ -223,7 +227,7 @@ const buildColumns = ({ Última parcela @@ -428,9 +432,9 @@ const buildColumns = ({ const label = cartaoName ?? contaName; const logoSrc = resolveLogoSrc(cartaoLogo ?? contaLogo); const href = cartaoId - ? `/cartoes/${cartaoId}/fatura` + ? `/cards/${cartaoId}/invoice` : contaId - ? `/contas/${contaId}/extrato` + ? `/accounts/${contaId}/statement` : null; const isOwnData = userId === currentUserId; diff --git a/components/lancamentos/lancamentos-export.tsx b/src/features/transactions/components/transactions-export.tsx similarity index 94% rename from components/lancamentos/lancamentos-export.tsx rename to src/features/transactions/components/transactions-export.tsx index f23071c..611894f 100644 --- a/components/lancamentos/lancamentos-export.tsx +++ b/src/features/transactions/components/transactions-export.tsx @@ -11,20 +11,20 @@ import autoTable from "jspdf-autotable"; import { useState } from "react"; import { toast } from "sonner"; import * as XLSX from "xlsx"; -import { Button } from "@/components/ui/button"; +import { formatCurrency } from "@/features/transactions/formatting-helpers"; +import { Button } from "@/shared/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { formatCurrency } from "@/lib/lancamentos/formatting-helpers"; -import { formatDateOnly, formatDateTime } from "@/lib/utils/date"; +} from "@/shared/components/ui/dropdown-menu"; +import { formatDateOnly, formatDateTime } from "@/shared/utils/date"; import { getPrimaryPdfColor, loadExportLogoDataUrl, -} from "@/lib/utils/export-branding"; -import { displayPeriod } from "@/lib/utils/period"; +} from "@/shared/utils/export-branding"; +import { displayPeriod } from "@/shared/utils/period"; import type { LancamentoItem } from "./types"; interface LancamentosExportProps { @@ -193,8 +193,8 @@ export function LancamentosExport({ const doc = new jsPDF({ orientation: "landscape" }); const primaryColor = getPrimaryPdfColor(); const [smallLogoDataUrl, textLogoDataUrl] = await Promise.all([ - loadExportLogoDataUrl("/imagens/logo_small.png"), - loadExportLogoDataUrl("/imagens/logo_text.png"), + loadExportLogoDataUrl("/images/logo_small.png"), + loadExportLogoDataUrl("/images/logo_text.png"), ]); let brandingEndX = 14; diff --git a/components/lancamentos/types.ts b/src/features/transactions/components/types.ts similarity index 100% rename from components/lancamentos/types.ts rename to src/features/transactions/components/types.ts diff --git a/lib/lancamentos/constants.ts b/src/features/transactions/constants.ts similarity index 100% rename from lib/lancamentos/constants.ts rename to src/features/transactions/constants.ts diff --git a/lib/lancamentos/form-helpers.ts b/src/features/transactions/form-helpers.ts similarity index 98% rename from lib/lancamentos/form-helpers.ts rename to src/features/transactions/form-helpers.ts index 85fd14d..57bf3ff 100644 --- a/lib/lancamentos/form-helpers.ts +++ b/src/features/transactions/form-helpers.ts @@ -1,6 +1,6 @@ -import type { LancamentoItem } from "@/components/lancamentos/types"; -import { getTodayDateString } from "@/lib/utils/date"; -import { derivePeriodFromDate, getNextPeriod } from "@/lib/utils/period"; +import type { LancamentoItem } from "@/features/transactions/components/types"; +import { getTodayDateString } from "@/shared/utils/date"; +import { derivePeriodFromDate, getNextPeriod } from "@/shared/utils/period"; import { LANCAMENTO_CONDITIONS, LANCAMENTO_PAYMENT_METHODS, diff --git a/lib/lancamentos/formatting-helpers.ts b/src/features/transactions/formatting-helpers.ts similarity index 87% rename from lib/lancamentos/formatting-helpers.ts rename to src/features/transactions/formatting-helpers.ts index 1b36d97..896b52d 100644 --- a/lib/lancamentos/formatting-helpers.ts +++ b/src/features/transactions/formatting-helpers.ts @@ -4,21 +4,13 @@ import { currencyFormatter, formatCurrency as formatCurrencyValue, -} from "@/lib/utils/currency"; -import { formatDateOnly } from "@/lib/utils/date"; -import { formatMonthYearLabel } from "@/lib/utils/period"; +} from "@/shared/utils/currency"; +import { formatDateOnly } from "@/shared/utils/date"; +import { formatMonthYearLabel } from "@/shared/utils/period"; +import { capitalize } from "@/shared/utils/string"; export { currencyFormatter }; -/** - * Capitalizes the first letter of a string - */ -function capitalize(value: string): string { - return value.length > 0 - ? value[0]?.toUpperCase().concat(value.slice(1)) - : value; -} - /** * Date formatter for pt-BR locale (dd/mm/yyyy) */ diff --git a/lib/lancamentos/page-helpers.ts b/src/features/transactions/page-helpers.ts similarity index 93% rename from lib/lancamentos/page-helpers.ts rename to src/features/transactions/page-helpers.ts index cbfd663..e373820 100644 --- a/lib/lancamentos/page-helpers.ts +++ b/src/features/transactions/page-helpers.ts @@ -1,25 +1,24 @@ import type { SQL } from "drizzle-orm"; import { and, eq, ilike, isNotNull, or } from "drizzle-orm"; -import type { SelectOption } from "@/components/lancamentos/types"; import { cartoes, - categorias, + type categorias, contas, lancamentos, - pagadores, + type pagadores, } from "@/db/schema"; -import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; +import type { SelectOption } from "@/features/transactions/components/types"; import { LANCAMENTO_CONDITIONS, LANCAMENTO_PAYMENT_METHODS, LANCAMENTO_TRANSACTION_TYPES, -} from "@/lib/lancamentos/constants"; +} from "@/features/transactions/constants"; +import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants"; import { PAGADOR_ROLE_ADMIN, PAGADOR_ROLE_TERCEIRO, -} from "@/lib/pagadores/constants"; -import { toDateOnlyString } from "@/lib/utils/date"; +} from "@/shared/lib/payers/constants"; +import { toDateOnlyString } from "@/shared/utils/date"; type PagadorRow = typeof pagadores.$inferSelect; type ContaRow = typeof contas.$inferSelect; @@ -179,27 +178,6 @@ export const toOption = ( dueDay: dueDay ?? null, }); -export const fetchLancamentoFilterSources = async (userId: string) => { - const [pagadorRows, contaRows, cartaoRows, categoriaRows] = await Promise.all( - [ - db.query.pagadores.findMany({ - where: eq(pagadores.userId, userId), - }), - db.query.contas.findMany({ - where: and(eq(contas.userId, userId), eq(contas.status, "Ativa")), - }), - db.query.cartoes.findMany({ - where: and(eq(cartoes.userId, userId), eq(cartoes.status, "Ativo")), - }), - db.query.categorias.findMany({ - where: eq(categorias.userId, userId), - }), - ], - ); - - return { pagadorRows, contaRows, cartaoRows, categoriaRows }; -}; - export const buildSluggedFilters = ({ pagadorRows, categoriaRows, diff --git a/src/features/transactions/queries.ts b/src/features/transactions/queries.ts new file mode 100644 index 0000000..5c321b5 --- /dev/null +++ b/src/features/transactions/queries.ts @@ -0,0 +1,101 @@ +import { and, desc, eq, gte, isNull, ne, or, type SQL } from "drizzle-orm"; +import { + cartoes, + categorias, + contas, + lancamentos, + pagadores, +} from "@/db/schema"; +import { INITIAL_BALANCE_NOTE } from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; + +export async function fetchLancamentoFilterSources(userId: string) { + const [pagadorRows, contaRows, cartaoRows, categoriaRows] = await Promise.all( + [ + db.query.pagadores.findMany({ + where: eq(pagadores.userId, userId), + }), + db.query.contas.findMany({ + where: and(eq(contas.userId, userId), eq(contas.status, "Ativa")), + }), + db.query.cartoes.findMany({ + where: and(eq(cartoes.userId, userId), eq(cartoes.status, "Ativo")), + }), + db.query.categorias.findMany({ + where: eq(categorias.userId, userId), + }), + ], + ); + + return { pagadorRows, contaRows, cartaoRows, categoriaRows }; +} + +export async function fetchLancamentos(filters: SQL[]) { + const lancamentoRows = await db + .select({ + lancamento: lancamentos, + pagador: pagadores, + conta: contas, + cartao: cartoes, + categoria: categorias, + }) + .from(lancamentos) + .leftJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .leftJoin(contas, eq(lancamentos.contaId, contas.id)) + .leftJoin(cartoes, eq(lancamentos.cartaoId, cartoes.id)) + .leftJoin(categorias, eq(lancamentos.categoriaId, categorias.id)) + .where( + and( + ...filters, + // Excluir saldos iniciais de contas que têm excludeInitialBalanceFromIncome = true + or( + ne(lancamentos.note, INITIAL_BALANCE_NOTE), + isNull(contas.excludeInitialBalanceFromIncome), + eq(contas.excludeInitialBalanceFromIncome, false), + ), + ), + ) + .orderBy(desc(lancamentos.purchaseDate), desc(lancamentos.createdAt)); + + // Transformar resultado para o formato esperado + return lancamentoRows.map((row) => ({ + ...row.lancamento, + pagador: row.pagador, + conta: row.conta, + cartao: row.cartao, + categoria: row.categoria, + })); +} + +export async function fetchRecentEstablishments( + userId: string, +): Promise { + const threeMonthsAgo = new Date(); + threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3); + + const results = await db + .select({ name: lancamentos.name }) + .from(lancamentos) + .where( + and( + eq(lancamentos.userId, userId), + gte(lancamentos.purchaseDate, threeMonthsAgo), + ), + ) + .orderBy(desc(lancamentos.purchaseDate)); + + const uniqueNames = Array.from( + new Set( + results + .map((row) => row.name) + .filter( + (name: string | null): name is string => + name != null && + name.trim().length > 0 && + !name.toLowerCase().startsWith("pagamento fatura"), + ), + ), + ); + + return uniqueNames.slice(0, 100); +} diff --git a/components/shared/animated-theme-toggler.tsx b/src/shared/components/animated-theme-toggler.tsx similarity index 95% rename from components/shared/animated-theme-toggler.tsx rename to src/shared/components/animated-theme-toggler.tsx index f042b1a..fc436a7 100644 --- a/components/shared/animated-theme-toggler.tsx +++ b/src/shared/components/animated-theme-toggler.tsx @@ -2,13 +2,13 @@ import { RiMoonClearLine, RiSunLine } from "@remixicon/react"; import { useEffect, useRef, useState } from "react"; import { flushSync } from "react-dom"; -import { buttonVariants } from "@/components/ui/button"; +import { buttonVariants } from "@/shared/components/ui/button"; import { Tooltip, TooltipContent, TooltipTrigger, -} from "@/components/ui/tooltip"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/tooltip"; +import { cn } from "@/shared/utils/ui"; interface AnimatedThemeTogglerProps extends React.ComponentPropsWithoutRef<"button"> { diff --git a/components/calculadora/calculator-dialog.tsx b/src/shared/components/calculator/calculator-dialog.tsx similarity index 90% rename from components/calculadora/calculator-dialog.tsx rename to src/shared/components/calculator/calculator-dialog.tsx index d61bd8b..c3dc604 100644 --- a/components/calculadora/calculator-dialog.tsx +++ b/src/shared/components/calculator/calculator-dialog.tsx @@ -2,22 +2,22 @@ import { RiCalculatorFill, RiCalculatorLine } from "@remixicon/react"; import * as React from "react"; -import Calculator from "@/components/calculadora/calculator"; -import { Button, buttonVariants } from "@/components/ui/button"; +import Calculator from "@/shared/components/calculator/calculator"; +import { Button, buttonVariants } from "@/shared/components/ui/button"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; +} from "@/shared/components/ui/dialog"; import { Tooltip, TooltipContent, TooltipTrigger, -} from "@/components/ui/tooltip"; -import { cn } from "@/lib/utils/ui"; -import { useDraggableDialog } from "../../lib/calculadora/use-draggable-dialog"; +} from "@/shared/components/ui/tooltip"; +import { useDraggableDialog } from "@/shared/lib/calculator/use-draggable-dialog"; +import { cn } from "@/shared/utils/ui"; type Variant = React.ComponentProps["variant"]; type Size = React.ComponentProps["size"]; diff --git a/components/calculadora/calculator-display.tsx b/src/shared/components/calculator/calculator-display.tsx similarity index 93% rename from components/calculadora/calculator-display.tsx rename to src/shared/components/calculator/calculator-display.tsx index 098c45b..c5c3fef 100644 --- a/components/calculadora/calculator-display.tsx +++ b/src/shared/components/calculator/calculator-display.tsx @@ -1,6 +1,6 @@ import { RiCheckLine, RiFileCopyLine } from "@remixicon/react"; -import { Button } from "@/components/ui/button"; -import { cn } from "@/lib/utils/ui"; +import { Button } from "@/shared/components/ui/button"; +import { cn } from "@/shared/utils/ui"; export type CalculatorDisplayProps = { history: string | null; diff --git a/components/calculadora/calculator-keypad.tsx b/src/shared/components/calculator/calculator-keypad.tsx similarity index 80% rename from components/calculadora/calculator-keypad.tsx rename to src/shared/components/calculator/calculator-keypad.tsx index 87f77c1..ec3e6ec 100644 --- a/components/calculadora/calculator-keypad.tsx +++ b/src/shared/components/calculator/calculator-keypad.tsx @@ -1,7 +1,7 @@ -import { Button } from "@/components/ui/button"; -import type { CalculatorButtonConfig } from "@/lib/calculadora/use-calculator-state"; -import type { Operator } from "@/lib/utils/calculator"; -import { cn } from "@/lib/utils/ui"; +import { Button } from "@/shared/components/ui/button"; +import type { CalculatorButtonConfig } from "@/shared/lib/calculator/use-calculator-state"; +import type { Operator } from "@/shared/utils/calculator"; +import { cn } from "@/shared/utils/ui"; type CalculatorKeypadProps = { buttons: CalculatorButtonConfig[][]; diff --git a/components/calculadora/calculator.tsx b/src/shared/components/calculator/calculator.tsx similarity index 82% rename from components/calculadora/calculator.tsx rename to src/shared/components/calculator/calculator.tsx index bcdbf3e..df020da 100644 --- a/components/calculadora/calculator.tsx +++ b/src/shared/components/calculator/calculator.tsx @@ -1,9 +1,9 @@ "use client"; -import { CalculatorKeypad } from "@/components/calculadora/calculator-keypad"; -import { Button } from "@/components/ui/button"; -import { useCalculatorKeyboard } from "@/lib/calculadora/use-calculator-keyboard"; -import { useCalculatorState } from "@/lib/calculadora/use-calculator-state"; +import { CalculatorKeypad } from "@/shared/components/calculator/calculator-keypad"; +import { Button } from "@/shared/components/ui/button"; +import { useCalculatorKeyboard } from "@/shared/lib/calculator/use-calculator-keyboard"; +import { useCalculatorState } from "@/shared/lib/calculator/use-calculator-state"; import { CalculatorDisplay } from "./calculator-display"; type CalculatorProps = { diff --git a/components/shared/confirm-action-dialog.tsx b/src/shared/components/confirm-action-dialog.tsx similarity index 95% rename from components/shared/confirm-action-dialog.tsx rename to src/shared/components/confirm-action-dialog.tsx index 7558f7d..c2d48ee 100644 --- a/components/shared/confirm-action-dialog.tsx +++ b/src/shared/components/confirm-action-dialog.tsx @@ -12,8 +12,8 @@ import { AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, -} from "@/components/ui/alert-dialog"; -import { buttonVariants } from "@/components/ui/button"; +} from "@/shared/components/ui/alert-dialog"; +import { buttonVariants } from "@/shared/components/ui/button"; interface ConfirmActionDialogProps { trigger?: React.ReactNode; diff --git a/components/shared/empty-state.tsx b/src/shared/components/empty-state.tsx similarity index 92% rename from components/shared/empty-state.tsx rename to src/shared/components/empty-state.tsx index f2e4207..1b369ad 100644 --- a/components/shared/empty-state.tsx +++ b/src/shared/components/empty-state.tsx @@ -6,8 +6,8 @@ import { EmptyHeader, EmptyMedia, EmptyTitle, -} from "@/components/ui/empty"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/empty"; +import { cn } from "@/shared/utils/ui"; interface EmptyStateProps { title: ReactNode; diff --git a/components/shared/expandable-widget-card.tsx b/src/shared/components/expandable-widget-card.tsx similarity index 92% rename from components/shared/expandable-widget-card.tsx rename to src/shared/components/expandable-widget-card.tsx index 51610c7..5a0c0cd 100644 --- a/components/shared/expandable-widget-card.tsx +++ b/src/shared/components/expandable-widget-card.tsx @@ -2,15 +2,15 @@ import { RiExpandDiagonalLine } from "@remixicon/react"; import { useEffect, useRef, useState } from "react"; -import type { WidgetCardProps } from "@/components/shared/widget-card"; -import WidgetCard from "@/components/shared/widget-card"; -import { Button } from "@/components/ui/button"; +import { Button } from "@/shared/components/ui/button"; import { Dialog, DialogContent, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; +} from "@/shared/components/ui/dialog"; +import type { WidgetCardProps } from "@/shared/components/widget-card"; +import WidgetCard from "@/shared/components/widget-card"; const OVERFLOW_THRESHOLD_PX = 16; const EXPANDABLE_CONTENT_CLASSNAME = diff --git a/src/shared/components/logo-picker/index.ts b/src/shared/components/logo-picker/index.ts new file mode 100644 index 0000000..af8bd5e --- /dev/null +++ b/src/shared/components/logo-picker/index.ts @@ -0,0 +1 @@ +export { LogoPickerDialog, LogoPickerTrigger } from "./logo-picker"; diff --git a/components/logo-picker/logo-picker.tsx b/src/shared/components/logo-picker/logo-picker.tsx similarity index 96% rename from components/logo-picker/logo-picker.tsx rename to src/shared/components/logo-picker/logo-picker.tsx index abf69bb..a93bc97 100644 --- a/components/logo-picker/logo-picker.tsx +++ b/src/shared/components/logo-picker/logo-picker.tsx @@ -8,10 +8,10 @@ import { DialogDescription, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import { Input } from "@/components/ui/input"; -import { deriveNameFromLogo, resolveLogoSrc } from "@/lib/logo"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/dialog"; +import { Input } from "@/shared/components/ui/input"; +import { deriveNameFromLogo, resolveLogoSrc } from "@/shared/lib/logo"; +import { cn } from "@/shared/utils/ui"; const DEFAULT_BASE_PATH = "/logos"; diff --git a/components/logo-picker/use-logo-selection.ts b/src/shared/components/logo-picker/use-logo-selection.ts similarity index 96% rename from components/logo-picker/use-logo-selection.ts rename to src/shared/components/logo-picker/use-logo-selection.ts index 9603eb6..dcba736 100644 --- a/components/logo-picker/use-logo-selection.ts +++ b/src/shared/components/logo-picker/use-logo-selection.ts @@ -1,5 +1,5 @@ import { useCallback } from "react"; -import { deriveNameFromLogo } from "@/lib/logo"; +import { deriveNameFromLogo } from "@/shared/lib/logo"; interface UseLogoSelectionProps { mode: "create" | "update"; diff --git a/components/shared/logo.tsx b/src/shared/components/logo.tsx similarity index 87% rename from components/shared/logo.tsx rename to src/shared/components/logo.tsx index b223488..74408f1 100644 --- a/components/shared/logo.tsx +++ b/src/shared/components/logo.tsx @@ -1,6 +1,6 @@ import Image from "next/image"; -import { cn } from "@/lib/utils/ui"; import { version } from "@/package.json"; +import { cn } from "@/shared/utils/ui"; interface LogoProps { variant?: "full" | "small" | "compact"; @@ -19,7 +19,7 @@ export function Logo({ return (
OpenMonetis OpenMonetis OpenMonetis OpenMonetis +
{/* Logo */} diff --git a/components/feedback/feedback-dialog.tsx b/src/shared/components/navigation/navbar/feedback-dialog.tsx similarity index 97% rename from components/feedback/feedback-dialog.tsx rename to src/shared/components/navigation/navbar/feedback-dialog.tsx index 8bbea85..6f4ec2e 100644 --- a/components/feedback/feedback-dialog.tsx +++ b/src/shared/components/navigation/navbar/feedback-dialog.tsx @@ -13,8 +13,8 @@ import { DialogDescription, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import { cn } from "@/lib/utils"; +} from "@/shared/components/ui/dialog"; +import { cn } from "@/shared/utils"; const GITHUB_REPO_BASE = "https://github.com/felipegcoutinho/openmonetis"; const GITHUB_DISCUSSIONS_BASE = `${GITHUB_REPO_BASE}/discussions/new`; diff --git a/components/navigation/navbar/mobile-link.tsx b/src/shared/components/navigation/navbar/mobile-link.tsx similarity index 93% rename from components/navigation/navbar/mobile-link.tsx rename to src/shared/components/navigation/navbar/mobile-link.tsx index bb43791..6ad5f0d 100644 --- a/components/navigation/navbar/mobile-link.tsx +++ b/src/shared/components/navigation/navbar/mobile-link.tsx @@ -1,8 +1,8 @@ "use client"; import { usePathname } from "next/navigation"; -import { Badge } from "@/components/ui/badge"; -import { cn } from "@/lib/utils/ui"; +import { Badge } from "@/shared/components/ui/badge"; +import { cn } from "@/shared/utils/ui"; import { NavLink } from "./nav-link"; type MobileLinkProps = { diff --git a/components/navigation/navbar/nav-dropdown.tsx b/src/shared/components/navigation/navbar/nav-dropdown.tsx similarity index 94% rename from components/navigation/navbar/nav-dropdown.tsx rename to src/shared/components/navigation/navbar/nav-dropdown.tsx index 2d00b58..7974dcf 100644 --- a/components/navigation/navbar/nav-dropdown.tsx +++ b/src/shared/components/navigation/navbar/nav-dropdown.tsx @@ -1,6 +1,6 @@ "use client"; -import { Badge } from "@/components/ui/badge"; +import { Badge } from "@/shared/components/ui/badge"; import type { NavItem } from "./nav-items"; import { NavLink } from "./nav-link"; diff --git a/components/navigation/navbar/nav-items.tsx b/src/shared/components/navigation/navbar/nav-items.tsx similarity index 84% rename from components/navigation/navbar/nav-items.tsx rename to src/shared/components/navigation/navbar/nav-items.tsx index 57c2328..6115e96 100644 --- a/components/navigation/navbar/nav-items.tsx +++ b/src/shared/components/navigation/navbar/nav-items.tsx @@ -33,18 +33,18 @@ export const NAV_SECTIONS: NavSection[] = [ label: "Lançamentos", items: [ { - href: "/lancamentos", + href: "/transactions", label: "lançamentos", icon: , preservePeriod: true, }, { - href: "/pre-lancamentos", + href: "/inbox", label: "pré-lançamentos", icon: , }, { - href: "/calendario", + href: "/calendar", label: "calendário", icon: , hideOnMobile: true, @@ -55,17 +55,17 @@ export const NAV_SECTIONS: NavSection[] = [ label: "Finanças", items: [ { - href: "/cartoes", + href: "/cards", label: "cartões", icon: , }, { - href: "/contas", + href: "/accounts", label: "contas", icon: , }, { - href: "/orcamentos", + href: "/budgets", label: "orçamentos", icon: , preservePeriod: true, @@ -76,17 +76,17 @@ export const NAV_SECTIONS: NavSection[] = [ label: "Organização", items: [ { - href: "/pagadores", + href: "/payers", label: "pagadores", icon: , }, { - href: "/categorias", + href: "/categories", label: "categorias", icon: , }, { - href: "/anotacoes", + href: "/notes", label: "anotações", icon: , }, @@ -102,23 +102,23 @@ export const NAV_SECTIONS: NavSection[] = [ preservePeriod: true, }, { - href: "/relatorios/tendencias", + href: "/reports/category-trends", label: "tendências", icon: , }, { - href: "/relatorios/uso-cartoes", + href: "/reports/card-usage", label: "uso de cartões", icon: , preservePeriod: true, }, { - href: "/relatorios/analise-parcelas", + href: "/reports/installment-analysis", label: "análise de parcelas", icon: , }, { - href: "/relatorios/estabelecimentos", + href: "/reports/establishments", label: "estabelecimentos", icon: , }, diff --git a/components/navigation/navbar/nav-link.tsx b/src/shared/components/navigation/navbar/nav-link.tsx similarity index 100% rename from components/navigation/navbar/nav-link.tsx rename to src/shared/components/navigation/navbar/nav-link.tsx diff --git a/components/navigation/navbar/nav-menu.tsx b/src/shared/components/navigation/navbar/nav-menu.tsx similarity index 92% rename from components/navigation/navbar/nav-menu.tsx rename to src/shared/components/navigation/navbar/nav-menu.tsx index c04c785..7c9dd5a 100644 --- a/components/navigation/navbar/nav-menu.tsx +++ b/src/shared/components/navigation/navbar/nav-menu.tsx @@ -2,23 +2,23 @@ import { RiDashboardLine, RiMenuLine } from "@remixicon/react"; import { useState } from "react"; -import { CalculatorDialogContent } from "@/components/calculadora/calculator-dialog"; -import { Button } from "@/components/ui/button"; -import { Dialog } from "@/components/ui/dialog"; +import { CalculatorDialogContent } from "@/shared/components/calculator/calculator-dialog"; +import { Button } from "@/shared/components/ui/button"; +import { Dialog } from "@/shared/components/ui/dialog"; import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuList, NavigationMenuTrigger, -} from "@/components/ui/navigation-menu"; +} from "@/shared/components/ui/navigation-menu"; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger, -} from "@/components/ui/sheet"; +} from "@/shared/components/ui/sheet"; import { MobileLink, MobileSectionLabel } from "./mobile-link"; import { NavDropdown } from "./nav-dropdown"; import { NAV_SECTIONS } from "./nav-items"; diff --git a/components/navigation/navbar/nav-pill.tsx b/src/shared/components/navigation/navbar/nav-pill.tsx similarity index 94% rename from components/navigation/navbar/nav-pill.tsx rename to src/shared/components/navigation/navbar/nav-pill.tsx index b2e5e6a..6c0d2bc 100644 --- a/components/navigation/navbar/nav-pill.tsx +++ b/src/shared/components/navigation/navbar/nav-pill.tsx @@ -1,7 +1,7 @@ "use client"; import { usePathname } from "next/navigation"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; import { NavLink } from "./nav-link"; import { linkActive, linkBase, linkIdle } from "./nav-styles"; diff --git a/components/navigation/navbar/nav-styles.ts b/src/shared/components/navigation/navbar/nav-styles.ts similarity index 100% rename from components/navigation/navbar/nav-styles.ts rename to src/shared/components/navigation/navbar/nav-styles.ts diff --git a/components/navigation/navbar/nav-tools.tsx b/src/shared/components/navigation/navbar/nav-tools.tsx similarity index 93% rename from components/navigation/navbar/nav-tools.tsx rename to src/shared/components/navigation/navbar/nav-tools.tsx index bd7ab64..7a37162 100644 --- a/components/navigation/navbar/nav-tools.tsx +++ b/src/shared/components/navigation/navbar/nav-tools.tsx @@ -1,9 +1,9 @@ "use client"; import { RiCalculatorLine, RiEyeLine, RiEyeOffLine } from "@remixicon/react"; -import { usePrivacyMode } from "@/components/providers/privacy-provider"; -import { Badge } from "@/components/ui/badge"; -import { cn } from "@/lib/utils/ui"; +import { usePrivacyMode } from "@/shared/components/providers/privacy-provider"; +import { Badge } from "@/shared/components/ui/badge"; +import { cn } from "@/shared/utils/ui"; const itemClass = "flex w-full items-center gap-2.5 rounded-sm px-2 py-2 text-sm text-foreground hover:bg-accent transition-colors cursor-pointer"; diff --git a/components/navigation/navbar/navbar-user.tsx b/src/shared/components/navigation/navbar/navbar-user.tsx similarity index 86% rename from components/navigation/navbar/navbar-user.tsx rename to src/shared/components/navigation/navbar/navbar-user.tsx index 4bde151..89cf378 100644 --- a/components/navigation/navbar/navbar-user.tsx +++ b/src/shared/components/navigation/navbar/navbar-user.tsx @@ -10,21 +10,21 @@ import Image from "next/image"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useState } from "react"; -import { FeedbackDialogBody } from "@/components/feedback/feedback-dialog"; -import { Badge } from "@/components/ui/badge"; -import { Dialog, DialogTrigger } from "@/components/ui/dialog"; +import { version } from "@/package.json"; +import { FeedbackDialogBody } from "@/shared/components/navigation/navbar/feedback-dialog"; +import { Badge } from "@/shared/components/ui/badge"; +import { Dialog, DialogTrigger } from "@/shared/components/ui/dialog"; import { DropdownMenu, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { Spinner } from "@/components/ui/spinner"; -import { authClient } from "@/lib/auth/client"; -import { getAvatarSrc } from "@/lib/pagadores/utils"; -import { cn } from "@/lib/utils/ui"; -import { version } from "@/package.json"; +} from "@/shared/components/ui/dropdown-menu"; +import { Spinner } from "@/shared/components/ui/spinner"; +import { authClient } from "@/shared/lib/auth/client"; +import { getAvatarSrc } from "@/shared/lib/payers/utils"; +import { cn } from "@/shared/utils/ui"; const itemClass = "flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors hover:bg-accent"; @@ -99,13 +99,13 @@ export function NavbarUser({ user, pagadorAvatarUrl }: NavbarUserProps) {
- + Ajustes diff --git a/components/notificacoes/notification-bell.tsx b/src/shared/components/navigation/navbar/notification-bell.tsx similarity index 94% rename from components/notificacoes/notification-bell.tsx rename to src/shared/components/navigation/navbar/notification-bell.tsx index 33ec411..312fae1 100644 --- a/components/notificacoes/notification-bell.tsx +++ b/src/shared/components/navigation/navbar/notification-bell.tsx @@ -15,34 +15,34 @@ import { import Image from "next/image"; import Link from "next/link"; import { useState } from "react"; -import { Badge } from "@/components/ui/badge"; -import { buttonVariants } from "@/components/ui/button"; +import type { + BudgetNotification, + DashboardNotification, +} from "@/features/dashboard/notifications-queries"; +import { Badge } from "@/shared/components/ui/badge"; +import { buttonVariants } from "@/shared/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuLabel, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; +} from "@/shared/components/ui/dropdown-menu"; import { Empty, EmptyDescription, EmptyMedia, EmptyTitle, -} from "@/components/ui/empty"; +} from "@/shared/components/ui/empty"; import { Tooltip, TooltipContent, TooltipTrigger, -} from "@/components/ui/tooltip"; -import type { - BudgetNotification, - DashboardNotification, -} from "@/lib/dashboard/notifications"; -import { resolveLogoSrc } from "@/lib/logo"; -import { formatCurrency } from "@/lib/utils/currency"; -import { formatDateOnly } from "@/lib/utils/date"; -import { formatPercentage } from "@/lib/utils/percentage"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/tooltip"; +import { resolveLogoSrc } from "@/shared/lib/logo"; +import { formatCurrency } from "@/shared/utils/currency"; +import { formatDateOnly } from "@/shared/utils/date"; +import { formatPercentage } from "@/shared/utils/percentage"; +import { cn } from "@/shared/utils/ui"; type NotificationBellProps = { notifications: DashboardNotification[]; @@ -173,7 +173,7 @@ export function NotificationBell({ title="Pré-lançamentos" /> setOpen(false)} className="group mx-1 mb-1 flex items-center gap-2 rounded-md px-2 py-2 transition-colors hover:bg-accent/60" > diff --git a/components/navigation/sidebar/app-sidebar.tsx b/src/shared/components/navigation/sidebar/app-sidebar.tsx similarity index 85% rename from components/navigation/sidebar/app-sidebar.tsx rename to src/shared/components/navigation/sidebar/app-sidebar.tsx index cab2caa..a73e22a 100644 --- a/components/navigation/sidebar/app-sidebar.tsx +++ b/src/shared/components/navigation/sidebar/app-sidebar.tsx @@ -1,9 +1,9 @@ "use client"; import * as React from "react"; -import { Logo } from "@/components/shared/logo"; -import { NavMain } from "@/components/navigation/sidebar/nav-main"; -import { NavSecondary } from "@/components/navigation/sidebar/nav-secondary"; -import { NavUser } from "@/components/navigation/sidebar/nav-user"; +import { Logo } from "@/shared/components/logo"; +import { NavMain } from "@/shared/components/navigation/sidebar/nav-main"; +import { NavSecondary } from "@/shared/components/navigation/sidebar/nav-secondary"; +import { NavUser } from "@/shared/components/navigation/sidebar/nav-user"; import { Sidebar, SidebarContent, @@ -13,7 +13,7 @@ import { SidebarMenuButton, SidebarMenuItem, useSidebar, -} from "@/components/ui/sidebar"; +} from "@/shared/components/ui/sidebar"; import { createSidebarNavData, type PagadorLike } from "./nav-link"; type AppUser = { diff --git a/components/navigation/sidebar/nav-link.tsx b/src/shared/components/navigation/sidebar/nav-link.tsx similarity index 88% rename from components/navigation/sidebar/nav-link.tsx rename to src/shared/components/navigation/sidebar/nav-link.tsx index bdc8441..58e36ba 100644 --- a/components/navigation/sidebar/nav-link.tsx +++ b/src/shared/components/navigation/sidebar/nav-link.tsx @@ -69,7 +69,7 @@ export function createSidebarNavData( title: pagador.name?.trim().length ? pagador.name.trim() : "Pagador sem nome", - url: `/pagadores/${pagador.id}`, + url: `/payers/${pagador.id}`, key: pagador.canEdit ? pagador.id : `${pagador.id}-shared`, isShared: !pagador.canEdit, avatarUrl: pagador.avatarUrl, @@ -92,12 +92,12 @@ export function createSidebarNavData( }, { title: "Lançamentos", - url: "/lancamentos", + url: "/transactions", icon: RiArrowLeftRightLine, items: [ { title: "Pré-Lançamentos", - url: "/pre-lancamentos", + url: "/inbox", key: "pre-lancamentos", icon: RiAtLine, badge: @@ -107,22 +107,22 @@ export function createSidebarNavData( }, { title: "Calendário", - url: "/calendario", + url: "/calendar", icon: RiCalendarEventLine, }, { title: "Cartões", - url: "/cartoes", + url: "/cards", icon: RiBankCard2Line, }, { title: "Contas", - url: "/contas", + url: "/accounts", icon: RiBankLine, }, { title: "Orçamentos", - url: "/orcamentos", + url: "/budgets", icon: RiFundsLine, }, ], @@ -132,18 +132,18 @@ export function createSidebarNavData( items: [ { title: "Pagadores", - url: "/pagadores", + url: "/payers", icon: RiGroupLine, items: pagadorItemsWithHistory, }, { title: "Categorias", - url: "/categorias", + url: "/categories", icon: RiPriceTag3Line, }, { title: "Anotações", - url: "/anotacoes", + url: "/notes", icon: RiTodoLine, }, ], @@ -158,17 +158,17 @@ export function createSidebarNavData( }, { title: "Tendências", - url: "/relatorios/tendencias", + url: "/reports/category-trends", icon: RiFileChartLine, }, { title: "Uso de Cartões", - url: "/relatorios/uso-cartoes", + url: "/reports/card-usage", icon: RiBankCard2Line, }, { title: "Análise de Parcelas", - url: "/relatorios/analise-parcelas", + url: "/reports/installment-analysis", icon: RiSecurePaymentLine, }, ], @@ -177,7 +177,7 @@ export function createSidebarNavData( navSecondary: [ { title: "Ajustes", - url: "/ajustes", + url: "/settings", icon: RiSettings2Line, }, ], diff --git a/components/navigation/sidebar/nav-main.tsx b/src/shared/components/navigation/sidebar/nav-main.tsx similarity index 94% rename from components/navigation/sidebar/nav-main.tsx rename to src/shared/components/navigation/sidebar/nav-main.tsx index 2b79d34..d850d4f 100644 --- a/components/navigation/sidebar/nav-main.tsx +++ b/src/shared/components/navigation/sidebar/nav-main.tsx @@ -7,13 +7,17 @@ import { } from "@remixicon/react"; import Link from "next/link"; import { usePathname, useSearchParams } from "next/navigation"; -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; -import { Badge } from "@/components/ui/badge"; +import { + Avatar, + AvatarFallback, + AvatarImage, +} from "@/shared/components/ui/avatar"; +import { Badge } from "@/shared/components/ui/badge"; import { Collapsible, CollapsibleContent, CollapsibleTrigger, -} from "@/components/ui/collapsible"; +} from "@/shared/components/ui/collapsible"; import { SidebarGroup, SidebarGroupContent, @@ -25,8 +29,8 @@ import { SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, -} from "@/components/ui/sidebar"; -import { getAvatarSrc } from "@/lib/pagadores/utils"; +} from "@/shared/components/ui/sidebar"; +import { getAvatarSrc } from "@/shared/lib/payers/utils"; type NavItem = { title: string; @@ -51,11 +55,7 @@ type NavSection = { const MONTH_PERIOD_PARAM = "periodo"; -const PERIOD_AWARE_PATHS = new Set([ - "/dashboard", - "/lancamentos", - "/orcamentos", -]); +const PERIOD_AWARE_PATHS = new Set(["/dashboard", "/transactions", "/budgets"]); export function NavMain({ sections }: { sections: NavSection[] }) { const pathname = usePathname(); diff --git a/components/navigation/sidebar/nav-secondary.tsx b/src/shared/components/navigation/sidebar/nav-secondary.tsx similarity index 97% rename from components/navigation/sidebar/nav-secondary.tsx rename to src/shared/components/navigation/sidebar/nav-secondary.tsx index e5863cd..d9a814f 100644 --- a/components/navigation/sidebar/nav-secondary.tsx +++ b/src/shared/components/navigation/sidebar/nav-secondary.tsx @@ -10,7 +10,7 @@ import { SidebarMenu, SidebarMenuButton, SidebarMenuItem, -} from "@/components/ui/sidebar"; +} from "@/shared/components/ui/sidebar"; export function NavSecondary({ items, diff --git a/components/navigation/sidebar/nav-user.tsx b/src/shared/components/navigation/sidebar/nav-user.tsx similarity index 91% rename from components/navigation/sidebar/nav-user.tsx rename to src/shared/components/navigation/sidebar/nav-user.tsx index 89490df..b6ea956 100644 --- a/components/navigation/sidebar/nav-user.tsx +++ b/src/shared/components/navigation/sidebar/nav-user.tsx @@ -5,8 +5,8 @@ import { SidebarMenu, SidebarMenuButton, SidebarMenuItem, -} from "@/components/ui/sidebar"; -import { getAvatarSrc } from "@/lib/pagadores/utils"; +} from "@/shared/components/ui/sidebar"; +import { getAvatarSrc } from "@/shared/lib/payers/utils"; type NavUserProps = { user: { diff --git a/components/shared/page-description.tsx b/src/shared/components/page-description.tsx similarity index 92% rename from components/shared/page-description.tsx rename to src/shared/components/page-description.tsx index af1b7e0..9928850 100644 --- a/components/shared/page-description.tsx +++ b/src/shared/components/page-description.tsx @@ -9,7 +9,7 @@ export default function PageDescription({ }) { return (
-

+

{icon} {title}

diff --git a/components/shared/period-picker.tsx b/src/shared/components/period-picker.tsx similarity index 86% rename from components/shared/period-picker.tsx rename to src/shared/components/period-picker.tsx index ff7971d..e6b5821 100644 --- a/components/shared/period-picker.tsx +++ b/src/shared/components/period-picker.tsx @@ -2,19 +2,19 @@ import { RiCalendarLine } from "@remixicon/react"; import { useState } from "react"; -import { Button } from "@/components/ui/button"; -import { MonthPicker } from "@/components/ui/month-picker"; +import { Button } from "@/shared/components/ui/button"; +import { MonthPicker } from "@/shared/components/ui/month-picker"; import { Popover, PopoverContent, PopoverTrigger, -} from "@/components/ui/popover"; +} from "@/shared/components/ui/popover"; import { dateToPeriod, formatMonthYearLabel, periodToDate, -} from "@/lib/utils/period"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/utils/period"; +import { cn } from "@/shared/utils/ui"; interface PeriodPickerProps { value: string; // "YYYY-MM" format diff --git a/components/providers/font-provider.tsx b/src/shared/components/providers/font-provider.tsx similarity index 100% rename from components/providers/font-provider.tsx rename to src/shared/components/providers/font-provider.tsx diff --git a/components/providers/index.ts b/src/shared/components/providers/index.ts similarity index 100% rename from components/providers/index.ts rename to src/shared/components/providers/index.ts diff --git a/components/providers/privacy-provider.tsx b/src/shared/components/providers/privacy-provider.tsx similarity index 100% rename from components/providers/privacy-provider.tsx rename to src/shared/components/providers/privacy-provider.tsx diff --git a/components/providers/theme-provider.tsx b/src/shared/components/providers/theme-provider.tsx similarity index 100% rename from components/providers/theme-provider.tsx rename to src/shared/components/providers/theme-provider.tsx diff --git a/components/shared/refresh-page-button.tsx b/src/shared/components/refresh-page-button.tsx similarity index 90% rename from components/shared/refresh-page-button.tsx rename to src/shared/components/refresh-page-button.tsx index 70867ff..3c3a221 100644 --- a/components/shared/refresh-page-button.tsx +++ b/src/shared/components/refresh-page-button.tsx @@ -3,13 +3,13 @@ import { RiRefreshLine } from "@remixicon/react"; import { useRouter } from "next/navigation"; import { useTransition } from "react"; -import { buttonVariants } from "@/components/ui/button"; +import { buttonVariants } from "@/shared/components/ui/button"; import { Tooltip, TooltipContent, TooltipTrigger, -} from "@/components/ui/tooltip"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/tooltip"; +import { cn } from "@/shared/utils/ui"; type RefreshPageButtonProps = React.ComponentPropsWithoutRef<"button">; diff --git a/components/shared/skeletons/account-statement-card-skeleton.tsx b/src/shared/components/skeletons/account-statement-card-skeleton.tsx similarity index 95% rename from components/shared/skeletons/account-statement-card-skeleton.tsx rename to src/shared/components/skeletons/account-statement-card-skeleton.tsx index 54f70af..45b7712 100644 --- a/components/shared/skeletons/account-statement-card-skeleton.tsx +++ b/src/shared/components/skeletons/account-statement-card-skeleton.tsx @@ -1,4 +1,4 @@ -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/shared/components/ui/skeleton"; /** * Skeleton para o card de resumo da conta (AccountStatementCard) diff --git a/components/shared/skeletons/category-report-skeleton.tsx b/src/shared/components/skeletons/category-report-skeleton.tsx similarity index 96% rename from components/shared/skeletons/category-report-skeleton.tsx rename to src/shared/components/skeletons/category-report-skeleton.tsx index 168371b..77516d7 100644 --- a/components/shared/skeletons/category-report-skeleton.tsx +++ b/src/shared/components/skeletons/category-report-skeleton.tsx @@ -1,5 +1,5 @@ -import { Card } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card } from "@/shared/components/ui/card"; +import { Skeleton } from "@/shared/components/ui/skeleton"; import { Table, TableBody, @@ -8,8 +8,8 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; -import { Tabs, TabsContent, TabsList } from "@/components/ui/tabs"; +} from "@/shared/components/ui/table"; +import { Tabs, TabsContent, TabsList } from "@/shared/components/ui/tabs"; /** * Skeleton para a página de relatórios de categorias diff --git a/components/shared/skeletons/dashboard-grid-skeleton.tsx b/src/shared/components/skeletons/dashboard-grid-skeleton.tsx similarity index 100% rename from components/shared/skeletons/dashboard-grid-skeleton.tsx rename to src/shared/components/skeletons/dashboard-grid-skeleton.tsx diff --git a/components/shared/skeletons/dashboard-metrics-cards-skeleton.tsx b/src/shared/components/skeletons/dashboard-metrics-cards-skeleton.tsx similarity index 90% rename from components/shared/skeletons/dashboard-metrics-cards-skeleton.tsx rename to src/shared/components/skeletons/dashboard-metrics-cards-skeleton.tsx index 6e7f2ec..49e5e60 100644 --- a/components/shared/skeletons/dashboard-metrics-cards-skeleton.tsx +++ b/src/shared/components/skeletons/dashboard-metrics-cards-skeleton.tsx @@ -1,5 +1,5 @@ -import { Card, CardFooter, CardHeader } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card, CardFooter, CardHeader } from "@/shared/components/ui/card"; +import { Skeleton } from "@/shared/components/ui/skeleton"; /** * Skeleton fiel aos cards de métricas do dashboard (DashboardMetricsCards) diff --git a/components/shared/skeletons/filter-skeleton.tsx b/src/shared/components/skeletons/filter-skeleton.tsx similarity index 89% rename from components/shared/skeletons/filter-skeleton.tsx rename to src/shared/components/skeletons/filter-skeleton.tsx index 35103d0..9324e9e 100644 --- a/components/shared/skeletons/filter-skeleton.tsx +++ b/src/shared/components/skeletons/filter-skeleton.tsx @@ -1,4 +1,4 @@ -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/shared/components/ui/skeleton"; /** * Skeleton para os filtros de lançamentos diff --git a/components/shared/skeletons/index.ts b/src/shared/components/skeletons/index.ts similarity index 100% rename from components/shared/skeletons/index.ts rename to src/shared/components/skeletons/index.ts diff --git a/components/shared/skeletons/invoice-summary-card-skeleton.tsx b/src/shared/components/skeletons/invoice-summary-card-skeleton.tsx similarity index 97% rename from components/shared/skeletons/invoice-summary-card-skeleton.tsx rename to src/shared/components/skeletons/invoice-summary-card-skeleton.tsx index 51461f8..acc137f 100644 --- a/components/shared/skeletons/invoice-summary-card-skeleton.tsx +++ b/src/shared/components/skeletons/invoice-summary-card-skeleton.tsx @@ -1,4 +1,4 @@ -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/shared/components/ui/skeleton"; /** * Skeleton para o card de resumo da fatura (InvoiceSummaryCard) diff --git a/components/shared/skeletons/transactions-table-skeleton.tsx b/src/shared/components/skeletons/transactions-table-skeleton.tsx similarity index 96% rename from components/shared/skeletons/transactions-table-skeleton.tsx rename to src/shared/components/skeletons/transactions-table-skeleton.tsx index bae9337..bd26526 100644 --- a/components/shared/skeletons/transactions-table-skeleton.tsx +++ b/src/shared/components/skeletons/transactions-table-skeleton.tsx @@ -1,4 +1,4 @@ -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/shared/components/ui/skeleton"; import { Table, TableBody, @@ -6,7 +6,7 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; +} from "@/shared/components/ui/table"; /** * Skeleton fiel à tabela de lançamentos diff --git a/components/shared/skeletons/widget-skeleton.tsx b/src/shared/components/skeletons/widget-skeleton.tsx similarity index 91% rename from components/shared/skeletons/widget-skeleton.tsx rename to src/shared/components/skeletons/widget-skeleton.tsx index 1bf8a9a..443bd56 100644 --- a/components/shared/skeletons/widget-skeleton.tsx +++ b/src/shared/components/skeletons/widget-skeleton.tsx @@ -1,5 +1,5 @@ -import { Card, CardContent, CardHeader } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Card, CardContent, CardHeader } from "@/shared/components/ui/card"; +import { Skeleton } from "@/shared/components/ui/skeleton"; /** * Skeleton fiel ao WidgetCard diff --git a/components/shared/status-dot.tsx b/src/shared/components/status-dot.tsx similarity index 88% rename from components/shared/status-dot.tsx rename to src/shared/components/status-dot.tsx index ff14c2e..2353a2c 100644 --- a/components/shared/status-dot.tsx +++ b/src/shared/components/status-dot.tsx @@ -1,4 +1,4 @@ -import { cn } from "@/lib/utils"; +import { cn } from "@/shared/utils"; type StatusDotProps = { color: string; diff --git a/components/shared/type-badge.tsx b/src/shared/components/type-badge.tsx similarity index 93% rename from components/shared/type-badge.tsx rename to src/shared/components/type-badge.tsx index ca5ab1a..9124c7d 100644 --- a/components/shared/type-badge.tsx +++ b/src/shared/components/type-badge.tsx @@ -1,5 +1,5 @@ -import { Badge } from "@/components/ui/badge"; -import { cn } from "@/lib/utils/ui"; +import { Badge } from "@/shared/components/ui/badge"; +import { cn } from "@/shared/utils/ui"; import StatusDot from "./status-dot"; type TypeBadgeType = diff --git a/components/ui/alert-dialog.tsx b/src/shared/components/ui/alert-dialog.tsx similarity index 97% rename from components/ui/alert-dialog.tsx rename to src/shared/components/ui/alert-dialog.tsx index 7e11f40..9fe9bbd 100644 --- a/components/ui/alert-dialog.tsx +++ b/src/shared/components/ui/alert-dialog.tsx @@ -2,8 +2,8 @@ import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; import type * as React from "react"; -import { buttonVariants } from "@/components/ui/button"; -import { cn } from "@/lib/utils/ui"; +import { buttonVariants } from "@/shared/components/ui/button"; +import { cn } from "@/shared/utils/ui"; function AlertDialog({ ...props diff --git a/components/ui/alert.tsx b/src/shared/components/ui/alert.tsx similarity index 97% rename from components/ui/alert.tsx rename to src/shared/components/ui/alert.tsx index 52a2893..d49616d 100644 --- a/components/ui/alert.tsx +++ b/src/shared/components/ui/alert.tsx @@ -1,7 +1,7 @@ import { cva, type VariantProps } from "class-variance-authority"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; const alertVariants = cva( "relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", diff --git a/components/ui/avatar.tsx b/src/shared/components/ui/avatar.tsx similarity index 96% rename from components/ui/avatar.tsx rename to src/shared/components/ui/avatar.tsx index a72f97a..a206530 100644 --- a/components/ui/avatar.tsx +++ b/src/shared/components/ui/avatar.tsx @@ -3,7 +3,7 @@ import * as AvatarPrimitive from "@radix-ui/react-avatar"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Avatar({ className, diff --git a/components/ui/badge.tsx b/src/shared/components/ui/badge.tsx similarity index 97% rename from components/ui/badge.tsx rename to src/shared/components/ui/badge.tsx index 5e74377..2150637 100644 --- a/components/ui/badge.tsx +++ b/src/shared/components/ui/badge.tsx @@ -2,7 +2,7 @@ import { Slot } from "@radix-ui/react-slot"; import { cva, type VariantProps } from "class-variance-authority"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; const badgeVariants = cva( "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", diff --git a/components/ui/button.tsx b/src/shared/components/ui/button.tsx similarity index 98% rename from components/ui/button.tsx rename to src/shared/components/ui/button.tsx index c244655..765fab7 100644 --- a/components/ui/button.tsx +++ b/src/shared/components/ui/button.tsx @@ -2,7 +2,7 @@ import { Slot } from "@radix-ui/react-slot"; import { cva, type VariantProps } from "class-variance-authority"; import type * as React from "react"; -import { cn } from "@/lib/utils"; +import { cn } from "@/shared/utils"; const buttonVariants = cva( "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", diff --git a/components/ui/calendar.tsx b/src/shared/components/ui/calendar.tsx similarity index 98% rename from components/ui/calendar.tsx rename to src/shared/components/ui/calendar.tsx index 76e41cd..ae6ad33 100644 --- a/components/ui/calendar.tsx +++ b/src/shared/components/ui/calendar.tsx @@ -11,8 +11,8 @@ import { DayPicker, getDefaultClassNames, } from "react-day-picker"; -import { Button, buttonVariants } from "@/components/ui/button"; -import { cn } from "@/lib/utils/ui"; +import { Button, buttonVariants } from "@/shared/components/ui/button"; +import { cn } from "@/shared/utils/ui"; function Calendar({ className, diff --git a/components/ui/card.tsx b/src/shared/components/ui/card.tsx similarity index 97% rename from components/ui/card.tsx rename to src/shared/components/ui/card.tsx index f4c56a3..d814896 100644 --- a/components/ui/card.tsx +++ b/src/shared/components/ui/card.tsx @@ -1,6 +1,6 @@ import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Card({ className, ...props }: React.ComponentProps<"div">) { return ( diff --git a/components/ui/chart.tsx b/src/shared/components/ui/chart.tsx similarity index 99% rename from components/ui/chart.tsx rename to src/shared/components/ui/chart.tsx index 206d35c..58ed675 100644 --- a/components/ui/chart.tsx +++ b/src/shared/components/ui/chart.tsx @@ -3,7 +3,7 @@ import * as React from "react"; import * as RechartsPrimitive from "recharts"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; // Format: { THEME_NAME: CSS_SELECTOR } const THEMES = { light: "", dark: ".dark" } as const; diff --git a/components/ui/checkbox.tsx b/src/shared/components/ui/checkbox.tsx similarity index 96% rename from components/ui/checkbox.tsx rename to src/shared/components/ui/checkbox.tsx index f97198a..4c37dc4 100644 --- a/components/ui/checkbox.tsx +++ b/src/shared/components/ui/checkbox.tsx @@ -3,7 +3,7 @@ import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; import { RiCheckLine } from "@remixicon/react"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Checkbox({ className, diff --git a/components/ui/collapsible.tsx b/src/shared/components/ui/collapsible.tsx similarity index 100% rename from components/ui/collapsible.tsx rename to src/shared/components/ui/collapsible.tsx diff --git a/components/ui/command.tsx b/src/shared/components/ui/command.tsx similarity index 98% rename from components/ui/command.tsx rename to src/shared/components/ui/command.tsx index 64f4e1b..a5b696f 100644 --- a/components/ui/command.tsx +++ b/src/shared/components/ui/command.tsx @@ -9,8 +9,8 @@ import { DialogDescription, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/dialog"; +import { cn } from "@/shared/utils/ui"; function Command({ className, diff --git a/components/ui/currency-input.tsx b/src/shared/components/ui/currency-input.tsx similarity index 98% rename from components/ui/currency-input.tsx rename to src/shared/components/ui/currency-input.tsx index 6356a00..5bd2d55 100644 --- a/components/ui/currency-input.tsx +++ b/src/shared/components/ui/currency-input.tsx @@ -2,7 +2,7 @@ import * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; import { Input } from "./input"; const BRL_FORMATTER = new Intl.NumberFormat("pt-BR", { diff --git a/components/ui/date-picker.tsx b/src/shared/components/ui/date-picker.tsx similarity index 92% rename from components/ui/date-picker.tsx rename to src/shared/components/ui/date-picker.tsx index b334598..51b2f47 100644 --- a/components/ui/date-picker.tsx +++ b/src/shared/components/ui/date-picker.tsx @@ -4,16 +4,16 @@ import { RiCalendarLine } from "@remixicon/react"; import { ptBR } from "date-fns/locale"; import * as React from "react"; -import { Button } from "@/components/ui/button"; -import { Calendar } from "@/components/ui/calendar"; -import { Input } from "@/components/ui/input"; +import { Button } from "@/shared/components/ui/button"; +import { Calendar } from "@/shared/components/ui/calendar"; +import { Input } from "@/shared/components/ui/input"; import { Popover, PopoverContent, PopoverTrigger, -} from "@/components/ui/popover"; -import { parseLocalDateString, toLocalDateString } from "@/lib/utils/date"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/popover"; +import { parseLocalDateString, toLocalDateString } from "@/shared/utils/date"; +import { cn } from "@/shared/utils/ui"; function formatDate(date: Date | undefined, compact = false): string { if (!date) { diff --git a/components/ui/dialog.tsx b/src/shared/components/ui/dialog.tsx similarity index 98% rename from components/ui/dialog.tsx rename to src/shared/components/ui/dialog.tsx index 3293414..0e16aad 100644 --- a/components/ui/dialog.tsx +++ b/src/shared/components/ui/dialog.tsx @@ -3,7 +3,7 @@ import * as DialogPrimitive from "@radix-ui/react-dialog"; import { RiCloseLine } from "@remixicon/react"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Dialog({ ...props diff --git a/components/ui/drawer.tsx b/src/shared/components/ui/drawer.tsx similarity index 99% rename from components/ui/drawer.tsx rename to src/shared/components/ui/drawer.tsx index b480de3..8d6eefe 100644 --- a/components/ui/drawer.tsx +++ b/src/shared/components/ui/drawer.tsx @@ -3,7 +3,7 @@ import type * as React from "react"; import { Drawer as DrawerPrimitive } from "vaul"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Drawer({ ...props diff --git a/components/ui/dropdown-menu.tsx b/src/shared/components/ui/dropdown-menu.tsx similarity index 99% rename from components/ui/dropdown-menu.tsx rename to src/shared/components/ui/dropdown-menu.tsx index 5d7750c..763f7a7 100644 --- a/components/ui/dropdown-menu.tsx +++ b/src/shared/components/ui/dropdown-menu.tsx @@ -8,7 +8,7 @@ import { } from "@remixicon/react"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function DropdownMenu({ ...props diff --git a/components/ui/empty.tsx b/src/shared/components/ui/empty.tsx similarity index 98% rename from components/ui/empty.tsx rename to src/shared/components/ui/empty.tsx index 57ecf8d..762b11f 100644 --- a/components/ui/empty.tsx +++ b/src/shared/components/ui/empty.tsx @@ -1,6 +1,6 @@ import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Empty({ className, ...props }: React.ComponentProps<"div">) { return ( diff --git a/components/ui/field.tsx b/src/shared/components/ui/field.tsx similarity index 97% rename from components/ui/field.tsx rename to src/shared/components/ui/field.tsx index 2509746..65f5679 100644 --- a/components/ui/field.tsx +++ b/src/shared/components/ui/field.tsx @@ -2,9 +2,9 @@ import { cva, type VariantProps } from "class-variance-authority"; import { useMemo } from "react"; -import { Label } from "@/components/ui/label"; -import { Separator } from "@/components/ui/separator"; -import { cn } from "@/lib/utils/ui"; +import { Label } from "@/shared/components/ui/label"; +import { Separator } from "@/shared/components/ui/separator"; +import { cn } from "@/shared/utils/ui"; function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) { return ( diff --git a/components/ui/hover-card.tsx b/src/shared/components/ui/hover-card.tsx similarity index 97% rename from components/ui/hover-card.tsx rename to src/shared/components/ui/hover-card.tsx index ba518a1..787cb9a 100644 --- a/components/ui/hover-card.tsx +++ b/src/shared/components/ui/hover-card.tsx @@ -3,7 +3,7 @@ import * as HoverCardPrimitive from "@radix-ui/react-hover-card"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function HoverCard({ ...props diff --git a/components/ui/input.tsx b/src/shared/components/ui/input.tsx similarity index 95% rename from components/ui/input.tsx rename to src/shared/components/ui/input.tsx index 322403b..7aa5b3a 100644 --- a/components/ui/input.tsx +++ b/src/shared/components/ui/input.tsx @@ -1,6 +1,6 @@ import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Input({ className, type, ...props }: React.ComponentProps<"input">) { return ( diff --git a/components/ui/item.tsx b/src/shared/components/ui/item.tsx similarity index 97% rename from components/ui/item.tsx rename to src/shared/components/ui/item.tsx index 4257ff8..98b1bf4 100644 --- a/components/ui/item.tsx +++ b/src/shared/components/ui/item.tsx @@ -1,8 +1,8 @@ import { Slot } from "@radix-ui/react-slot"; import { cva, type VariantProps } from "class-variance-authority"; import type * as React from "react"; -import { Separator } from "@/components/ui/separator"; -import { cn } from "@/lib/utils"; +import { Separator } from "@/shared/components/ui/separator"; +import { cn } from "@/shared/utils"; function ItemGroup({ className, ...props }: React.ComponentProps<"div">) { return ( diff --git a/components/ui/label.tsx b/src/shared/components/ui/label.tsx similarity index 93% rename from components/ui/label.tsx rename to src/shared/components/ui/label.tsx index 1745fc2..848eba3 100644 --- a/components/ui/label.tsx +++ b/src/shared/components/ui/label.tsx @@ -3,7 +3,7 @@ import * as LabelPrimitive from "@radix-ui/react-label"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Label({ className, diff --git a/components/ui/month-picker.tsx b/src/shared/components/ui/month-picker.tsx similarity index 99% rename from components/ui/month-picker.tsx rename to src/shared/components/ui/month-picker.tsx index e201d8c..7ab4053 100644 --- a/components/ui/month-picker.tsx +++ b/src/shared/components/ui/month-picker.tsx @@ -1,7 +1,7 @@ "use client"; import { RiArrowLeftSFill, RiArrowRightSFill } from "@remixicon/react"; import * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; import { buttonVariants } from "./button"; type Month = { diff --git a/components/ui/navigation-menu.tsx b/src/shared/components/ui/navigation-menu.tsx similarity index 99% rename from components/ui/navigation-menu.tsx rename to src/shared/components/ui/navigation-menu.tsx index 3256b02..d1d3432 100644 --- a/components/ui/navigation-menu.tsx +++ b/src/shared/components/ui/navigation-menu.tsx @@ -2,7 +2,7 @@ import { RiArrowDropDownLine } from "@remixicon/react"; import { cva } from "class-variance-authority"; import { NavigationMenu as NavigationMenuPrimitive } from "radix-ui"; import type * as React from "react"; -import { cn } from "@/lib/utils"; +import { cn } from "@/shared/utils"; function NavigationMenu({ className, diff --git a/components/ui/popover.tsx b/src/shared/components/ui/popover.tsx similarity index 97% rename from components/ui/popover.tsx rename to src/shared/components/ui/popover.tsx index 48cc674..c846980 100644 --- a/components/ui/popover.tsx +++ b/src/shared/components/ui/popover.tsx @@ -3,7 +3,7 @@ import * as PopoverPrimitive from "@radix-ui/react-popover"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Popover({ ...props diff --git a/components/ui/progress.tsx b/src/shared/components/ui/progress.tsx similarity index 94% rename from components/ui/progress.tsx rename to src/shared/components/ui/progress.tsx index a0554a3..6fb2cf8 100644 --- a/components/ui/progress.tsx +++ b/src/shared/components/ui/progress.tsx @@ -3,7 +3,7 @@ import * as ProgressPrimitive from "@radix-ui/react-progress"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Progress({ className, diff --git a/components/ui/radio-group.tsx b/src/shared/components/ui/radio-group.tsx similarity index 97% rename from components/ui/radio-group.tsx rename to src/shared/components/ui/radio-group.tsx index e2f78d3..f7d61ac 100644 --- a/components/ui/radio-group.tsx +++ b/src/shared/components/ui/radio-group.tsx @@ -3,7 +3,7 @@ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"; import { RiCircleLine } from "@remixicon/react"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function RadioGroup({ className, diff --git a/components/ui/select.tsx b/src/shared/components/ui/select.tsx similarity index 99% rename from components/ui/select.tsx rename to src/shared/components/ui/select.tsx index 431ec42..9a05e7d 100644 --- a/components/ui/select.tsx +++ b/src/shared/components/ui/select.tsx @@ -7,7 +7,7 @@ import { RiCheckLine, } from "@remixicon/react"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Select({ ...props diff --git a/components/ui/separator.tsx b/src/shared/components/ui/separator.tsx similarity index 94% rename from components/ui/separator.tsx rename to src/shared/components/ui/separator.tsx index 50f035f..0737619 100644 --- a/components/ui/separator.tsx +++ b/src/shared/components/ui/separator.tsx @@ -3,7 +3,7 @@ import * as SeparatorPrimitive from "@radix-ui/react-separator"; import type * as React from "react"; -import { cn } from "@/lib/utils"; +import { cn } from "@/shared/utils"; function Separator({ className, diff --git a/components/ui/sheet.tsx b/src/shared/components/ui/sheet.tsx similarity index 98% rename from components/ui/sheet.tsx rename to src/shared/components/ui/sheet.tsx index 9ed2585..b3dd145 100644 --- a/components/ui/sheet.tsx +++ b/src/shared/components/ui/sheet.tsx @@ -3,7 +3,7 @@ import * as SheetPrimitive from "@radix-ui/react-dialog"; import { RiCloseLine } from "@remixicon/react"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Sheet({ ...props }: React.ComponentProps) { return ; diff --git a/components/ui/sidebar.tsx b/src/shared/components/ui/sidebar.tsx similarity index 98% rename from components/ui/sidebar.tsx rename to src/shared/components/ui/sidebar.tsx index e8474a6..aadc9c6 100644 --- a/components/ui/sidebar.tsx +++ b/src/shared/components/ui/sidebar.tsx @@ -4,24 +4,24 @@ import { Slot } from "@radix-ui/react-slot"; import { RiLayoutLeft2Line } from "@remixicon/react"; import { cva, type VariantProps } from "class-variance-authority"; import * as React from "react"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Separator } from "@/components/ui/separator"; +import { Button } from "@/shared/components/ui/button"; +import { Input } from "@/shared/components/ui/input"; +import { Separator } from "@/shared/components/ui/separator"; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, -} from "@/components/ui/sheet"; -import { Skeleton } from "@/components/ui/skeleton"; +} from "@/shared/components/ui/sheet"; +import { Skeleton } from "@/shared/components/ui/skeleton"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, -} from "@/components/ui/tooltip"; -import { cn } from "@/lib/utils/ui"; +} from "@/shared/components/ui/tooltip"; +import { cn } from "@/shared/utils/ui"; import { useIsMobile } from "./use-mobile"; const SIDEBAR_COOKIE_NAME = "sidebar_state"; diff --git a/components/ui/skeleton.tsx b/src/shared/components/ui/skeleton.tsx similarity index 85% rename from components/ui/skeleton.tsx rename to src/shared/components/ui/skeleton.tsx index 8665739..7504610 100644 --- a/components/ui/skeleton.tsx +++ b/src/shared/components/ui/skeleton.tsx @@ -1,4 +1,4 @@ -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Skeleton({ className, ...props }: React.ComponentProps<"div">) { return ( diff --git a/components/ui/slider.tsx b/src/shared/components/ui/slider.tsx similarity index 96% rename from components/ui/slider.tsx rename to src/shared/components/ui/slider.tsx index 250cc19..060133a 100644 --- a/components/ui/slider.tsx +++ b/src/shared/components/ui/slider.tsx @@ -2,7 +2,7 @@ import { Slider as SliderPrimitive } from "radix-ui"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Slider({ className, diff --git a/components/ui/sonner.tsx b/src/shared/components/ui/sonner.tsx similarity index 100% rename from components/ui/sonner.tsx rename to src/shared/components/ui/sonner.tsx diff --git a/components/ui/spinner.tsx b/src/shared/components/ui/spinner.tsx similarity index 87% rename from components/ui/spinner.tsx rename to src/shared/components/ui/spinner.tsx index b5e0fc3..8ce86e3 100644 --- a/components/ui/spinner.tsx +++ b/src/shared/components/ui/spinner.tsx @@ -1,5 +1,5 @@ import { RiLoader4Line } from "@remixicon/react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Spinner({ className, ...props }: React.ComponentProps<"svg">) { return ( diff --git a/components/ui/switch.tsx b/src/shared/components/ui/switch.tsx similarity index 96% rename from components/ui/switch.tsx rename to src/shared/components/ui/switch.tsx index d05ed76..56916f0 100644 --- a/components/ui/switch.tsx +++ b/src/shared/components/ui/switch.tsx @@ -3,7 +3,7 @@ import * as SwitchPrimitive from "@radix-ui/react-switch"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Switch({ className, diff --git a/components/ui/table.tsx b/src/shared/components/ui/table.tsx similarity index 98% rename from components/ui/table.tsx rename to src/shared/components/ui/table.tsx index 8341aae..cef5b37 100644 --- a/components/ui/table.tsx +++ b/src/shared/components/ui/table.tsx @@ -2,7 +2,7 @@ import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Table({ className, ...props }: React.ComponentProps<"table">) { return ( diff --git a/components/ui/tabs.tsx b/src/shared/components/ui/tabs.tsx similarity index 97% rename from components/ui/tabs.tsx rename to src/shared/components/ui/tabs.tsx index 6b81ffc..e3b2f5a 100644 --- a/components/ui/tabs.tsx +++ b/src/shared/components/ui/tabs.tsx @@ -3,7 +3,7 @@ import * as TabsPrimitive from "@radix-ui/react-tabs"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Tabs({ className, diff --git a/components/ui/textarea.tsx b/src/shared/components/ui/textarea.tsx similarity index 94% rename from components/ui/textarea.tsx rename to src/shared/components/ui/textarea.tsx index 11078f7..2a3f585 100644 --- a/components/ui/textarea.tsx +++ b/src/shared/components/ui/textarea.tsx @@ -1,6 +1,6 @@ import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { return ( diff --git a/components/ui/toggle-group.tsx b/src/shared/components/ui/toggle-group.tsx similarity index 94% rename from components/ui/toggle-group.tsx rename to src/shared/components/ui/toggle-group.tsx index ae1697b..6cea7d0 100644 --- a/components/ui/toggle-group.tsx +++ b/src/shared/components/ui/toggle-group.tsx @@ -3,8 +3,8 @@ import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"; import type { VariantProps } from "class-variance-authority"; import * as React from "react"; -import { toggleVariants } from "@/components/ui/toggle"; -import { cn } from "@/lib/utils/ui"; +import { toggleVariants } from "@/shared/components/ui/toggle"; +import { cn } from "@/shared/utils/ui"; const ToggleGroupContext = React.createContext< VariantProps diff --git a/components/ui/toggle.tsx b/src/shared/components/ui/toggle.tsx similarity index 97% rename from components/ui/toggle.tsx rename to src/shared/components/ui/toggle.tsx index e15fd6d..5721e27 100644 --- a/components/ui/toggle.tsx +++ b/src/shared/components/ui/toggle.tsx @@ -4,7 +4,7 @@ import * as TogglePrimitive from "@radix-ui/react-toggle"; import { cva, type VariantProps } from "class-variance-authority"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; const toggleVariants = cva( "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap", diff --git a/components/ui/tooltip.tsx b/src/shared/components/ui/tooltip.tsx similarity index 97% rename from components/ui/tooltip.tsx rename to src/shared/components/ui/tooltip.tsx index 000575f..6af3b84 100644 --- a/components/ui/tooltip.tsx +++ b/src/shared/components/ui/tooltip.tsx @@ -3,7 +3,7 @@ import * as TooltipPrimitive from "@radix-ui/react-tooltip"; import type * as React from "react"; -import { cn } from "@/lib/utils/ui"; +import { cn } from "@/shared/utils/ui"; function TooltipProvider({ delayDuration = 0, diff --git a/src/shared/components/ui/use-mobile.ts b/src/shared/components/ui/use-mobile.ts new file mode 100644 index 0000000..5772abc --- /dev/null +++ b/src/shared/components/ui/use-mobile.ts @@ -0,0 +1 @@ +export { useIsMobile, useMobile } from "@/shared/hooks/use-mobile"; diff --git a/components/shared/widget-card.tsx b/src/shared/components/widget-card.tsx similarity index 86% rename from components/shared/widget-card.tsx rename to src/shared/components/widget-card.tsx index 5d6e49d..eeeb941 100644 --- a/components/shared/widget-card.tsx +++ b/src/shared/components/widget-card.tsx @@ -5,8 +5,8 @@ import { CardDescription, CardHeader, CardTitle, -} from "@/components/ui/card"; -import { Separator } from "@/components/ui/separator"; +} from "@/shared/components/ui/card"; +import { Separator } from "@/shared/components/ui/separator"; export type WidgetCardProps = { title: string; @@ -37,7 +37,7 @@ export default function WidgetCard({
- + {icon} {title} diff --git a/components/shared/widget-empty-state.tsx b/src/shared/components/widget-empty-state.tsx similarity index 92% rename from components/shared/widget-empty-state.tsx rename to src/shared/components/widget-empty-state.tsx index c4554dc..8a1cc15 100644 --- a/components/shared/widget-empty-state.tsx +++ b/src/shared/components/widget-empty-state.tsx @@ -5,7 +5,7 @@ import { EmptyHeader, EmptyMedia, EmptyTitle, -} from "@/components/ui/empty"; +} from "@/shared/components/ui/empty"; type WidgetEmptyStateProps = { icon?: ReactNode; diff --git a/lib/hooks/index.ts b/src/shared/hooks/index.ts similarity index 100% rename from lib/hooks/index.ts rename to src/shared/hooks/index.ts diff --git a/lib/hooks/use-controlled-state.ts b/src/shared/hooks/use-controlled-state.ts similarity index 100% rename from lib/hooks/use-controlled-state.ts rename to src/shared/hooks/use-controlled-state.ts diff --git a/lib/hooks/use-form-state.ts b/src/shared/hooks/use-form-state.ts similarity index 100% rename from lib/hooks/use-form-state.ts rename to src/shared/hooks/use-form-state.ts diff --git a/lib/hooks/use-mobile.ts b/src/shared/hooks/use-mobile.ts similarity index 100% rename from lib/hooks/use-mobile.ts rename to src/shared/hooks/use-mobile.ts diff --git a/lib/contas/constants.ts b/src/shared/lib/accounts/constants.ts similarity index 94% rename from lib/contas/constants.ts rename to src/shared/lib/accounts/constants.ts index 83b4f17..709786a 100644 --- a/lib/contas/constants.ts +++ b/src/shared/lib/accounts/constants.ts @@ -2,7 +2,7 @@ import { LANCAMENTO_CONDITIONS, LANCAMENTO_PAYMENT_METHODS, LANCAMENTO_TRANSACTION_TYPES, -} from "@/lib/lancamentos/constants"; +} from "@/features/transactions/constants"; export const INITIAL_BALANCE_CATEGORY_NAME = "Saldo inicial"; export const INITIAL_BALANCE_NOTE = "saldo inicial"; diff --git a/lib/actions/helpers.ts b/src/shared/lib/actions/helpers.ts similarity index 66% rename from lib/actions/helpers.ts rename to src/shared/lib/actions/helpers.ts index b85dc19..7b94982 100644 --- a/lib/actions/helpers.ts +++ b/src/shared/lib/actions/helpers.ts @@ -1,7 +1,10 @@ import { revalidatePath, revalidateTag } from "next/cache"; import { z } from "zod"; -import type { ActionResult } from "@/lib/types/actions"; -import { errorResult } from "@/lib/types/actions"; + +export type { ActionResult } from "@/shared/lib/types/actions"; + +import type { ActionResult } from "@/shared/lib/types/actions"; +import { errorResult } from "@/shared/lib/types/actions"; /** * Handles errors in server actions consistently @@ -21,15 +24,16 @@ export function handleActionError(error: unknown): ActionResult { * Configuration for revalidation after mutations */ export const revalidateConfig = { - cartoes: ["/cartoes", "/contas", "/lancamentos"], - contas: ["/contas", "/lancamentos"], - categorias: ["/categorias"], - estabelecimentos: ["/estabelecimentos", "/lancamentos"], - orcamentos: ["/orcamentos"], - pagadores: ["/pagadores"], - anotacoes: ["/anotacoes", "/anotacoes/arquivadas", "/dashboard"], - lancamentos: ["/lancamentos", "/contas"], - inbox: ["/pre-lancamentos", "/lancamentos", "/dashboard"], + cartoes: ["/cards", "/accounts", "/transactions"], + contas: ["/accounts", "/transactions"], + categorias: ["/categories"], + estabelecimentos: ["/reports/establishments", "/transactions"], + orcamentos: ["/budgets"], + pagadores: ["/payers"], + anotacoes: ["/notes", "/notes/arquivadas", "/dashboard"], + lancamentos: ["/transactions", "/accounts"], + inbox: ["/inbox", "/transactions", "/dashboard"], + recorrentes: ["/transactions", "/dashboard"], } as const; /** Entities whose mutations should invalidate the dashboard cache */ @@ -41,6 +45,7 @@ const DASHBOARD_ENTITIES: ReadonlySet = new Set([ "pagadores", "anotacoes", "inbox", + "recorrentes", ]); /** diff --git a/lib/auth/api-token.ts b/src/shared/lib/auth/api-token.ts similarity index 100% rename from lib/auth/api-token.ts rename to src/shared/lib/auth/api-token.ts diff --git a/lib/auth/client.ts b/src/shared/lib/auth/client.ts similarity index 100% rename from lib/auth/client.ts rename to src/shared/lib/auth/client.ts diff --git a/lib/auth/config.ts b/src/shared/lib/auth/config.ts similarity index 93% rename from lib/auth/config.ts rename to src/shared/lib/auth/config.ts index fa3d62a..eb4a01a 100644 --- a/lib/auth/config.ts +++ b/src/shared/lib/auth/config.ts @@ -2,10 +2,10 @@ import { passkey } from "@better-auth/passkey"; import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import type { GoogleProfile } from "better-auth/social-providers"; -import { seedDefaultCategoriesForUser } from "@/lib/categorias/defaults"; -import { db, schema } from "@/lib/db"; -import { ensureDefaultPagadorForUser } from "@/lib/pagadores/defaults"; -import { normalizeNameFromEmail } from "@/lib/pagadores/utils"; +import { seedDefaultCategoriesForUser } from "@/shared/lib/categories/defaults"; +import { db, schema } from "@/shared/lib/db"; +import { ensureDefaultPagadorForUser } from "@/shared/lib/payers/defaults"; +import { normalizeNameFromEmail } from "@/shared/lib/payers/utils"; // ============================================================================ // GOOGLE OAUTH CONFIGURATION diff --git a/lib/auth/server.ts b/src/shared/lib/auth/server.ts similarity index 96% rename from lib/auth/server.ts rename to src/shared/lib/auth/server.ts index 567c70c..f436d5e 100644 --- a/lib/auth/server.ts +++ b/src/shared/lib/auth/server.ts @@ -1,7 +1,7 @@ import { headers } from "next/headers"; import { redirect } from "next/navigation"; import { cache } from "react"; -import { auth } from "@/lib/auth/config"; +import { auth } from "@/shared/lib/auth/config"; /** * Cached session fetch - deduplicates auth calls within a single request. diff --git a/lib/calculadora/use-calculator-keyboard.ts b/src/shared/lib/calculator/use-calculator-keyboard.ts similarity index 98% rename from lib/calculadora/use-calculator-keyboard.ts rename to src/shared/lib/calculator/use-calculator-keyboard.ts index 8e1a711..1210a7a 100644 --- a/lib/calculadora/use-calculator-keyboard.ts +++ b/src/shared/lib/calculator/use-calculator-keyboard.ts @@ -1,5 +1,5 @@ import { useEffect } from "react"; -import type { Operator } from "@/lib/utils/calculator"; +import type { Operator } from "@/shared/utils/calculator"; type UseCalculatorKeyboardParams = { isOpen: boolean; diff --git a/lib/calculadora/use-calculator-state.ts b/src/shared/lib/calculator/use-calculator-state.ts similarity index 98% rename from lib/calculadora/use-calculator-state.ts rename to src/shared/lib/calculator/use-calculator-state.ts index c98a9d2..874e7e1 100644 --- a/lib/calculadora/use-calculator-state.ts +++ b/src/shared/lib/calculator/use-calculator-state.ts @@ -1,6 +1,6 @@ import type { VariantProps } from "class-variance-authority"; import { useEffect, useRef, useState } from "react"; -import type { buttonVariants } from "@/components/ui/button"; +import type { buttonVariants } from "@/shared/components/ui/button"; import { formatLocaleValue, formatNumber, @@ -8,7 +8,7 @@ import { OPERATOR_SYMBOLS, type Operator, performOperation, -} from "@/lib/utils/calculator"; +} from "@/shared/utils/calculator"; export type CalculatorButtonConfig = { label: string; diff --git a/lib/calculadora/use-draggable-dialog.ts b/src/shared/lib/calculator/use-draggable-dialog.ts similarity index 100% rename from lib/calculadora/use-draggable-dialog.ts rename to src/shared/lib/calculator/use-draggable-dialog.ts diff --git a/lib/cartoes/brand-assets.ts b/src/shared/lib/cards/brand-assets.ts similarity index 80% rename from lib/cartoes/brand-assets.ts rename to src/shared/lib/cards/brand-assets.ts index b752443..d7667bc 100644 --- a/lib/cartoes/brand-assets.ts +++ b/src/shared/lib/cards/brand-assets.ts @@ -1,11 +1,11 @@ const CARD_BRAND_ASSET_BY_KEY = { - visa: "/bandeiras/visa.svg", - mastercard: "/bandeiras/mastercard.svg", - amex: "/bandeiras/amex.svg", - american: "/bandeiras/amex.svg", - elo: "/bandeiras/elo.svg", - hipercard: "/bandeiras/hipercard.svg", - hiper: "/bandeiras/hipercard.svg", + visa: "/flags/visa.svg", + mastercard: "/flags/mastercard.svg", + amex: "/flags/amex.svg", + american: "/flags/amex.svg", + elo: "/flags/elo.svg", + hipercard: "/flags/hipercard.svg", + hiper: "/flags/hipercard.svg", } as const; const CARD_BRAND_LOGO_BY_KEY = { diff --git a/lib/cartoes/constants.ts b/src/shared/lib/cards/constants.ts similarity index 100% rename from lib/cartoes/constants.ts rename to src/shared/lib/cards/constants.ts diff --git a/lib/categorias/constants.ts b/src/shared/lib/categories/constants.ts similarity index 100% rename from lib/categorias/constants.ts rename to src/shared/lib/categories/constants.ts diff --git a/lib/categorias/defaults.ts b/src/shared/lib/categories/defaults.ts similarity index 96% rename from lib/categorias/defaults.ts rename to src/shared/lib/categories/defaults.ts index 5a34769..70049a4 100644 --- a/lib/categorias/defaults.ts +++ b/src/shared/lib/categories/defaults.ts @@ -1,7 +1,7 @@ import { eq } from "drizzle-orm"; import { categorias } from "@/db/schema"; -import type { CategoryType } from "@/lib/categorias/constants"; -import { db } from "@/lib/db"; +import type { CategoryType } from "@/shared/lib/categories/constants"; +import { db } from "@/shared/lib/db"; type DefaultCategory = { name: string; diff --git a/lib/categorias/icons.ts b/src/shared/lib/categories/icons.ts similarity index 100% rename from lib/categorias/icons.ts rename to src/shared/lib/categories/icons.ts diff --git a/lib/db.ts b/src/shared/lib/db.ts similarity index 74% rename from lib/db.ts rename to src/shared/lib/db.ts index e900fde..f8a9f45 100644 --- a/lib/db.ts +++ b/src/shared/lib/db.ts @@ -1,13 +1,13 @@ -import { drizzle, type PgDatabase } from "drizzle-orm/node-postgres"; +import { drizzle, type NodePgDatabase } from "drizzle-orm/node-postgres"; import { Pool } from "pg"; import * as schema from "@/db/schema"; const globalForDb = globalThis as unknown as { - db?: PgDatabase; + db?: NodePgDatabase; pool?: Pool; }; -let _db: PgDatabase | undefined; +let _db: NodePgDatabase | undefined; let _pool: Pool | undefined; function getDb() { @@ -30,7 +30,7 @@ function getDb() { return _db; } -export const db = new Proxy({} as PgDatabase, { +export const db = new Proxy({} as NodePgDatabase, { get(_, prop) { return Reflect.get(getDb(), prop); }, diff --git a/lib/email/resend.ts b/src/shared/lib/email/resend.ts similarity index 100% rename from lib/email/resend.ts rename to src/shared/lib/email/resend.ts diff --git a/lib/installments/anticipation-helpers.ts b/src/shared/lib/installments/anticipation-helpers.ts similarity index 100% rename from lib/installments/anticipation-helpers.ts rename to src/shared/lib/installments/anticipation-helpers.ts diff --git a/lib/installments/anticipation-types.ts b/src/shared/lib/installments/anticipation-types.ts similarity index 100% rename from lib/installments/anticipation-types.ts rename to src/shared/lib/installments/anticipation-types.ts diff --git a/lib/installments/utils.ts b/src/shared/lib/installments/utils.ts similarity index 96% rename from lib/installments/utils.ts rename to src/shared/lib/installments/utils.ts index 86c87e4..f3402df 100644 --- a/lib/installments/utils.ts +++ b/src/shared/lib/installments/utils.ts @@ -1,4 +1,4 @@ -import { displayPeriod, periodToDate } from "@/lib/utils/period"; +import { displayPeriod, periodToDate } from "@/shared/utils/period"; /** * Calcula a data da última parcela baseado no período da parcela atual diff --git a/lib/faturas/index.ts b/src/shared/lib/invoices/index.ts similarity index 100% rename from lib/faturas/index.ts rename to src/shared/lib/invoices/index.ts diff --git a/lib/logo/index.ts b/src/shared/lib/logo/index.ts similarity index 100% rename from lib/logo/index.ts rename to src/shared/lib/logo/index.ts diff --git a/lib/logo/options.ts b/src/shared/lib/logo/options.ts similarity index 100% rename from lib/logo/options.ts rename to src/shared/lib/logo/options.ts diff --git a/lib/pagadores/access.ts b/src/shared/lib/payers/access.ts similarity index 98% rename from lib/pagadores/access.ts rename to src/shared/lib/payers/access.ts index 147817a..8b8a619 100644 --- a/lib/pagadores/access.ts +++ b/src/shared/lib/payers/access.ts @@ -4,7 +4,7 @@ import { pagadores, user as usersTable, } from "@/db/schema"; -import { db } from "@/lib/db"; +import { db } from "@/shared/lib/db"; export type PagadorWithAccess = typeof pagadores.$inferSelect & { canEdit: boolean; diff --git a/lib/pagadores/constants.ts b/src/shared/lib/payers/constants.ts similarity index 100% rename from lib/pagadores/constants.ts rename to src/shared/lib/payers/constants.ts diff --git a/lib/pagadores/defaults.ts b/src/shared/lib/payers/defaults.ts similarity index 96% rename from lib/pagadores/defaults.ts rename to src/shared/lib/payers/defaults.ts index 9e89798..a6065e2 100644 --- a/lib/pagadores/defaults.ts +++ b/src/shared/lib/payers/defaults.ts @@ -1,6 +1,6 @@ import { eq } from "drizzle-orm"; import { pagadores } from "@/db/schema"; -import { db } from "@/lib/db"; +import { db } from "@/shared/lib/db"; import { DEFAULT_PAGADOR_AVATAR, PAGADOR_ROLE_ADMIN, diff --git a/lib/pagadores/details.ts b/src/shared/lib/payers/details.ts similarity index 96% rename from lib/pagadores/details.ts rename to src/shared/lib/payers/details.ts index 2c617af..5ffeec9 100644 --- a/lib/pagadores/details.ts +++ b/src/shared/lib/payers/details.ts @@ -12,15 +12,15 @@ import { sum, } from "drizzle-orm"; import { cartoes, lancamentos } from "@/db/schema"; -import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/contas/constants"; -import { db } from "@/lib/db"; -import { toDateOnlyString } from "@/lib/utils/date"; -import { safeToNumber as toNumber } from "@/lib/utils/number"; +import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants"; +import { db } from "@/shared/lib/db"; +import { toDateOnlyString } from "@/shared/utils/date"; +import { safeToNumber as toNumber } from "@/shared/utils/number"; import { addMonthsToPeriod, buildPeriodRange, formatCompactPeriodLabel, -} from "@/lib/utils/period"; +} from "@/shared/utils/period"; const RECEITA = "Receita"; const DESPESA = "Despesa"; diff --git a/lib/pagadores/get-admin-id.ts b/src/shared/lib/payers/get-admin-id.ts similarity index 85% rename from lib/pagadores/get-admin-id.ts rename to src/shared/lib/payers/get-admin-id.ts index f858dcb..1eb5062 100644 --- a/lib/pagadores/get-admin-id.ts +++ b/src/shared/lib/payers/get-admin-id.ts @@ -1,8 +1,8 @@ import { and, eq } from "drizzle-orm"; import { cache } from "react"; import { pagadores } from "@/db/schema"; -import { db } from "@/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; +import { db } from "@/shared/lib/db"; +import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; /** * Returns the admin pagador ID for a user (cached per request via React.cache). diff --git a/lib/pagadores/notifications.ts b/src/shared/lib/payers/notifications.ts similarity index 96% rename from lib/pagadores/notifications.ts rename to src/shared/lib/payers/notifications.ts index 479035f..7bc65cd 100644 --- a/lib/pagadores/notifications.ts +++ b/src/shared/lib/payers/notifications.ts @@ -1,10 +1,10 @@ import { inArray } from "drizzle-orm"; import { Resend } from "resend"; import { pagadores } from "@/db/schema"; -import { db } from "@/lib/db"; -import { getResendFromEmail } from "@/lib/email/resend"; -import { formatCurrency } from "@/lib/utils/currency"; -import { formatDateTime } from "@/lib/utils/date"; +import { db } from "@/shared/lib/db"; +import { getResendFromEmail } from "@/shared/lib/email/resend"; +import { formatCurrency } from "@/shared/utils/currency"; +import { formatDateTime } from "@/shared/utils/date"; type ActionType = "created" | "deleted"; diff --git a/lib/pagadores/utils.ts b/src/shared/lib/payers/utils.ts similarity index 93% rename from lib/pagadores/utils.ts rename to src/shared/lib/payers/utils.ts index 314f9a9..1a95bc8 100644 --- a/lib/pagadores/utils.ts +++ b/src/shared/lib/payers/utils.ts @@ -29,7 +29,7 @@ export const normalizeAvatarPath = ( */ export const getAvatarSrc = (avatar: string | null | undefined): string => { if (!avatar) { - return `/avatares/${DEFAULT_PAGADOR_AVATAR}`; + return `/avatars/${DEFAULT_PAGADOR_AVATAR}`; } // Se for uma URL completa (Google, etc), retorna diretamente @@ -43,7 +43,7 @@ export const getAvatarSrc = (avatar: string | null | undefined): string => { // Se for um caminho local, normaliza e adiciona o prefixo const normalized = normalizeAvatarPath(avatar); - return `/avatares/${normalized ?? DEFAULT_PAGADOR_AVATAR}`; + return `/avatars/${normalized ?? DEFAULT_PAGADOR_AVATAR}`; }; /** diff --git a/lib/preferences/fonts.ts b/src/shared/lib/preferences/fonts.ts similarity index 95% rename from lib/preferences/fonts.ts rename to src/shared/lib/preferences/fonts.ts index 0051376..cd35a28 100644 --- a/lib/preferences/fonts.ts +++ b/src/shared/lib/preferences/fonts.ts @@ -1,11 +1,11 @@ import { eq } from "drizzle-orm"; import { cache } from "react"; -import { db, schema } from "@/lib/db"; import { DEFAULT_FONT_KEY, type FontKey, normalizeFontKey, } from "@/public/fonts/font_index"; +import { db, schema } from "@/shared/lib/db"; export type FontPreferences = { systemFont: FontKey; diff --git a/lib/schemas/common.ts b/src/shared/lib/schemas/common.ts similarity index 100% rename from lib/schemas/common.ts rename to src/shared/lib/schemas/common.ts diff --git a/lib/schemas/inbox.ts b/src/shared/lib/schemas/inbox.ts similarity index 100% rename from lib/schemas/inbox.ts rename to src/shared/lib/schemas/inbox.ts diff --git a/lib/schemas/index.ts b/src/shared/lib/schemas/index.ts similarity index 100% rename from lib/schemas/index.ts rename to src/shared/lib/schemas/index.ts diff --git a/lib/schemas/insights.ts b/src/shared/lib/schemas/insights.ts similarity index 100% rename from lib/schemas/insights.ts rename to src/shared/lib/schemas/insights.ts diff --git a/src/shared/lib/schemas/recurring-series.ts b/src/shared/lib/schemas/recurring-series.ts new file mode 100644 index 0000000..bc480bd --- /dev/null +++ b/src/shared/lib/schemas/recurring-series.ts @@ -0,0 +1,13 @@ +import { z } from "zod"; +import { uuidSchema } from "./common"; + +/** + * Schema for pause/resume/cancel recurring series actions + */ +export const recurringSeriesActionSchema = z.object({ + seriesId: uuidSchema("Série recorrente"), +}); + +export type RecurringSeriesActionInput = z.infer< + typeof recurringSeriesActionSchema +>; diff --git a/lib/transferencias/constants.ts b/src/shared/lib/transfers/constants.ts similarity index 100% rename from lib/transferencias/constants.ts rename to src/shared/lib/transfers/constants.ts diff --git a/lib/types/actions.ts b/src/shared/lib/types/actions.ts similarity index 100% rename from lib/types/actions.ts rename to src/shared/lib/types/actions.ts diff --git a/lib/types/calendario.ts b/src/shared/lib/types/calendar.ts similarity index 95% rename from lib/types/calendario.ts rename to src/shared/lib/types/calendar.ts index cc65454..f761502 100644 --- a/lib/types/calendario.ts +++ b/src/shared/lib/types/calendar.ts @@ -1,7 +1,7 @@ import type { LancamentoItem, SelectOption, -} from "@/components/lancamentos/types"; +} from "@/features/transactions/components/types"; export type CalendarEvent = | { diff --git a/src/shared/lib/types/index.ts b/src/shared/lib/types/index.ts new file mode 100644 index 0000000..adaf110 --- /dev/null +++ b/src/shared/lib/types/index.ts @@ -0,0 +1,3 @@ +export * from "./actions"; +export * from "./calendar"; +export * from "./reports"; diff --git a/lib/types/relatorios.ts b/src/shared/lib/types/reports.ts similarity index 100% rename from lib/types/relatorios.ts rename to src/shared/lib/types/reports.ts diff --git a/lib/utils/calculator.ts b/src/shared/utils/calculator.ts similarity index 100% rename from lib/utils/calculator.ts rename to src/shared/utils/calculator.ts diff --git a/lib/utils/calendario.ts b/src/shared/utils/calendar.ts similarity index 91% rename from lib/utils/calendario.ts rename to src/shared/utils/calendar.ts index 0302f29..ca338c8 100644 --- a/lib/utils/calendario.ts +++ b/src/shared/utils/calendar.ts @@ -1,5 +1,5 @@ -import type { CalendarDay, CalendarEvent } from "@/lib/types/calendario"; -import { toDateOnlyString } from "@/lib/utils/date"; +import type { CalendarDay, CalendarEvent } from "@/shared/lib/types/calendar"; +import { toDateOnlyString } from "@/shared/utils/date"; export const formatDateKey = (date: Date) => toDateOnlyString(date) ?? ""; diff --git a/lib/utils/category-colors.ts b/src/shared/utils/category-colors.ts similarity index 100% rename from lib/utils/category-colors.ts rename to src/shared/utils/category-colors.ts diff --git a/lib/utils/currency.ts b/src/shared/utils/currency.ts similarity index 100% rename from lib/utils/currency.ts rename to src/shared/utils/currency.ts diff --git a/lib/utils/date.ts b/src/shared/utils/date.ts similarity index 98% rename from lib/utils/date.ts rename to src/shared/utils/date.ts index 09fb9a7..742eb6f 100644 --- a/lib/utils/date.ts +++ b/src/shared/utils/date.ts @@ -8,6 +8,8 @@ * Note: Period-related functions (YYYY-MM) are in /lib/utils/period */ +import { capitalize } from "@/shared/utils/string"; + // ============================================================================ // CONSTANTS // ============================================================================ @@ -45,12 +47,6 @@ type DateOnlyParts = { day: number; }; -function capitalize(value: string): string { - return value.length > 0 - ? value[0]?.toUpperCase().concat(value.slice(1)) - : value; -} - function buildDateOnlyString({ year, month, day }: DateOnlyParts): string { return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`; } diff --git a/lib/utils/export-branding.ts b/src/shared/utils/export-branding.ts similarity index 98% rename from lib/utils/export-branding.ts rename to src/shared/utils/export-branding.ts index eb47703..df2938c 100644 --- a/lib/utils/export-branding.ts +++ b/src/shared/utils/export-branding.ts @@ -66,7 +66,7 @@ export function getPrimaryPdfColor(): [number, number, number] { } export async function loadExportLogoDataUrl( - logoPath = "/imagens/logo_text.png", + logoPath = "/images/logo_text.png", ): Promise { if (typeof window === "undefined" || typeof document === "undefined") { return null; diff --git a/lib/utils/financial-dates.ts b/src/shared/utils/financial-dates.ts similarity index 97% rename from lib/utils/financial-dates.ts rename to src/shared/utils/financial-dates.ts index f1ef60c..42e80dd 100644 --- a/lib/utils/financial-dates.ts +++ b/src/shared/utils/financial-dates.ts @@ -1,7 +1,7 @@ import { buildDateOnlyStringFromPeriodDay, formatDateOnlyLabel, -} from "@/lib/utils/date"; +} from "@/shared/utils/date"; type FinancialStatusLabelInput = { isSettled: boolean; diff --git a/lib/utils/icons.tsx b/src/shared/utils/icons.tsx similarity index 100% rename from lib/utils/icons.tsx rename to src/shared/utils/icons.tsx diff --git a/lib/utils.ts b/src/shared/utils/index.ts similarity index 64% rename from lib/utils.ts rename to src/shared/utils/index.ts index b282626..297fc45 100644 --- a/lib/utils.ts +++ b/src/shared/utils/index.ts @@ -1,2 +1,2 @@ // Re-export from lib/utils/ui.ts for shadcn compatibility -export { cn } from "./utils/ui"; +export { cn } from "./ui"; diff --git a/lib/utils/math.ts b/src/shared/utils/math.ts similarity index 100% rename from lib/utils/math.ts rename to src/shared/utils/math.ts diff --git a/lib/utils/number.ts b/src/shared/utils/number.ts similarity index 100% rename from lib/utils/number.ts rename to src/shared/utils/number.ts diff --git a/lib/utils/percentage.ts b/src/shared/utils/percentage.ts similarity index 100% rename from lib/utils/percentage.ts rename to src/shared/utils/percentage.ts diff --git a/lib/utils/period/index.ts b/src/shared/utils/period/index.ts similarity index 98% rename from lib/utils/period/index.ts rename to src/shared/utils/period/index.ts index d85e8d3..fb585e4 100644 --- a/lib/utils/period/index.ts +++ b/src/shared/utils/period/index.ts @@ -5,11 +5,13 @@ * - /lib/month-period.ts (URL param handling) * - /lib/period/index.ts (YYYY-MM operations) * - /hooks/use-dates.ts (month navigation) - * - /lib/lancamentos/period-helpers.ts (formatting) + * - /lib/transactions/period-helpers.ts (formatting) * * Moved from /lib/period to /lib/utils/period for better organization */ +import { capitalize } from "@/shared/utils/string"; + // ============================================================================ // CONSTANTS // ============================================================================ @@ -284,12 +286,6 @@ export function formatPeriodForUrl(period: string): string { // DISPLAY FORMATTING // ============================================================================ -function capitalize(value: string): string { - return value.length > 0 - ? value[0]?.toUpperCase().concat(value.slice(1)) - : value; -} - /** * Converts period string (YYYY-MM) to Date object for the first day of month */ diff --git a/lib/utils/string.ts b/src/shared/utils/string.ts similarity index 83% rename from lib/utils/string.ts rename to src/shared/utils/string.ts index 48c9840..30fa588 100644 --- a/lib/utils/string.ts +++ b/src/shared/utils/string.ts @@ -2,6 +2,15 @@ * Utility functions for string normalization and manipulation */ +/** + * Capitalizes the first letter of a string + */ +export function capitalize(value: string): string { + return value.length > 0 + ? value[0]?.toUpperCase().concat(value.slice(1)) + : value; +} + /** * Normalizes optional string - trims and returns null if empty * @param value - String to normalize diff --git a/lib/utils/ui.ts b/src/shared/utils/ui.ts similarity index 100% rename from lib/utils/ui.ts rename to src/shared/utils/ui.ts diff --git a/tsconfig.json b/tsconfig.json index fd75fd2..22f87de 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "baseUrl": ".", "target": "ES2017", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, @@ -19,13 +20,17 @@ } ], "paths": { - "@/*": ["./*"] + "@/*": ["./src/*", "./*"] } }, "include": [ "next-env.d.ts", - "**/*.ts", - "**/*.tsx", + "src/**/*.ts", + "src/**/*.tsx", + "public/fonts/**/*.ts", + "scripts/**/*.ts", + "*.ts", + "*.mjs", ".next/types/**/*.ts", ".next/dev/types/**/*.ts" ],