feat: implementar sistema de preferências do usuário e refatorar changelog

Adiciona sistema completo de preferências de usuário:
  - Cria tabela userPreferences no schema com campos disableMagnetlines, periodMonthsBefore e periodMonthsAfter
  - Implementa página de Ajustes com abas (Preferências, Alterar nome, Senha, E-mail, Deletar conta)
  - Adiciona componente PreferencesForm para configuração de magnetlines e períodos de exibição
  - Propaga periodPreferences para todos os componentes de lançamentos e calendário

  Refatora sistema de changelog:
  - Remove implementação anterior baseada em JSON estático
  - Adiciona nova página de changelog dinâmica em app/(dashboard)/changelog
  - Adiciona componente changelog-list.tsx
  - Remove arquivos obsoletos (changelog-notification, actions, data, utils, scripts)

  Adiciona controle de saldo inicial em contas:
  - Novo campo excludeInitialBalanceFromIncome em contas
  - Permite excluir saldo inicial do cálculo de receitas
  - Atualiza queries de lançamentos para respeitar esta configuração

  Melhorias adicionais:
  - Adiciona componente ui/accordion.tsx do shadcn/ui
  - Refatora formatPeriodLabel para displayPeriod centralizado
  - Propaga estabelecimentos para componentes de lançamentos
  - Remove variável DB_PROVIDER obsoleta do .env.example e documentação
  - Adiciona 6 migrações de banco de dados (0003-0008)
This commit is contained in:
Felipe Coutinho
2026-01-03 14:18:03 +00:00
parent 3eca48c71a
commit fd817683ca
87 changed files with 13582 additions and 1445 deletions

View File

@@ -12,4 +12,6 @@ export const LANCAMENTO_PAYMENT_METHODS = [
"Pix",
"Dinheiro",
"Boleto",
"Pré-Pago | VR/VA",
"Transferência bancária",
] as const;

View File

@@ -110,7 +110,7 @@ export function buildLancamentoInitialState(
isSettled:
paymentMethod === "Cartão de crédito"
? null
: lancamento?.isSettled ?? false,
: lancamento?.isSettled ?? true,
};
}
@@ -150,7 +150,7 @@ export function applyFieldDependencies(
updates.isSettled = null;
} else {
updates.cartaoId = undefined;
updates.isSettled = currentState.isSettled ?? false;
updates.isSettled = currentState.isSettled ?? true;
}
// Clear boleto-specific fields if not boleto

View File

@@ -80,7 +80,10 @@ export function formatCondition(value?: string | null): string {
*/
export function getTransactionBadgeVariant(type?: string | null): "default" | "destructive" | "secondary" {
if (!type) return "secondary";
return type.toLowerCase() === "receita" ? "default" : "destructive";
const normalized = type.toLowerCase();
return normalized === "receita" || normalized === "saldo inicial"
? "default"
: "destructive";
}
/**

View File

@@ -55,6 +55,7 @@ type CategoriaSluggedOption = BaseSluggedOption & {
type ContaSluggedOption = BaseSluggedOption & {
kind: "conta";
logo: string | null;
accountType: string | null;
};
type CartaoSluggedOption = BaseSluggedOption & {
@@ -154,7 +155,8 @@ export const toOption = (
slug?: string | null,
avatarUrl?: string | null,
logo?: string | null,
icon?: string | null
icon?: string | null,
accountType?: string | null
): SelectOption => ({
value,
label: normalizeLabel(label),
@@ -164,6 +166,7 @@ export const toOption = (
avatarUrl: avatarUrl ?? null,
logo: logo ?? null,
icon: icon ?? null,
accountType: accountType ?? null,
});
export const fetchLancamentoFilterSources = async (userId: string) => {
@@ -234,6 +237,7 @@ export const buildSluggedFilters = ({
slug: contaCartaoSlugger(label),
kind: "conta" as const,
logo: conta.logo ?? null,
accountType: conta.accountType ?? null,
};
});
@@ -468,8 +472,8 @@ export const buildOptionSets = ({
: contaFiltersRaw;
const contaOptions = sortByLabel(
contaOptionsSource.map(({ id, label, slug, logo }) =>
toOption(id, label, undefined, undefined, slug, undefined, logo)
contaOptionsSource.map(({ id, label, slug, logo, accountType }) =>
toOption(id, label, undefined, undefined, slug, undefined, logo, undefined, accountType)
)
);