mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-07-09 19:36:02 +00:00
refactor: faxina arquitetural — código morto, identificadores em inglês e estrutura padronizada
Refatoração estrutural sem mudanças funcionais. Saldo líquido: −428 linhas. Removido: - 14 funções/constantes mortas verificadas via grep no repo todo: validateCategoriaOwnership, getInstallmentAnticipationsAction, getAnticipationDetailsAction, formatDecimalForDb, currencyFormatterNoCents, optionalDecimalSchema, formatMonthLabel, getGoalProgressStatusColorClass, MONTH_PERIOD_PARAM, calculateRemainingInstallments, e 5 funções fetch* não usadas em inbox/queries.ts. - 1 tipo morto (ImportRow) + 2 órfãos consequentes (InstallmentAnticipationWithRelations, GoalProgressStatus convertido em interno). - ~30 export keywords desnecessários (símbolos usados apenas no próprio arquivo). - Re-exports mortos em barrels: EstablishmentLogoPicker, CategoryReportSkeleton, WidgetSkeleton, toNameKey. - Arquivo features/reports/types.ts (barrel inteiro era órfão). Padronizado (PT-BR→EN em identificadores expostos): - 4 constantes globais (LANCAMENTOS_* → TRANSACTIONS_*). - 12 tipos/interfaces (Lancamento*/Pagador*/Estabelecimento* → equivalentes EN). - 13 funções/components exportados (fetchPagador*, EstabelecimentoInput, PagadorInfoCard, etc.). - 5 props cross-file (preLancamentosCount → inboxPendingCount, pagadorAvatarUrl → payerAvatarUrl, etc.). - Mantidas em PT-BR conforme exceção do CLAUDE.md: variáveis locais (pagador, categoria, lancamento), accessor key pagadorName (persistida em preferências), strings de UI. Reorganizado: - transactions/: 14 helpers soltos na raiz movidos para lib/; barrel actions.ts reduzido de 76 linhas de wrappers para 14 linhas de re-exports puros; anticipation-actions.ts movido para actions/anticipation.ts. - dashboard/: 8 helpers soltos consolidados em dashboard/lib/. - reports/: 5 query files na raiz consolidados em reports/lib/. - payers/: detail-actions.ts (21KB) e detail-queries.ts movidos para payers/lib/. - shared/components/: 9 dos 16 componentes soltos agrupados em brand/, widgets/, feedback/. - shared/lib/fetch-json.ts movido para shared/utils/fetch-json.ts. Validação: pnpm exec tsc --noEmit (0 erros), biome check (0 issues), knip (sem unused). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,76 +1,14 @@
|
||||
"use server";
|
||||
|
||||
import {
|
||||
createMassTransactionsAction as createMassTransactionsActionImpl,
|
||||
deleteMultipleTransactionsAction as deleteMultipleTransactionsActionImpl,
|
||||
deleteTransactionBulkAction as deleteTransactionBulkActionImpl,
|
||||
updateTransactionBulkAction as updateTransactionBulkActionImpl,
|
||||
export {
|
||||
createMassTransactionsAction,
|
||||
deleteMultipleTransactionsAction,
|
||||
deleteTransactionBulkAction,
|
||||
updateTransactionBulkAction,
|
||||
} from "./actions/bulk-actions";
|
||||
import { exportTransactionsDataAction as exportTransactionsDataActionImpl } from "./actions/export-actions";
|
||||
import {
|
||||
createTransactionAction as createTransactionActionImpl,
|
||||
deleteTransactionAction as deleteTransactionActionImpl,
|
||||
toggleTransactionSettlementAction as toggleTransactionSettlementActionImpl,
|
||||
updateTransactionAction as updateTransactionActionImpl,
|
||||
updateTransactionSplitPairAction as updateTransactionSplitPairActionImpl,
|
||||
export { exportTransactionsDataAction } from "./actions/export-actions";
|
||||
export {
|
||||
createTransactionAction,
|
||||
deleteTransactionAction,
|
||||
toggleTransactionSettlementAction,
|
||||
updateTransactionAction,
|
||||
updateTransactionSplitPairAction,
|
||||
} from "./actions/single-actions";
|
||||
|
||||
export async function createTransactionAction(
|
||||
...args: Parameters<typeof createTransactionActionImpl>
|
||||
): ReturnType<typeof createTransactionActionImpl> {
|
||||
return createTransactionActionImpl(...args);
|
||||
}
|
||||
|
||||
export async function updateTransactionAction(
|
||||
...args: Parameters<typeof updateTransactionActionImpl>
|
||||
): ReturnType<typeof updateTransactionActionImpl> {
|
||||
return updateTransactionActionImpl(...args);
|
||||
}
|
||||
|
||||
export async function deleteTransactionAction(
|
||||
...args: Parameters<typeof deleteTransactionActionImpl>
|
||||
): ReturnType<typeof deleteTransactionActionImpl> {
|
||||
return deleteTransactionActionImpl(...args);
|
||||
}
|
||||
|
||||
export async function toggleTransactionSettlementAction(
|
||||
...args: Parameters<typeof toggleTransactionSettlementActionImpl>
|
||||
): ReturnType<typeof toggleTransactionSettlementActionImpl> {
|
||||
return toggleTransactionSettlementActionImpl(...args);
|
||||
}
|
||||
|
||||
export async function deleteTransactionBulkAction(
|
||||
...args: Parameters<typeof deleteTransactionBulkActionImpl>
|
||||
): ReturnType<typeof deleteTransactionBulkActionImpl> {
|
||||
return deleteTransactionBulkActionImpl(...args);
|
||||
}
|
||||
|
||||
export async function updateTransactionBulkAction(
|
||||
...args: Parameters<typeof updateTransactionBulkActionImpl>
|
||||
): ReturnType<typeof updateTransactionBulkActionImpl> {
|
||||
return updateTransactionBulkActionImpl(...args);
|
||||
}
|
||||
|
||||
export async function createMassTransactionsAction(
|
||||
...args: Parameters<typeof createMassTransactionsActionImpl>
|
||||
): ReturnType<typeof createMassTransactionsActionImpl> {
|
||||
return createMassTransactionsActionImpl(...args);
|
||||
}
|
||||
|
||||
export async function deleteMultipleTransactionsAction(
|
||||
...args: Parameters<typeof deleteMultipleTransactionsActionImpl>
|
||||
): ReturnType<typeof deleteMultipleTransactionsActionImpl> {
|
||||
return deleteMultipleTransactionsActionImpl(...args);
|
||||
}
|
||||
|
||||
export async function updateTransactionSplitPairAction(
|
||||
...args: Parameters<typeof updateTransactionSplitPairActionImpl>
|
||||
): ReturnType<typeof updateTransactionSplitPairActionImpl> {
|
||||
return updateTransactionSplitPairActionImpl(...args);
|
||||
}
|
||||
|
||||
export async function exportTransactionsDataAction(
|
||||
...args: Parameters<typeof exportTransactionsDataActionImpl>
|
||||
): ReturnType<typeof exportTransactionsDataActionImpl> {
|
||||
return exportTransactionsDataActionImpl(...args);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use server";
|
||||
|
||||
import { and, asc, desc, eq, inArray, isNull, or } from "drizzle-orm";
|
||||
import { and, asc, eq, inArray, isNull, or } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
categories,
|
||||
@@ -22,7 +22,6 @@ import type {
|
||||
CancelAnticipationInput,
|
||||
CreateAnticipationInput,
|
||||
EligibleInstallment,
|
||||
InstallmentAnticipationWithRelations,
|
||||
} from "@/shared/lib/installments/anticipation-types";
|
||||
import { uuidSchema } from "@/shared/lib/schemas/common";
|
||||
import type { ActionResult } from "@/shared/lib/types/actions";
|
||||
@@ -326,71 +325,6 @@ export async function createInstallmentAnticipationAction(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Busca histórico de antecipações de uma série
|
||||
*/
|
||||
export async function getInstallmentAnticipationsAction(
|
||||
seriesId: string,
|
||||
): Promise<ActionResult<InstallmentAnticipationWithRelations[]>> {
|
||||
try {
|
||||
const user = await getUser();
|
||||
|
||||
// Validar seriesId
|
||||
const validatedSeriesId = uuidSchema("Série").parse(seriesId);
|
||||
|
||||
// Usar query builder ao invés de db.query para evitar problemas de tipagem
|
||||
const anticipations = await db
|
||||
.select({
|
||||
id: installmentAnticipations.id,
|
||||
seriesId: installmentAnticipations.seriesId,
|
||||
anticipationPeriod: installmentAnticipations.anticipationPeriod,
|
||||
anticipationDate: installmentAnticipations.anticipationDate,
|
||||
anticipatedInstallmentIds:
|
||||
installmentAnticipations.anticipatedInstallmentIds,
|
||||
totalAmount: installmentAnticipations.totalAmount,
|
||||
installmentCount: installmentAnticipations.installmentCount,
|
||||
discount: installmentAnticipations.discount,
|
||||
transactionId: installmentAnticipations.transactionId,
|
||||
payerId: installmentAnticipations.payerId,
|
||||
categoryId: installmentAnticipations.categoryId,
|
||||
note: installmentAnticipations.note,
|
||||
userId: installmentAnticipations.userId,
|
||||
createdAt: installmentAnticipations.createdAt,
|
||||
// Joins
|
||||
transaction: transactions,
|
||||
payer: payers,
|
||||
category: categories,
|
||||
})
|
||||
.from(installmentAnticipations)
|
||||
.leftJoin(
|
||||
transactions,
|
||||
eq(installmentAnticipations.transactionId, transactions.id),
|
||||
)
|
||||
.leftJoin(payers, eq(installmentAnticipations.payerId, payers.id))
|
||||
.leftJoin(
|
||||
categories,
|
||||
eq(installmentAnticipations.categoryId, categories.id),
|
||||
)
|
||||
.where(
|
||||
and(
|
||||
eq(installmentAnticipations.seriesId, validatedSeriesId),
|
||||
eq(installmentAnticipations.userId, user.id),
|
||||
),
|
||||
)
|
||||
.orderBy(desc(installmentAnticipations.createdAt));
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Antecipações carregadas.",
|
||||
data: anticipations,
|
||||
};
|
||||
} catch (error) {
|
||||
return handleActionError(error) as ActionResult<
|
||||
InstallmentAnticipationWithRelations[]
|
||||
>;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancela uma antecipação de parcelas
|
||||
* Remove o lançamento de antecipação e restaura as parcelas originais
|
||||
@@ -503,46 +437,3 @@ export async function cancelInstallmentAnticipationAction(
|
||||
return handleActionError(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Busca detalhes de uma antecipação específica
|
||||
*/
|
||||
export async function getAnticipationDetailsAction(
|
||||
anticipationId: string,
|
||||
): Promise<ActionResult<InstallmentAnticipationWithRelations>> {
|
||||
try {
|
||||
const user = await getUser();
|
||||
|
||||
// Validar anticipationId
|
||||
const validatedId = uuidSchema("Antecipação").parse(anticipationId);
|
||||
|
||||
const anticipation = await db.query.installmentAnticipations.findFirst({
|
||||
where: and(
|
||||
eq(installmentAnticipations.id, validatedId),
|
||||
eq(installmentAnticipations.userId, user.id),
|
||||
),
|
||||
with: {
|
||||
transaction: true,
|
||||
payer: true,
|
||||
category: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!anticipation) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Antecipação não encontrada.",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Detalhes da antecipação carregados.",
|
||||
data: anticipation,
|
||||
};
|
||||
} catch (error) {
|
||||
return handleActionError(
|
||||
error,
|
||||
) as ActionResult<InstallmentAnticipationWithRelations>;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { attachments, transactionAttachments, transactions } from "@/db/schema";
|
||||
import {
|
||||
ALLOWED_MIME_TYPES,
|
||||
MAX_FILE_SIZE,
|
||||
} from "@/features/transactions/attachments-config";
|
||||
} from "@/features/transactions/lib/attachments-config";
|
||||
import {
|
||||
handleActionError,
|
||||
revalidateForEntity,
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
PAYMENT_METHODS,
|
||||
TRANSACTION_CONDITIONS,
|
||||
TRANSACTION_TYPES,
|
||||
} from "@/features/transactions/constants";
|
||||
} from "@/features/transactions/lib/constants";
|
||||
import { handleActionError } from "@/shared/lib/actions/helpers";
|
||||
import { getUser } from "@/shared/lib/auth/server";
|
||||
import { db } from "@/shared/lib/db";
|
||||
@@ -705,7 +705,7 @@ export async function createMassTransactionsAction(
|
||||
await sendPayerAutoEmails({
|
||||
userLabel: resolveUserLabel(user),
|
||||
action: "created",
|
||||
entriesByPagador: notificationEntries,
|
||||
entriesByPayer: notificationEntries,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -799,7 +799,7 @@ export async function deleteMultipleTransactionsAction(
|
||||
await sendPayerAutoEmails({
|
||||
userLabel: resolveUserLabel(user),
|
||||
action: "deleted",
|
||||
entriesByPagador: notificationEntries,
|
||||
entriesByPayer: notificationEntries,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
PAYMENT_METHODS,
|
||||
TRANSACTION_CONDITIONS,
|
||||
TRANSACTION_TYPES,
|
||||
} from "@/features/transactions/constants";
|
||||
} from "@/features/transactions/lib/constants";
|
||||
import {
|
||||
INITIAL_BALANCE_CONDITION,
|
||||
INITIAL_BALANCE_NOTE,
|
||||
@@ -31,7 +31,7 @@ import { addMonthsToPeriod, MONTH_NAMES } from "@/shared/utils/period";
|
||||
// Authorization Validation Functions
|
||||
// ============================================================================
|
||||
|
||||
export async function validatePagadorOwnership(
|
||||
export async function validatePayerOwnership(
|
||||
userId: string,
|
||||
payerId: string | null | undefined,
|
||||
): Promise<boolean> {
|
||||
@@ -65,19 +65,6 @@ export async function fetchOwnedPayerIds(
|
||||
return new Set(rows.map((row) => row.id));
|
||||
}
|
||||
|
||||
export async function validateCategoriaOwnership(
|
||||
userId: string,
|
||||
categoryId: string | null | undefined,
|
||||
): Promise<boolean> {
|
||||
if (!categoryId) return true;
|
||||
|
||||
const categoria = await db.query.categories.findFirst({
|
||||
where: and(eq(categories.id, categoryId), eq(categories.userId, userId)),
|
||||
});
|
||||
|
||||
return !!categoria;
|
||||
}
|
||||
|
||||
export async function fetchOwnedCategoryIds(
|
||||
userId: string,
|
||||
categoryIds: Array<string | null | undefined>,
|
||||
@@ -298,10 +285,10 @@ export const resolvePeriod = (purchaseDate: string, period?: string | null) => {
|
||||
return `${year}-${month}`;
|
||||
};
|
||||
|
||||
export const isValidDateInput = (value: string) =>
|
||||
const isValidDateInput = (value: string) =>
|
||||
!Number.isNaN(parseLocalDateString(value).getTime());
|
||||
|
||||
export const baseFields = z.object({
|
||||
const baseFields = z.object({
|
||||
purchaseDate: z
|
||||
.string({ message: "Informe a data da transação." })
|
||||
.trim()
|
||||
@@ -498,7 +485,7 @@ export const toggleSettlementSchema = z.object({
|
||||
.optional(),
|
||||
});
|
||||
|
||||
export type BaseInput = z.infer<typeof baseFields>;
|
||||
type BaseInput = z.infer<typeof baseFields>;
|
||||
export type CreateInput = z.infer<typeof createSchema>;
|
||||
export type UpdateInput = z.infer<typeof updateSchema>;
|
||||
export type DeleteInput = z.infer<typeof deleteSchema>;
|
||||
@@ -527,7 +514,7 @@ type InitialCandidate = {
|
||||
paymentMethod: string | null;
|
||||
};
|
||||
|
||||
export const isInitialBalanceLancamento = (record?: InitialCandidate | null) =>
|
||||
export const isInitialBalanceTransaction = (record?: InitialCandidate | null) =>
|
||||
!!record &&
|
||||
record.note === INITIAL_BALANCE_NOTE &&
|
||||
record.transactionType === INITIAL_BALANCE_TRANSACTION_TYPE &&
|
||||
@@ -554,7 +541,7 @@ const splitAmount = (totalCents: number, parts: number) => {
|
||||
);
|
||||
};
|
||||
|
||||
export type Share = {
|
||||
type Share = {
|
||||
payerId: string | null;
|
||||
amountCents: number;
|
||||
};
|
||||
@@ -617,7 +604,7 @@ type BuildTransactionRecordsParams = {
|
||||
|
||||
export type TransactionInsert = typeof transactions.$inferInsert;
|
||||
|
||||
export const buildLancamentoRecords = ({
|
||||
export const buildTransactionRecords = ({
|
||||
data,
|
||||
userId,
|
||||
period,
|
||||
@@ -859,7 +846,7 @@ export const updateBulkSchema = z.object({
|
||||
|
||||
export type UpdateBulkInput = z.infer<typeof updateBulkSchema>;
|
||||
|
||||
export const massAddTransactionSchema = z.object({
|
||||
const massAddTransactionSchema = z.object({
|
||||
purchaseDate: z
|
||||
.string({ message: "Informe a data da transação." })
|
||||
.trim()
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
"use server";
|
||||
|
||||
import { z } from "zod";
|
||||
import { fetchAccountLancamentos } from "@/features/accounts/statement-queries";
|
||||
import type { TransactionsExportContext } from "@/features/transactions/export-types";
|
||||
import { fetchAccountTransactions } from "@/features/accounts/statement-queries";
|
||||
import type { TransactionsExportContext } from "@/features/transactions/lib/export-types";
|
||||
import {
|
||||
buildSluggedFilters,
|
||||
buildSlugMaps,
|
||||
buildTransactionWhere,
|
||||
mapTransactionsData,
|
||||
} from "@/features/transactions/page-helpers";
|
||||
} from "@/features/transactions/lib/page-helpers";
|
||||
import {
|
||||
fetchTransactionFilterSources,
|
||||
fetchTransactions,
|
||||
@@ -66,7 +66,7 @@ export async function exportTransactionsDataAction(
|
||||
|
||||
const rows =
|
||||
validated.source === "account-statement"
|
||||
? await fetchAccountLancamentos(filters, validated.settledOnly ?? true)
|
||||
? await fetchAccountTransactions(filters, validated.settledOnly ?? true)
|
||||
: await fetchTransactions(filters);
|
||||
|
||||
return {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { eq } from "drizzle-orm";
|
||||
import { transactions } from "@/db/schema";
|
||||
import { mapTransactionsData } from "@/features/transactions/page-helpers";
|
||||
import { mapTransactionsData } from "@/features/transactions/lib/page-helpers";
|
||||
import { fetchTransactionsWithRelations } from "@/features/transactions/queries";
|
||||
import { getUser } from "@/shared/lib/auth/server";
|
||||
import type { TransactionItem } from "../components/types";
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import {
|
||||
buildOptionSets,
|
||||
buildSluggedFilters,
|
||||
} from "@/features/transactions/page-helpers";
|
||||
} from "@/features/transactions/lib/page-helpers";
|
||||
import {
|
||||
fetchRecentEstablishments,
|
||||
fetchTransactionFilterSources,
|
||||
|
||||
@@ -6,7 +6,7 @@ import { transactions } from "@/db/schema";
|
||||
import {
|
||||
validateCartaoOwnership,
|
||||
validateContaOwnership,
|
||||
validatePagadorOwnership,
|
||||
validatePayerOwnership,
|
||||
} from "@/features/transactions/actions/core";
|
||||
import { revalidateForEntity } from "@/shared/lib/actions/helpers";
|
||||
import { getUserId } from "@/shared/lib/auth/server";
|
||||
@@ -36,8 +36,7 @@ const importSchema = z.object({
|
||||
.optional(),
|
||||
});
|
||||
|
||||
export type ImportRow = z.infer<typeof importRowSchema>;
|
||||
export type ImportInput = z.infer<typeof importSchema>;
|
||||
type ImportInput = z.infer<typeof importSchema>;
|
||||
|
||||
type ImportResult =
|
||||
| { success: true; imported: number; skipped: number; importBatchId: string }
|
||||
@@ -79,7 +78,7 @@ export async function importTransactionsAction(
|
||||
|
||||
// Valida ownership
|
||||
const [payerOk, accountOk, cardOk] = await Promise.all([
|
||||
validatePagadorOwnership(userId, payerId),
|
||||
validatePayerOwnership(userId, payerId),
|
||||
validateContaOwnership(userId, accountId),
|
||||
validateCartaoOwnership(userId, cardId),
|
||||
]);
|
||||
|
||||
@@ -21,11 +21,11 @@ import {
|
||||
getBusinessTodayDate,
|
||||
parseLocalDateString,
|
||||
} from "@/shared/utils/date";
|
||||
import { copyAttachmentsForImport } from "../attachment-copy";
|
||||
import { copyAttachmentsForImport } from "../lib/attachment-copy";
|
||||
import { cleanupAttachmentsAfterTransactionDelete } from "./attachments";
|
||||
import {
|
||||
buildLancamentoRecords,
|
||||
buildShares,
|
||||
buildTransactionRecords,
|
||||
type CreateInput,
|
||||
centsToDecimalString,
|
||||
createSchema,
|
||||
@@ -33,7 +33,7 @@ import {
|
||||
deleteSchema,
|
||||
formatPaidInvoicePeriods,
|
||||
getPaidInvoicePeriods,
|
||||
isInitialBalanceLancamento,
|
||||
isInitialBalanceTransaction,
|
||||
resolvePeriod,
|
||||
resolveUserLabel,
|
||||
revalidate,
|
||||
@@ -95,7 +95,7 @@ export async function createTransactionAction(
|
||||
data.condition === "Parcelado" || data.condition === "Recorrente";
|
||||
const seriesId = isSeriesLancamento ? randomUUID() : null;
|
||||
|
||||
const records = buildLancamentoRecords({
|
||||
const records = buildTransactionRecords({
|
||||
data,
|
||||
userId: user.id,
|
||||
period,
|
||||
@@ -180,7 +180,7 @@ export async function createTransactionAction(
|
||||
await sendPayerAutoEmails({
|
||||
userLabel: resolveUserLabel(user),
|
||||
action: "created",
|
||||
entriesByPagador: notificationEntries,
|
||||
entriesByPayer: notificationEntries,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -343,7 +343,7 @@ export async function updateTransactionAction(
|
||||
and(eq(transactions.id, data.id), eq(transactions.userId, user.id)),
|
||||
);
|
||||
|
||||
if (isInitialBalanceLancamento(existing) && existing.accountId) {
|
||||
if (isInitialBalanceTransaction(existing) && existing.accountId) {
|
||||
const updatedInitialBalance = formatDecimalForDbRequired(
|
||||
Math.abs(data.amount ?? 0),
|
||||
);
|
||||
@@ -465,7 +465,7 @@ export async function deleteTransactionAction(
|
||||
await sendPayerAutoEmails({
|
||||
userLabel: resolveUserLabel(user),
|
||||
action: "deleted",
|
||||
entriesByPagador: notificationEntries,
|
||||
entriesByPayer: notificationEntries,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { toast } from "sonner";
|
||||
import {
|
||||
ALLOWED_MIME_TYPES,
|
||||
DEFAULT_MAX_FILE_SIZE_MB,
|
||||
} from "@/features/transactions/attachments-config";
|
||||
} from "@/features/transactions/lib/attachments-config";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
|
||||
interface AttachmentFilePickerProps {
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
import {
|
||||
ALLOWED_MIME_TYPES,
|
||||
DEFAULT_MAX_FILE_SIZE_MB,
|
||||
} from "@/features/transactions/attachments-config";
|
||||
} from "@/features/transactions/lib/attachments-config";
|
||||
|
||||
interface AttachmentUploadProps {
|
||||
transactionId: string;
|
||||
|
||||
@@ -7,7 +7,7 @@ import { CategoryIcon } from "@/features/categories/components/category-icon";
|
||||
import {
|
||||
createInstallmentAnticipationAction,
|
||||
getEligibleInstallmentsAction,
|
||||
} from "@/features/transactions/anticipation-actions";
|
||||
} from "@/features/transactions/actions/anticipation";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
import { PeriodPicker } from "@/shared/components/period-picker";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { useMemo, useState, useTransition } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { createTransactionAction } from "@/features/transactions/actions";
|
||||
import { groupAndSortCategories } from "@/features/transactions/category-helpers";
|
||||
import { groupAndSortCategories } from "@/features/transactions/lib/category-helpers";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
import { RiAddLine, RiDeleteBinLine } from "@remixicon/react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { groupAndSortCategories } from "@/features/transactions/category-helpers";
|
||||
import { groupAndSortCategories } from "@/features/transactions/lib/category-helpers";
|
||||
import {
|
||||
PAYMENT_METHODS,
|
||||
type TRANSACTION_TYPES,
|
||||
} from "@/features/transactions/constants";
|
||||
} from "@/features/transactions/lib/constants";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { CurrencyInput } from "@/shared/components/ui/currency-input";
|
||||
import { DatePicker } from "@/shared/components/ui/date-picker";
|
||||
@@ -51,7 +51,7 @@ import {
|
||||
PaymentMethodSelectContent,
|
||||
TransactionTypeSelectContent,
|
||||
} from "../select-items";
|
||||
import { EstabelecimentoInput } from "../shared/establishment-input";
|
||||
import { EstablishmentInput } from "../shared/establishment-input";
|
||||
import type { SelectOption } from "../types";
|
||||
|
||||
/** Payment methods sem Boleto para este modal */
|
||||
@@ -490,7 +490,7 @@ export function MassAddDialog({
|
||||
>
|
||||
Estabelecimento {index + 1}
|
||||
</Label>
|
||||
<EstabelecimentoInput
|
||||
<EstablishmentInput
|
||||
id={`name-${transaction.id}`}
|
||||
placeholder="Local"
|
||||
value={transaction.name}
|
||||
|
||||
@@ -4,8 +4,8 @@ import { useRouter } from "next/navigation";
|
||||
import { useEffect, useMemo, useState, useTransition } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { refundTransactionAction } from "@/features/transactions/actions/refund-action";
|
||||
import { deriveCreditCardPeriod } from "@/features/transactions/form-helpers";
|
||||
import { formatDate } from "@/features/transactions/formatting-helpers";
|
||||
import { deriveCreditCardPeriod } from "@/features/transactions/lib/form-helpers";
|
||||
import { formatDate } from "@/features/transactions/lib/formatting-helpers";
|
||||
import { PeriodPicker } from "@/shared/components/period-picker";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { DatePicker } from "@/shared/components/ui/date-picker";
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
formatCondition,
|
||||
formatDate,
|
||||
formatPeriod,
|
||||
} from "@/features/transactions/formatting-helpers";
|
||||
} from "@/features/transactions/lib/formatting-helpers";
|
||||
import { TransactionTypeBadge } from "@/shared/components/transaction-type-badge";
|
||||
import {
|
||||
Avatar,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { CalculatorDialogButton } from "@/shared/components/calculator/calculato
|
||||
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 { EstablishmentInput } from "../../shared/establishment-input";
|
||||
import type { BasicFieldsSectionProps } from "./transaction-dialog-types";
|
||||
|
||||
export function BasicFieldsSection({
|
||||
@@ -17,7 +17,7 @@ export function BasicFieldsSection({
|
||||
<div className="space-y-3">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="name">Descrição</Label>
|
||||
<EstabelecimentoInput
|
||||
<EstablishmentInput
|
||||
id="name"
|
||||
value={formState.name}
|
||||
onChange={(value) => onFieldChange("name", value)}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { TRANSACTION_TYPES } from "@/features/transactions/constants";
|
||||
import { TRANSACTION_TYPES } from "@/features/transactions/lib/constants";
|
||||
import { Label } from "@/shared/components/ui/label";
|
||||
import {
|
||||
Select,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { TRANSACTION_CONDITIONS } from "@/features/transactions/constants";
|
||||
import { TRANSACTION_CONDITIONS } from "@/features/transactions/lib/constants";
|
||||
import { Label } from "@/shared/components/ui/label";
|
||||
import {
|
||||
Select,
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
RiCheckboxCircleFill,
|
||||
} from "@remixicon/react";
|
||||
import { useState } from "react";
|
||||
import { PAYMENT_METHODS } from "@/features/transactions/constants";
|
||||
import { PAYMENT_METHODS } from "@/features/transactions/lib/constants";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { Label } from "@/shared/components/ui/label";
|
||||
import { MonthPicker } from "@/shared/components/ui/month-picker";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { TransactionFormState } from "@/features/transactions/form-helpers";
|
||||
import type { TransactionFormState } from "@/features/transactions/lib/form-helpers";
|
||||
import type { SelectOption, TransactionItem } from "../../types";
|
||||
|
||||
export type FormState = TransactionFormState;
|
||||
@@ -71,7 +71,7 @@ export interface TransactionDialogProps {
|
||||
}) => void;
|
||||
}
|
||||
|
||||
export interface BaseFieldSectionProps {
|
||||
interface BaseFieldSectionProps {
|
||||
formState: FormState;
|
||||
onFieldChange: <Key extends keyof FormState>(
|
||||
key: Key,
|
||||
|
||||
@@ -14,12 +14,12 @@ import {
|
||||
import {
|
||||
filterSecondaryPayerOptions,
|
||||
groupAndSortCategories,
|
||||
} from "@/features/transactions/category-helpers";
|
||||
} from "@/features/transactions/lib/category-helpers";
|
||||
import {
|
||||
applyFieldDependencies,
|
||||
buildTransactionInitialState,
|
||||
deriveCreditCardPeriod,
|
||||
} from "@/features/transactions/form-helpers";
|
||||
} from "@/features/transactions/lib/form-helpers";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import {
|
||||
Collapsible,
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
SelectValue,
|
||||
} from "@/shared/components/ui/select";
|
||||
|
||||
export type AccountCardValue = `card:${string}` | `account:${string}`;
|
||||
type AccountCardValue = `card:${string}` | `account:${string}`;
|
||||
|
||||
export function encodeAccountCard(
|
||||
type: "card" | "account",
|
||||
|
||||
@@ -21,7 +21,7 @@ import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog";
|
||||
import type {
|
||||
TransactionsExportContext,
|
||||
TransactionsPaginationState,
|
||||
} from "../../export-types";
|
||||
} from "../../lib/export-types";
|
||||
import { AnticipateInstallmentsDialog } from "../dialogs/anticipate-installments-dialog/anticipate-installments-dialog";
|
||||
import { AnticipationHistoryDialog } from "../dialogs/anticipate-installments-dialog/anticipation-history-dialog";
|
||||
import {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { RiBankCard2Line, RiBankLine } from "@remixicon/react";
|
||||
import Image from "next/image";
|
||||
import { CategoryIcon } from "@/features/categories/components/category-icon";
|
||||
import StatusDot from "@/shared/components/status-dot";
|
||||
import StatusDot from "@/shared/components/feedback/status-dot";
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { format } from "date-fns";
|
||||
import { ptBR } from "date-fns/locale";
|
||||
import { useTransition } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { cancelInstallmentAnticipationAction } from "@/features/transactions/anticipation-actions";
|
||||
import { cancelInstallmentAnticipationAction } from "@/features/transactions/actions/anticipation";
|
||||
import type { InstallmentAnticipationListItem } from "@/features/transactions/hooks/use-installment-anticipations";
|
||||
import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
PopoverTrigger,
|
||||
} from "@/shared/components/ui/popover";
|
||||
|
||||
export interface EstabelecimentoInputProps {
|
||||
interface EstablishmentInputProps {
|
||||
id?: string;
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
@@ -27,7 +27,7 @@ export interface EstabelecimentoInputProps {
|
||||
maxLength?: number;
|
||||
}
|
||||
|
||||
export function EstabelecimentoInput({
|
||||
export function EstablishmentInput({
|
||||
id,
|
||||
value,
|
||||
onChange,
|
||||
@@ -35,7 +35,7 @@ export function EstabelecimentoInput({
|
||||
placeholder = "Ex.: Padaria, Transferência, Saldo inicial",
|
||||
required = false,
|
||||
maxLength = 20,
|
||||
}: EstabelecimentoInputProps) {
|
||||
}: EstablishmentInputProps) {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [searchValue, setSearchValue] = React.useState("");
|
||||
const [width, setWidth] = React.useState<number | undefined>();
|
||||
|
||||
@@ -18,11 +18,11 @@ import {
|
||||
import type { ColumnDef } from "@tanstack/react-table";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { DEFAULT_LANCAMENTOS_COLUMN_ORDER } from "@/features/transactions/column-order";
|
||||
import { DEFAULT_TRANSACTIONS_COLUMN_ORDER } from "@/features/transactions/lib/column-order";
|
||||
import {
|
||||
CREDIT_CARD_PAYMENT_METHOD,
|
||||
SETTLEABLE_PAYMENT_METHODS,
|
||||
} from "@/features/transactions/constants";
|
||||
} from "@/features/transactions/lib/constants";
|
||||
import {
|
||||
CategoryIconBadge,
|
||||
EstablishmentLogo,
|
||||
@@ -58,7 +58,7 @@ import { getConditionIcon, getPaymentMethodIcon } from "@/shared/utils/icons";
|
||||
import { cn } from "@/shared/utils/ui";
|
||||
import type { TransactionItem } from "../types";
|
||||
|
||||
export type BuildColumnsArgs = {
|
||||
type BuildColumnsArgs = {
|
||||
currentUserId: string;
|
||||
noteAsColumn: boolean;
|
||||
onEdit?: (item: TransactionItem) => void;
|
||||
@@ -748,6 +748,6 @@ export function getTransactionColumns(
|
||||
const built = buildColumns(args);
|
||||
const order = args.columnOrder?.length
|
||||
? args.columnOrder
|
||||
: DEFAULT_LANCAMENTOS_COLUMN_ORDER;
|
||||
: DEFAULT_TRANSACTIONS_COLUMN_ORDER;
|
||||
return reorderColumnsByPreference(built, order);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
SETTLED_FILTER_VALUES,
|
||||
TRANSACTION_CONDITIONS,
|
||||
TRANSACTION_TYPES,
|
||||
} from "@/features/transactions/constants";
|
||||
} from "@/features/transactions/lib/constants";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import {
|
||||
Command,
|
||||
|
||||
@@ -20,8 +20,8 @@ import { useMemo, useState } from "react";
|
||||
import type {
|
||||
TransactionsExportContext,
|
||||
TransactionsPaginationState,
|
||||
} from "@/features/transactions/export-types";
|
||||
import { EmptyState } from "@/shared/components/empty-state";
|
||||
} from "@/features/transactions/lib/export-types";
|
||||
import { EmptyState } from "@/shared/components/feedback/empty-state";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { Card, CardContent } from "@/shared/components/ui/card";
|
||||
import {
|
||||
@@ -50,7 +50,7 @@ import { getTransactionColumns } from "./transactions-columns";
|
||||
import { TransactionsFilters } from "./transactions-filters";
|
||||
import { TransactionsPagination } from "./transactions-pagination";
|
||||
|
||||
type LancamentosTableProps = {
|
||||
type TransactionsTableProps = {
|
||||
data: TransactionItem[];
|
||||
currentUserId: string;
|
||||
noteAsColumn?: boolean;
|
||||
@@ -106,7 +106,7 @@ export function TransactionsTable({
|
||||
isSettlementLoading,
|
||||
showActions = true,
|
||||
showFilters = true,
|
||||
}: LancamentosTableProps) {
|
||||
}: TransactionsTableProps) {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
@@ -9,8 +9,8 @@ import {
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { exportTransactionsDataAction } from "@/features/transactions/actions";
|
||||
import type { TransactionsExportContext } from "@/features/transactions/export-types";
|
||||
import { formatCurrency } from "@/features/transactions/formatting-helpers";
|
||||
import type { TransactionsExportContext } from "@/features/transactions/lib/export-types";
|
||||
import { formatCurrency } from "@/features/transactions/lib/formatting-helpers";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
import { displayPeriod } from "@/shared/utils/period";
|
||||
import type { TransactionItem } from "./types";
|
||||
|
||||
interface LancamentosExportProps {
|
||||
interface TransactionsExportProps {
|
||||
lancamentos: TransactionItem[];
|
||||
period: string;
|
||||
exportContext?: TransactionsExportContext;
|
||||
@@ -47,7 +47,7 @@ export function TransactionsExport({
|
||||
lancamentos,
|
||||
period,
|
||||
exportContext,
|
||||
}: LancamentosExportProps) {
|
||||
}: TransactionsExportProps) {
|
||||
const [isExporting, setIsExporting] = useState(false);
|
||||
|
||||
const getFileName = (extension: string) => {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { z } from "zod";
|
||||
import { fetchJson } from "@/shared/lib/fetch-json";
|
||||
import { fetchJson } from "@/shared/utils/fetch-json";
|
||||
|
||||
const anticipationItemSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { TransactionAttachmentListItem } from "@/features/transactions/attachment-queries";
|
||||
import { fetchJson } from "@/shared/lib/fetch-json";
|
||||
import type { TransactionAttachmentListItem } from "@/features/transactions/lib/attachment-queries";
|
||||
import { fetchJson } from "@/shared/utils/fetch-json";
|
||||
|
||||
export const transactionAttachmentsQueryKey = (transactionId: string) =>
|
||||
["transactions", "attachments", transactionId] as const;
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
import { db } from "@/shared/lib/db";
|
||||
import { uuidSchema } from "@/shared/lib/schemas/common";
|
||||
|
||||
export type InstallmentAnticipationListItem = {
|
||||
type InstallmentAnticipationListItem = {
|
||||
id: string;
|
||||
anticipationPeriod: string;
|
||||
anticipationDate: string;
|
||||
@@ -2,7 +2,7 @@
|
||||
* Ids das colunas reordenáveis da tabela de lançamentos (extrato).
|
||||
* select, purchaseDate e actions são fixos (início, oculto, fim).
|
||||
*/
|
||||
export const LANCAMENTOS_REORDERABLE_COLUMN_IDS = [
|
||||
const TRANSACTIONS_REORDERABLE_COLUMN_IDS = [
|
||||
"name",
|
||||
"transactionType",
|
||||
"amount",
|
||||
@@ -14,7 +14,7 @@ export const LANCAMENTOS_REORDERABLE_COLUMN_IDS = [
|
||||
"contaCartao",
|
||||
] as const;
|
||||
|
||||
export const LANCAMENTOS_COLUMN_LABELS: Record<string, string> = {
|
||||
export const TRANSACTIONS_COLUMN_LABELS: Record<string, string> = {
|
||||
name: "Estabelecimento",
|
||||
transactionType: "Transação",
|
||||
amount: "Valor",
|
||||
@@ -26,6 +26,6 @@ export const LANCAMENTOS_COLUMN_LABELS: Record<string, string> = {
|
||||
contaCartao: "Conta/Cartão",
|
||||
};
|
||||
|
||||
export const DEFAULT_LANCAMENTOS_COLUMN_ORDER: string[] = [
|
||||
...LANCAMENTOS_REORDERABLE_COLUMN_IDS,
|
||||
export const DEFAULT_TRANSACTIONS_COLUMN_ORDER: string[] = [
|
||||
...TRANSACTIONS_REORDERABLE_COLUMN_IDS,
|
||||
];
|
||||
@@ -1,4 +1,4 @@
|
||||
export type TransactionExportFilters = {
|
||||
type TransactionExportFilters = {
|
||||
transactionFilter: string | null;
|
||||
conditionFilter: string | null;
|
||||
paymentFilter: string | null;
|
||||
@@ -90,7 +90,7 @@ export type TransactionFormState = {
|
||||
/**
|
||||
* Initial state overrides for lancamento form
|
||||
*/
|
||||
export type LancamentoFormOverrides = {
|
||||
type TransactionFormOverrides = {
|
||||
defaultCardId?: string | null;
|
||||
defaultPaymentMethod?: string | null;
|
||||
defaultPurchaseDate?: string | null;
|
||||
@@ -107,7 +107,7 @@ export function buildTransactionInitialState(
|
||||
transaction?: TransactionItem,
|
||||
defaultPayerId?: string | null,
|
||||
preferredPeriod?: string,
|
||||
overrides?: LancamentoFormOverrides,
|
||||
overrides?: TransactionFormOverrides,
|
||||
): TransactionFormState {
|
||||
const purchaseDate = transaction?.purchaseDate
|
||||
? transaction.purchaseDate.slice(0, 10)
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
SETTLED_FILTER_VALUES,
|
||||
TRANSACTION_CONDITIONS,
|
||||
TRANSACTION_TYPES,
|
||||
} from "@/features/transactions/constants";
|
||||
} from "@/features/transactions/lib/constants";
|
||||
import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants";
|
||||
import {
|
||||
PAYER_ROLE_ADMIN,
|
||||
@@ -32,8 +32,8 @@ export type ResolvedSearchParams =
|
||||
| Record<string, string | string[] | undefined>
|
||||
| undefined;
|
||||
|
||||
export const TRANSACTIONS_DEFAULT_PAGE_SIZE = 30;
|
||||
export const TRANSACTIONS_PAGE_SIZE_OPTIONS = [5, 10, 20, 30, 40, 50, 100];
|
||||
const TRANSACTIONS_DEFAULT_PAGE_SIZE = 30;
|
||||
const TRANSACTIONS_PAGE_SIZE_OPTIONS = [5, 10, 20, 30, 40, 50, 100];
|
||||
|
||||
export type TransactionSearchFilters = {
|
||||
transactionFilter: string | null;
|
||||
@@ -91,16 +91,16 @@ export type SlugMaps = {
|
||||
card: Map<string, string>;
|
||||
};
|
||||
|
||||
export type FilterOption = {
|
||||
type FilterOption = {
|
||||
slug: string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
export type AccountCardFilterOption = FilterOption & {
|
||||
type AccountCardFilterOption = FilterOption & {
|
||||
kind: "conta" | "cartao";
|
||||
};
|
||||
|
||||
export type TransactionOptionSets = {
|
||||
type TransactionOptionSets = {
|
||||
payerOptions: SelectOption[];
|
||||
splitPayerOptions: SelectOption[];
|
||||
defaultPayerId: string | null;
|
||||
@@ -186,7 +186,7 @@ const createSlugGenerator = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export const toOption = (
|
||||
const toOption = (
|
||||
value: string,
|
||||
label: string | null | undefined,
|
||||
role?: string | null,
|
||||
@@ -32,7 +32,7 @@ type TransactionQueryInput = BaseTransactionQueryInput & {
|
||||
offset?: number;
|
||||
};
|
||||
|
||||
export type PaginatedTransactionsResult = {
|
||||
type PaginatedTransactionsResult = {
|
||||
rows: Awaited<ReturnType<typeof fetchTransactions>>;
|
||||
totalItems: number;
|
||||
page: number;
|
||||
|
||||
Reference in New Issue
Block a user