refactor(core): move app para src e padroniza estrutura

This commit is contained in:
Felipe Coutinho
2026-03-12 19:22:50 +00:00
parent d92e70f1b9
commit b0fbb1062a
567 changed files with 8981 additions and 5014 deletions

1
.nvmrc
View File

@@ -1 +0,0 @@
v22.12.0

View File

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

View File

@@ -1,5 +1,5 @@
<p align="center">
<img src="./public/imagens/logo_small.png" alt="OpenMonetis Logo" height="80" />
<img src="./public/images/logo_small.png" alt="OpenMonetis Logo" height="80" />
</p>
<p align="center">
@@ -21,7 +21,7 @@
---
<p align="center">
<img src="./public/imagens/dashboard-preview-light.webp" alt="Dashboard Preview" width="800" />
<img src="./public/images/dashboard-preview-light.webp" alt="Dashboard Preview" width="800" />
</p>
---

View File

@@ -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 (
<main>
<CategoryHistoryWidget data={data} />
</main>
);
}

View File

@@ -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,
}));
}

View File

@@ -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 (
<main className="flex flex-col gap-4 pb-8">
<InstallmentAnalysisPage data={data} />
</main>
);
}

View File

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

View File

@@ -1 +0,0 @@
export { LogoPickerTrigger, LogoPickerDialog } from "./logo-picker";

View File

@@ -1 +0,0 @@
export { useIsMobile, useMobile } from "@/lib/hooks/use-mobile";

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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
}
]
}
"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
}
]
}

View File

@@ -1,3 +0,0 @@
export * from "./actions";
export * from "./calendario";
export * from "./relatorios";

View File

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

View File

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

1133
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

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

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 163 KiB

View File

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 178 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 152 KiB

View File

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 160 KiB

View File

Before

Width:  |  Height:  |  Size: 162 KiB

After

Width:  |  Height:  |  Size: 162 KiB

View File

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 169 KiB

View File

Before

Width:  |  Height:  |  Size: 262 KiB

After

Width:  |  Height:  |  Size: 262 KiB

View File

Before

Width:  |  Height:  |  Size: 272 KiB

After

Width:  |  Height:  |  Size: 272 KiB

View File

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -1,4 +1,4 @@
import { LoginForm } from "@/components/auth/login-form";
import { LoginForm } from "@/features/auth/components/login-form";
export default function LoginPage() {
return (

View File

@@ -1,4 +1,4 @@
import { SignupForm } from "@/components/auth/signup-form";
import { SignupForm } from "@/features/auth/components/signup-form";
export default function Page() {
return (

View File

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

View File

@@ -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<ResolvedSearchParams>;
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);

View File

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

View File

@@ -1,4 +1,4 @@
import { Skeleton } from "@/components/ui/skeleton";
import { Skeleton } from "@/shared/components/ui/skeleton";
export default function ContasLoading() {
return (

View File

@@ -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();

View File

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

View File

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

View File

@@ -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<Record<string, string | string[] | undefined>>;

View File

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

View File

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

View File

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

View File

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

View File

@@ -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<ResolvedSearchParams>;
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 =

View File

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

View File

@@ -1,4 +1,4 @@
import { Skeleton } from "@/components/ui/skeleton";
import { Skeleton } from "@/shared/components/ui/skeleton";
export default function CartoesLoading() {
return (

View File

@@ -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();

View File

@@ -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<Record<string, string | string[] | undefined>>;
@@ -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),
]);

View File

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

View File

@@ -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 (
<main>
<CategoryHistoryWidget data={data} />
</main>
);
}

View File

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

View File

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

View File

@@ -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();

View File

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

View File

@@ -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<Record<string, string | string[] | undefined>>;
@@ -19,17 +23,9 @@ type PageProps = {
searchParams?: PageSearchParams;
};
const getSingleParam = (
params: Record<string, string | string[] | undefined> | 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);

View File

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

View File

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

View File

@@ -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();

View File

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

View File

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

View File

@@ -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<Record<string, string | string[] | undefined>>;

View File

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

View File

@@ -1,5 +1,5 @@
import { RiTodoLine } from "@remixicon/react";
import PageDescription from "@/components/shared/page-description";
import PageDescription from "@/shared/components/page-description";
export const metadata = {
title: "Anotações | OpenMonetis",

View File

@@ -1,4 +1,4 @@
import { Skeleton } from "@/components/ui/skeleton";
import { Skeleton } from "@/shared/components/ui/skeleton";
/**
* Loading state para a página de anotações

View File

@@ -1,6 +1,6 @@
import { NotesPage } from "@/components/anotacoes/notes-page";
import { getUserId } from "@/lib/auth/server";
import { fetchAllNotesForUser } from "./data";
import { NotesPage } from "@/features/notes/components/notes-page";
import { fetchAllNotesForUser } from "@/features/notes/queries";
import { getUserId } from "@/shared/lib/auth/server";
export default async function Page() {
const userId = await getUserId();

View File

@@ -1,4 +1,4 @@
import { Skeleton } from "@/components/ui/skeleton";
import { Skeleton } from "@/shared/components/ui/skeleton";
/**
* Loading state para a página de detalhes do pagador.

View File

@@ -4,46 +4,52 @@ import {
RiWallet3Line,
} from "@remixicon/react";
import { notFound } from "next/navigation";
import { fetchUserPreferences } from "@/app/(dashboard)/ajustes/data";
import { getRecentEstablishmentsAction } from "@/app/(dashboard)/lancamentos/actions";
import { ExpandableWidgetCard } from "@/components/shared/expandable-widget-card";
import { LancamentosPage as LancamentosSection } from "@/components/lancamentos/page/lancamentos-page";
import type {
ContaCartaoFilterOption,
LancamentoFilterOption,
LancamentoItem,
SelectOption,
} from "@/components/lancamentos/types";
import MonthNavigation from "@/components/month-picker/month-navigation";
import { PagadorCardUsageCard } from "@/components/pagadores/details/pagador-card-usage-card";
import { PagadorHeaderCard } from "@/components/pagadores/details/pagador-header-card";
import { PagadorHistoryCard } from "@/components/pagadores/details/pagador-history-card";
import { PagadorInfoCard } from "@/components/pagadores/details/pagador-info-card";
import { PagadorLeaveShareCard } from "@/components/pagadores/details/pagador-leave-share-card";
import { PagadorMonthlySummaryCard } from "@/components/pagadores/details/pagador-monthly-summary-card";
import { PagadorCardUsageCard } from "@/features/payers/components/details/payer-card-usage-card";
import { PagadorHeaderCard } from "@/features/payers/components/details/payer-header-card";
import { PagadorHistoryCard } from "@/features/payers/components/details/payer-history-card";
import { PagadorInfoCard } from "@/features/payers/components/details/payer-info-card";
import { PagadorLeaveShareCard } from "@/features/payers/components/details/payer-leave-share-card";
import { PagadorMonthlySummaryCard } from "@/features/payers/components/details/payer-monthly-summary-card";
import {
PagadorBoletoCard,
PagadorPaymentStatusCard,
} from "@/components/pagadores/details/pagador-payment-method-cards";
import { PagadorSharingCard } from "@/components/pagadores/details/pagador-sharing-card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import type { pagadores } from "@/db/schema";
import { getUserId } from "@/lib/auth/server";
} from "@/features/payers/components/details/payer-payment-method-cards";
import { PagadorSharingCard } from "@/features/payers/components/details/payer-sharing-card";
import {
fetchCurrentUserShare,
fetchPagadorLancamentos,
fetchPagadorShares,
} from "@/features/payers/detail-queries";
import { buildReadOnlyOptionSets } from "@/features/payers/lib/build-readonly-option-sets";
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,
type LancamentoSearchFilters,
mapLancamentosData,
type ResolvedSearchParams,
type SluggedFilters,
type SlugMaps,
} from "@/lib/lancamentos/page-helpers";
import { getPagadorAccess } from "@/lib/pagadores/access";
} from "@/features/transactions/page-helpers";
import {
fetchLancamentoFilterSources,
fetchRecentEstablishments,
} from "@/features/transactions/queries";
import { ExpandableWidgetCard } from "@/shared/components/expandable-widget-card";
import MonthNavigation from "@/shared/components/month-picker/month-navigation";
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@/shared/components/ui/tabs";
import { getUserId } from "@/shared/lib/auth/server";
import { getPagadorAccess } from "@/shared/lib/payers/access";
import {
fetchPagadorBoletoItems,
fetchPagadorBoletoStats,
@@ -52,18 +58,13 @@ import {
fetchPagadorMonthlyBreakdown,
fetchPagadorPaymentStatus,
type PagadorCardUsageItem,
} from "@/lib/pagadores/details";
import { parsePeriodParam } from "@/lib/utils/period";
import {
fetchCurrentUserShare,
fetchPagadorLancamentos,
fetchPagadorShares,
} from "./data";
} from "@/shared/lib/payers/details";
import { parsePeriodParam } from "@/shared/utils/period";
type PageSearchParams = Promise<ResolvedSearchParams>;
type PageProps = {
params: Promise<{ pagadorId: string }>;
params: Promise<{ payerId: string }>;
searchParams?: PageSearchParams;
};
@@ -90,7 +91,7 @@ const createEmptySlugMaps = (): SlugMaps => ({
type OptionSet = ReturnType<typeof buildOptionSets>;
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) {
</main>
);
}
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<string, SelectOption>();
const cartaoOptionsMap = new Map<string, SelectOption>();
const categoriaOptionsMap = new Map<string, SelectOption>();
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,
};
}

View File

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

View File

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

View File

@@ -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();

View File

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

Some files were not shown because too many files have changed in this diff Show More