From 43b0f0c47e5410fc1aa563f98d2686b4ec3356ba Mon Sep 17 00:00:00 2001 From: Felipe Coutinho Date: Sat, 14 Mar 2026 12:51:08 +0000 Subject: [PATCH] refactor: traduz dominio de payers no app --- src/app/(dashboard)/layout.tsx | 10 +- src/app/(dashboard)/payers/[payerId]/page.tsx | 211 +++++++++--------- src/app/(dashboard)/payers/page.tsx | 8 +- src/features/payers/actions.ts | 145 ++++++------ .../details/payer-card-usage-card.tsx | 6 +- .../components/details/payer-header-card.tsx | 58 ++--- .../components/details/payer-history-card.tsx | 6 +- .../components/details/payer-info-card.tsx | 34 +-- .../details/payer-leave-share-card.tsx | 6 +- .../details/payer-monthly-summary-card.tsx | 6 +- .../details/payer-payment-method-cards.tsx | 16 +- .../components/details/payer-sharing-card.tsx | 16 +- .../payers/components/details/types.ts | 4 +- src/features/payers/components/payer-card.tsx | 32 +-- .../payers/components/payer-dialog.tsx | 92 ++++---- .../payers/components/payers-page.tsx | 85 ++++--- src/features/payers/components/types.ts | 10 +- src/features/payers/detail-actions.ts | 126 +++++------ src/features/payers/detail-queries.ts | 78 ++++--- src/features/payers/lib/avatar-options.ts | 6 +- .../payers/lib/build-readonly-option-sets.ts | 87 ++++---- src/features/payers/queries.ts | 38 ++-- .../navigation/sidebar/nav-link.tsx | 2 +- src/shared/lib/auth/config.ts | 2 +- src/shared/lib/payers/access.ts | 52 ++--- src/shared/lib/payers/constants.ts | 10 +- src/shared/lib/payers/defaults.ts | 22 +- src/shared/lib/payers/details.ts | 174 +++++++-------- src/shared/lib/payers/get-admin-id.ts | 19 +- src/shared/lib/payers/notifications.ts | 44 ++-- src/shared/lib/payers/utils.ts | 6 +- 31 files changed, 691 insertions(+), 720 deletions(-) diff --git a/src/app/(dashboard)/layout.tsx b/src/app/(dashboard)/layout.tsx index f90d4ae..af2e1fd 100644 --- a/src/app/(dashboard)/layout.tsx +++ b/src/app/(dashboard)/layout.tsx @@ -3,8 +3,8 @@ import { fetchPendingInboxCount } from "@/features/inbox/queries"; import { AppNavbar } from "@/shared/components/navigation/navbar/app-navbar"; 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 { fetchPayersWithAccess } from "@/shared/lib/payers/access"; +import { PAYER_ROLE_ADMIN } from "@/shared/lib/payers/constants"; import { parsePeriodParam } from "@/shared/utils/period"; export default async function DashboardLayout({ @@ -15,11 +15,11 @@ export default async function DashboardLayout({ searchParams?: Promise>; }>) { const session = await getUserSession(); - const pagadoresList = await fetchPagadoresWithAccess(session.user.id); + const payerList = await fetchPayersWithAccess(session.user.id); // Encontrar o pagador admin do usuário - const adminPagador = pagadoresList.find( - (p) => p.role === PAGADOR_ROLE_ADMIN && p.userId === session.user.id, + const adminPagador = payerList.find( + (p) => p.role === PAYER_ROLE_ADMIN && p.userId === session.user.id, ); // Buscar notificações para o período atual diff --git a/src/app/(dashboard)/payers/[payerId]/page.tsx b/src/app/(dashboard)/payers/[payerId]/page.tsx index c6e42cd..3554da0 100644 --- a/src/app/(dashboard)/payers/[payerId]/page.tsx +++ b/src/app/(dashboard)/payers/[payerId]/page.tsx @@ -4,41 +4,41 @@ import { RiWallet3Line, } from "@remixicon/react"; import { notFound } from "next/navigation"; -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 { PayerCardUsageCard } from "@/features/payers/components/details/payer-card-usage-card"; +import { PayerHeaderCard } from "@/features/payers/components/details/payer-header-card"; +import { PayerHistoryCard } 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 { PayerLeaveShareCard } from "@/features/payers/components/details/payer-leave-share-card"; +import { PayerMonthlySummaryCard } from "@/features/payers/components/details/payer-monthly-summary-card"; import { - PagadorBoletoCard, - PagadorPaymentStatusCard, + PayerBoletoCard, + PayerPaymentStatusCard, } from "@/features/payers/components/details/payer-payment-method-cards"; -import { PagadorSharingCard } from "@/features/payers/components/details/payer-sharing-card"; +import { PayerSharingCard } from "@/features/payers/components/details/payer-sharing-card"; import { fetchCurrentUserShare, fetchPagadorLancamentos, - fetchPagadorShares, + fetchPayerShares, } 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 { TransactionsPage as LancamentosSection } from "@/features/transactions/components/page/transactions-page"; import { - buildLancamentoWhere, buildOptionSets, buildSluggedFilters, buildSlugMaps, - extractLancamentoSearchFilters, + buildTransactionWhere, + extractTransactionSearchFilters, getSingleParam, - type LancamentoSearchFilters, - mapLancamentosData, + mapTransactionsData, type ResolvedSearchParams, type SluggedFilters, type SlugMaps, + type TransactionSearchFilters, } from "@/features/transactions/page-helpers"; import { - fetchLancamentoFilterSources, fetchRecentEstablishments, + fetchTransactionFilterSources, } from "@/features/transactions/queries"; import { ExpandableWidgetCard } from "@/shared/components/expandable-widget-card"; import MonthNavigation from "@/shared/components/month-picker/month-navigation"; @@ -49,15 +49,15 @@ import { TabsTrigger, } from "@/shared/components/ui/tabs"; import { getUserId } from "@/shared/lib/auth/server"; -import { getPagadorAccess } from "@/shared/lib/payers/access"; +import { getPayerAccess } from "@/shared/lib/payers/access"; import { fetchPagadorBoletoItems, fetchPagadorBoletoStats, fetchPagadorCardUsage, - fetchPagadorHistory, - fetchPagadorMonthlyBreakdown, fetchPagadorPaymentStatus, - type PagadorCardUsageItem, + fetchPayerHistory, + fetchPayerMonthlyBreakdown, + type PayerCardUsageItem, } from "@/shared/lib/payers/details"; import { parsePeriodParam } from "@/shared/utils/period"; @@ -71,31 +71,31 @@ type PageProps = { const capitalize = (value: string) => value.length ? value.charAt(0).toUpperCase().concat(value.slice(1)) : value; -const EMPTY_FILTERS: LancamentoSearchFilters = { +const EMPTY_FILTERS: TransactionSearchFilters = { transactionFilter: null, conditionFilter: null, paymentFilter: null, - pagadorFilter: null, - categoriaFilter: null, - contaCartaoFilter: null, + payerFilter: null, + categoryFilter: null, + accountCardFilter: null, searchFilter: null, }; const createEmptySlugMaps = (): SlugMaps => ({ - pagador: new Map(), - categoria: new Map(), - conta: new Map(), - cartao: new Map(), + payer: new Map(), + category: new Map(), + financialAccount: new Map(), + card: new Map(), }); type OptionSet = ReturnType; export default async function Page({ params, searchParams }: PageProps) { - const { payerId: pagadorId } = await params; + const { payerId } = await params; const userId = await getUserId(); const resolvedSearchParams = searchParams ? await searchParams : undefined; - const access = await getPagadorAccess(userId, pagadorId); + const access = await getPayerAccess(userId, payerId); if (!access) { notFound(); @@ -112,7 +112,8 @@ export default async function Page({ params, searchParams }: PageProps) { } = parsePeriodParam(periodoParamRaw); const periodLabel = `${capitalize(monthName)} de ${year}`; - const allSearchFilters = extractLancamentoSearchFilters(resolvedSearchParams); + const allSearchFilters = + extractTransactionSearchFilters(resolvedSearchParams); const searchFilters = canEdit ? allSearchFilters : { @@ -121,40 +122,40 @@ export default async function Page({ params, searchParams }: PageProps) { }; let filterSources: Awaited< - ReturnType + ReturnType > | null = null; let loggedUserFilterSources: Awaited< - ReturnType + ReturnType > | null = null; let sluggedFilters: SluggedFilters; let slugMaps: SlugMaps; if (canEdit) { - filterSources = await fetchLancamentoFilterSources(dataOwnerId); + filterSources = await fetchTransactionFilterSources(dataOwnerId); sluggedFilters = buildSluggedFilters(filterSources); slugMaps = buildSlugMaps(sluggedFilters); } else { // Buscar opções do usuário logado para usar ao importar - loggedUserFilterSources = await fetchLancamentoFilterSources(userId); + loggedUserFilterSources = await fetchTransactionFilterSources(userId); sluggedFilters = { - pagadorFiltersRaw: [], - categoriaFiltersRaw: [], - contaFiltersRaw: [], - cartaoFiltersRaw: [], + payerFiltersRaw: [], + categoryFiltersRaw: [], + accountFiltersRaw: [], + cardFiltersRaw: [], }; slugMaps = createEmptySlugMaps(); } - const filters = buildLancamentoWhere({ + const filters = buildTransactionWhere({ userId: dataOwnerId, period: selectedPeriod, filters: searchFilters, slugMaps, - pagadorId: pagador.id, + payerId: pagador.id, }); const sharesPromise = canEdit - ? fetchPagadorShares(pagador.id) + ? fetchPayerShares(pagador.id) : Promise.resolve([]); const currentUserSharePromise = !canEdit @@ -162,7 +163,7 @@ export default async function Page({ params, searchParams }: PageProps) { : Promise.resolve(null); const [ - lancamentoRows, + transactionRows, monthlyBreakdown, historyData, cardUsage, @@ -175,34 +176,34 @@ export default async function Page({ params, searchParams }: PageProps) { userPreferences, ] = await Promise.all([ fetchPagadorLancamentos(filters), - fetchPagadorMonthlyBreakdown({ + fetchPayerMonthlyBreakdown({ userId: dataOwnerId, - pagadorId: pagador.id, + payerId: pagador.id, period: selectedPeriod, }), - fetchPagadorHistory({ + fetchPayerHistory({ userId: dataOwnerId, - pagadorId: pagador.id, + payerId: pagador.id, period: selectedPeriod, }), fetchPagadorCardUsage({ userId: dataOwnerId, - pagadorId: pagador.id, + payerId: pagador.id, period: selectedPeriod, }), fetchPagadorBoletoStats({ userId: dataOwnerId, - pagadorId: pagador.id, + payerId: pagador.id, period: selectedPeriod, }), fetchPagadorBoletoItems({ userId: dataOwnerId, - pagadorId: pagador.id, + payerId: pagador.id, period: selectedPeriod, }), fetchPagadorPaymentStatus({ userId: dataOwnerId, - pagadorId: pagador.id, + payerId: pagador.id, period: selectedPeriod, }), sharesPromise, @@ -211,12 +212,12 @@ export default async function Page({ params, searchParams }: PageProps) { fetchUserPreferences(userId), ]); - const mappedLancamentos = mapLancamentosData(lancamentoRows); - const lancamentosData = canEdit - ? mappedLancamentos - : mappedLancamentos.map((item) => ({ ...item, readonly: true })); + const mappedTransactions = mapTransactionsData(transactionRows); + const transactionData = canEdit + ? mappedTransactions + : mappedTransactions.map((item) => ({ ...item, readonly: true })); - const pagadorSharesData = shareRows; + const payerSharesData = shareRows; let optionSets: OptionSet; let loggedUserOptionSets: OptionSet | null = null; @@ -225,11 +226,11 @@ export default async function Page({ params, searchParams }: PageProps) { if (canEdit && filterSources) { optionSets = buildOptionSets({ ...sluggedFilters, - pagadorRows: filterSources.pagadorRows, + payerRows: filterSources.payerRows, }); } else { effectiveSluggedFilters = { - pagadorFiltersRaw: [ + payerFiltersRaw: [ { id: pagador.id, label: pagador.name, @@ -238,11 +239,11 @@ export default async function Page({ params, searchParams }: PageProps) { avatarUrl: pagador.avatarUrl, }, ], - categoriaFiltersRaw: [], - contaFiltersRaw: [], - cartaoFiltersRaw: [], + categoryFiltersRaw: [], + accountFiltersRaw: [], + cardFiltersRaw: [], }; - optionSets = buildReadOnlyOptionSets(lancamentosData, pagador); + optionSets = buildReadOnlyOptionSets(transactionData, pagador); // Construir opções do usuário logado para usar ao importar if (loggedUserFilterSources) { @@ -251,23 +252,23 @@ export default async function Page({ params, searchParams }: PageProps) { ); loggedUserOptionSets = buildOptionSets({ ...loggedUserSluggedFilters, - pagadorRows: loggedUserFilterSources.pagadorRows, + payerRows: loggedUserFilterSources.payerRows, }); } } - const pagadorSlug = - effectiveSluggedFilters.pagadorFiltersRaw.find( + const payerSlug = + effectiveSluggedFilters.payerFiltersRaw.find( (item) => item.id === pagador.id, )?.slug ?? null; - const pagadorFilterOptions = pagadorSlug - ? optionSets.pagadorFilterOptions.filter( - (option) => option.slug === pagadorSlug, + const payerFilterOptions = payerSlug + ? optionSets.payerFilterOptions.filter( + (option) => option.slug === payerSlug, ) - : optionSets.pagadorFilterOptions; + : optionSets.payerFilterOptions; - const pagadorData = { + const payerData = { id: pagador.id, name: pagador.name, email: pagador.email ?? null, @@ -288,7 +289,7 @@ export default async function Page({ params, searchParams }: PageProps) { periodLabel, totalExpenses: monthlyBreakdown.totalExpenses, paymentSplits: monthlyBreakdown.paymentSplits, - cardUsage: cardUsage.slice(0, 3).map((item: PagadorCardUsageItem) => ({ + cardUsage: cardUsage.slice(0, 3).map((item: PayerCardUsageItem) => ({ name: item.name, amount: item.amount, })), @@ -299,7 +300,7 @@ export default async function Page({ params, searchParams }: PageProps) { paidCount: boletoStats.paidCount, pendingCount: boletoStats.pendingCount, }, - lancamentoCount: lancamentosData.length, + lancamentoCount: transactionData.length, }; return ( @@ -312,25 +313,25 @@ export default async function Page({ params, searchParams }: PageProps) { Painel Lançamentos - - - {canEdit && pagadorData.shareCode ? ( - + {canEdit && payerData.shareCode ? ( + ) : null} {!canEdit && currentUserShare ? ( - ) : null} @@ -338,11 +339,11 @@ export default async function Page({ params, searchParams }: PageProps) {
- - +
@@ -351,21 +352,21 @@ export default async function Page({ params, searchParams }: PageProps) { subtitle="Valores por cartão neste período" icon={} > - + } > - + } > - +
@@ -374,29 +375,27 @@ export default async function Page({ params, searchParams }: PageProps) {
diff --git a/src/app/(dashboard)/payers/page.tsx b/src/app/(dashboard)/payers/page.tsx index ab7c4dd..d759fce 100644 --- a/src/app/(dashboard)/payers/page.tsx +++ b/src/app/(dashboard)/payers/page.tsx @@ -1,14 +1,14 @@ -import { PagadoresPage } from "@/features/payers/components/payers-page"; -import { fetchPagadoresForUser } from "@/features/payers/queries"; +import { PayersPage } from "@/features/payers/components/payers-page"; +import { fetchPayersForUser } from "@/features/payers/queries"; import { getUserId } from "@/shared/lib/auth/server"; export default async function Page() { const userId = await getUserId(); - const { pagadores, avatarOptions } = await fetchPagadoresForUser(userId); + const { payers, avatarOptions } = await fetchPayersForUser(userId); return (
- +
); } diff --git a/src/features/payers/actions.ts b/src/features/payers/actions.ts index e59df27..c72875d 100644 --- a/src/features/payers/actions.ts +++ b/src/features/payers/actions.ts @@ -4,7 +4,7 @@ import { randomBytes } from "node:crypto"; import { and, eq } from "drizzle-orm"; import { revalidatePath } from "next/cache"; import { z } from "zod"; -import { compartilhamentosPagador, pagadores, user } from "@/db/schema"; +import { payerShares, payers, user } from "@/db/schema"; import { handleActionError, revalidateForEntity, @@ -12,21 +12,25 @@ import { 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, + DEFAULT_PAYER_AVATAR, + PAYER_ROLE_ADMIN, + PAYER_ROLE_THIRD_PARTY, + PAYER_STATUS_OPTIONS, } 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: () => ({ - message: "Selecione um status válido.", - }), -}); +const statusEnum = z + .enum([...PAYER_STATUS_OPTIONS] as [string, ...string[]]) + .refine( + (v) => + PAYER_STATUS_OPTIONS.includes(v as (typeof PAYER_STATUS_OPTIONS)[number]), + { + message: "Selecione um status válido.", + }, + ); const baseSchema = z.object({ name: z @@ -48,11 +52,11 @@ const baseSchema = z.object({ const createSchema = baseSchema; const updateSchema = baseSchema.extend({ - id: uuidSchema("Pagador"), + id: uuidSchema("Payer"), }); const deleteSchema = z.object({ - id: uuidSchema("Pagador"), + id: uuidSchema("Payer"), }); const shareDeleteSchema = z.object({ @@ -67,7 +71,7 @@ const shareCodeJoinSchema = z.object({ }); const shareCodeRegenerateSchema = z.object({ - pagadorId: uuidSchema("Pagador"), + payerId: uuidSchema("Payer"), }); type CreateInput = z.infer; @@ -77,7 +81,7 @@ type ShareDeleteInput = z.infer; type ShareCodeJoinInput = z.infer; type ShareCodeRegenerateInput = z.infer; -const revalidate = () => revalidateForEntity("pagadores"); +const revalidate = () => revalidateForEntity("payers"); const generateShareCode = () => { // base64url já retorna apenas [a-zA-Z0-9_-] @@ -85,56 +89,53 @@ const generateShareCode = () => { return randomBytes(18).toString("base64url").slice(0, 24); }; -export async function createPagadorAction( +export async function createPayerAction( input: CreateInput, ): Promise { try { const user = await getUser(); const data = createSchema.parse(input); - await db.insert(pagadores).values({ + await db.insert(payers).values({ name: data.name, email: data.email, status: data.status, note: data.note, - avatarUrl: normalizeAvatarPath(data.avatarUrl) ?? DEFAULT_PAGADOR_AVATAR, + avatarUrl: normalizeAvatarPath(data.avatarUrl) ?? DEFAULT_PAYER_AVATAR, isAutoSend: data.isAutoSend ?? false, - role: PAGADOR_ROLE_TERCEIRO, + role: PAYER_ROLE_THIRD_PARTY, shareCode: generateShareCode(), userId: user.id, }); revalidate(); - return { success: true, message: "Pagador criado com sucesso." }; + return { success: true, message: "Payer criado com sucesso." }; } catch (error) { return handleActionError(error); } } -export async function updatePagadorAction( +export async function updatePayerAction( input: UpdateInput, ): Promise { try { const currentUser = await getUser(); const data = updateSchema.parse(input); - const existing = await db.query.pagadores.findFirst({ - where: and( - eq(pagadores.id, data.id), - eq(pagadores.userId, currentUser.id), - ), + const existing = await db.query.payers.findFirst({ + where: and(eq(payers.id, data.id), eq(payers.userId, currentUser.id)), }); if (!existing) { return { success: false, - error: "Pagador não encontrado.", + error: "Payer não encontrado.", }; } await db - .update(pagadores) + .update(payers) .set({ name: data.name, email: data.email, @@ -143,14 +144,12 @@ export async function updatePagadorAction( avatarUrl: normalizeAvatarPath(data.avatarUrl) ?? existing.avatarUrl ?? null, isAutoSend: data.isAutoSend ?? false, - role: existing.role ?? PAGADOR_ROLE_TERCEIRO, + role: existing.role ?? PAYER_ROLE_THIRD_PARTY, }) - .where( - and(eq(pagadores.id, data.id), eq(pagadores.userId, currentUser.id)), - ); + .where(and(eq(payers.id, data.id), eq(payers.userId, currentUser.id))); // Se o pagador é admin, sincronizar nome com o usuário - if (existing.role === PAGADOR_ROLE_ADMIN) { + if (existing.role === PAYER_ROLE_ADMIN) { await db .update(user) .set({ name: data.name }) @@ -161,31 +160,31 @@ export async function updatePagadorAction( revalidate(); - return { success: true, message: "Pagador atualizado com sucesso." }; + return { success: true, message: "Payer atualizado com sucesso." }; } catch (error) { return handleActionError(error); } } -export async function deletePagadorAction( +export async function deletePayerAction( input: DeleteInput, ): Promise { try { const user = await getUser(); const data = deleteSchema.parse(input); - const existing = await db.query.pagadores.findFirst({ - where: and(eq(pagadores.id, data.id), eq(pagadores.userId, user.id)), + const existing = await db.query.payers.findFirst({ + where: and(eq(payers.id, data.id), eq(payers.userId, user.id)), }); if (!existing) { return { success: false, - error: "Pagador não encontrado.", + error: "Payer não encontrado.", }; } - if (existing.role === PAGADOR_ROLE_ADMIN) { + if (existing.role === PAYER_ROLE_ADMIN) { return { success: false, error: "Pagadores administradores não podem ser removidos.", @@ -193,26 +192,26 @@ export async function deletePagadorAction( } await db - .delete(pagadores) - .where(and(eq(pagadores.id, data.id), eq(pagadores.userId, user.id))); + .delete(payers) + .where(and(eq(payers.id, data.id), eq(payers.userId, user.id))); revalidate(); - return { success: true, message: "Pagador removido com sucesso." }; + return { success: true, message: "Payer removido com sucesso." }; } catch (error) { return handleActionError(error); } } -export async function joinPagadorByShareCodeAction( +export async function joinPayerByShareCodeAction( input: ShareCodeJoinInput, ): Promise { try { const user = await getUser(); const data = shareCodeJoinSchema.parse(input); - const pagadorRow = await db.query.pagadores.findFirst({ - where: eq(pagadores.shareCode, data.code), + const pagadorRow = await db.query.payers.findFirst({ + where: eq(payers.shareCode, data.code), }); if (!pagadorRow) { @@ -226,10 +225,10 @@ export async function joinPagadorByShareCodeAction( }; } - const existingShare = await db.query.compartilhamentosPagador.findFirst({ + const existingShare = await db.query.payerShares.findFirst({ where: and( - eq(compartilhamentosPagador.pagadorId, pagadorRow.id), - eq(compartilhamentosPagador.sharedWithUserId, user.id), + eq(payerShares.payerId, pagadorRow.id), + eq(payerShares.sharedWithUserId, user.id), ), }); @@ -240,8 +239,8 @@ export async function joinPagadorByShareCodeAction( }; } - await db.insert(compartilhamentosPagador).values({ - pagadorId: pagadorRow.id, + await db.insert(payerShares).values({ + payerId: pagadorRow.id, sharedWithUserId: user.id, permission: "read", createdByUserId: pagadorRow.userId, @@ -249,28 +248,28 @@ export async function joinPagadorByShareCodeAction( revalidate(); - return { success: true, message: "Pagador adicionado à sua lista." }; + return { success: true, message: "Payer adicionado à sua lista." }; } catch (error) { return handleActionError(error); } } -export async function deletePagadorShareAction( +export async function deletePayerShareAction( input: ShareDeleteInput, ): Promise { try { const user = await getUser(); const data = shareDeleteSchema.parse(input); - const existing = await db.query.compartilhamentosPagador.findFirst({ + const existing = await db.query.payerShares.findFirst({ columns: { id: true, - pagadorId: true, + payerId: true, sharedWithUserId: true, }, - where: eq(compartilhamentosPagador.id, data.shareId), + where: eq(payerShares.id, data.shareId), with: { - pagador: { + payer: { columns: { userId: true, }, @@ -279,10 +278,10 @@ export async function deletePagadorShareAction( }); // Permitir que o owner OU o próprio usuário compartilhado remova o share + const payerOwner = existing?.payer as { userId: string } | null | undefined; if ( !existing || - (existing.pagador.userId !== user.id && - existing.sharedWithUserId !== user.id) + (payerOwner?.userId !== user.id && existing.sharedWithUserId !== user.id) ) { return { success: false, @@ -290,12 +289,10 @@ export async function deletePagadorShareAction( }; } - await db - .delete(compartilhamentosPagador) - .where(eq(compartilhamentosPagador.id, data.shareId)); + await db.delete(payerShares).where(eq(payerShares.id, data.shareId)); revalidate(); - revalidatePath(`/payers/${existing.pagadorId}`); + revalidatePath(`/payers/${existing.payerId}`); return { success: true, message: "Compartilhamento removido." }; } catch (error) { @@ -303,23 +300,20 @@ export async function deletePagadorShareAction( } } -export async function regeneratePagadorShareCodeAction( +export async function regeneratePayerShareCodeAction( input: ShareCodeRegenerateInput, ): Promise<{ success: true; message: string; code: string } | ActionResult> { try { const user = await getUser(); const data = shareCodeRegenerateSchema.parse(input); - const existing = await db.query.pagadores.findFirst({ + const existing = await db.query.payers.findFirst({ columns: { id: true, userId: true }, - where: and( - eq(pagadores.id, data.pagadorId), - eq(pagadores.userId, user.id), - ), + where: and(eq(payers.id, data.payerId), eq(payers.userId, user.id)), }); if (!existing) { - return { success: false, error: "Pagador não encontrado." }; + return { success: false, error: "Payer não encontrado." }; } let attempts = 0; @@ -327,17 +321,12 @@ export async function regeneratePagadorShareCodeAction( const newCode = generateShareCode(); try { await db - .update(pagadores) + .update(payers) .set({ shareCode: newCode }) - .where( - and( - eq(pagadores.id, data.pagadorId), - eq(pagadores.userId, user.id), - ), - ); + .where(and(eq(payers.id, data.payerId), eq(payers.userId, user.id))); revalidate(); - revalidatePath(`/payers/${data.pagadorId}`); + revalidatePath(`/payers/${data.payerId}`); return { success: true, message: "Código atualizado com sucesso.", @@ -347,8 +336,8 @@ export async function regeneratePagadorShareCodeAction( if ( error instanceof Error && "constraint" in error && - // @ts-expect-error constraint is present in postgres errors - error.constraint === "pagadores_share_code_key" + (error as { constraint?: string }).constraint === + "pagadores_share_code_key" ) { attempts += 1; continue; diff --git a/src/features/payers/components/details/payer-card-usage-card.tsx b/src/features/payers/components/details/payer-card-usage-card.tsx index 3bd878e..9068f5a 100644 --- a/src/features/payers/components/details/payer-card-usage-card.tsx +++ b/src/features/payers/components/details/payer-card-usage-card.tsx @@ -4,7 +4,7 @@ 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"; +import type { PayerCardUsageItem } from "@/shared/lib/payers/details"; const buildInitials = (value: string) => { const parts = value.trim().split(/\s+/).filter(Boolean); @@ -19,10 +19,10 @@ const buildInitials = (value: string) => { }; type PagadorCardUsageCardProps = { - items: PagadorCardUsageItem[]; + items: PayerCardUsageItem[]; }; -export function PagadorCardUsageCard({ items }: PagadorCardUsageCardProps) { +export function PayerCardUsageCard({ items }: PagadorCardUsageCardProps) { if (items.length === 0) { return ( diff --git a/src/features/payers/components/details/payer-header-card.tsx b/src/features/payers/components/details/payer-header-card.tsx index 64a046d..00a7575 100644 --- a/src/features/payers/components/details/payer-header-card.tsx +++ b/src/features/payers/components/details/payer-header-card.tsx @@ -13,7 +13,7 @@ import Link from "next/link"; import { useRouter } from "next/navigation"; import { useState, useTransition } from "react"; import { toast } from "sonner"; -import { sendPagadorSummaryAction } from "@/features/payers/detail-actions"; +import { sendPayerSummaryAction } from "@/features/payers/detail-actions"; import { Badge } from "@/shared/components/ui/badge"; import { Button } from "@/shared/components/ui/button"; import { @@ -30,41 +30,41 @@ import { DialogHeader, DialogTitle, } from "@/shared/components/ui/dialog"; -import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { PAYER_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"; +import type { PayerInfo, PayerSummaryPreview } from "./types"; -type PagadorHeaderCardProps = { - pagador: PagadorInfo; +type PayerHeaderCardProps = { + payer: PayerInfo; selectedPeriod: string; - summary: PagadorSummaryPreview; + summary: PayerSummaryPreview; }; -export function PagadorHeaderCard({ - pagador, +export function PayerHeaderCard({ + payer, selectedPeriod, summary, -}: PagadorHeaderCardProps) { +}: PayerHeaderCardProps) { const router = useRouter(); const [isSending, startTransition] = useTransition(); const [confirmOpen, setConfirmOpen] = useState(false); - const avatarSrc = getAvatarSrc(pagador.avatarUrl); - const createdAtLabel = formatDate(pagador.createdAt); - const isAdmin = pagador.role === PAGADOR_ROLE_ADMIN; + const avatarSrc = getAvatarSrc(payer.avatarUrl); + const createdAtLabel = formatDate(payer.createdAt); + const isAdmin = payer.role === PAYER_ROLE_ADMIN; const lastMailLabel = - formatDateTime(pagador.lastMailAt, { + formatDateTime(payer.lastMailAt, { dateStyle: "short", timeStyle: "short", }) ?? "Nunca enviado"; - const disableSend = isSending || !pagador.email || !pagador.canEdit; + const disableSend = isSending || !payer.email || !payer.canEdit; const openConfirmDialog = () => { - if (!pagador.email) { + if (!payer.email) { toast.error("Cadastre um e-mail para este pagador antes de enviar."); return; } @@ -72,14 +72,14 @@ export function PagadorHeaderCard({ }; const handleSendSummary = () => { - if (!pagador.email) { + if (!payer.email) { toast.error("Cadastre um e-mail para este pagador antes de enviar."); return; } startTransition(async () => { - const result = await sendPagadorSummaryAction({ - pagadorId: pagador.id, + const result = await sendPayerSummaryAction({ + payerId: payer.id, period: selectedPeriod, }); @@ -109,7 +109,7 @@ export function PagadorHeaderCard({
{`Avatar
- {pagador.name} + {payer.name} {isAdmin ? ( ) : null} - {pagador.status} + {payer.status} - {pagador.isAutoSend ? ( + {payer.isAutoSend ? ( Envio automático @@ -144,14 +144,14 @@ export function PagadorHeaderCard({ Criado em {createdAtLabel} - {pagador.email ? ( + {payer.email ? ( - {pagador.email} + {payer.email} ) : ( Sem e-mail cadastrado @@ -161,7 +161,7 @@ export function PagadorHeaderCard({
- {pagador.canEdit ? ( + {payer.canEdit ? ( <>