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

@@ -2,6 +2,7 @@ import { DeleteAccountForm } from "@/components/ajustes/delete-account-form";
import { UpdateEmailForm } from "@/components/ajustes/update-email-form";
import { UpdateNameForm } from "@/components/ajustes/update-name-form";
import { UpdatePasswordForm } from "@/components/ajustes/update-password-form";
import { PreferencesForm } from "@/components/ajustes/preferences-form";
import { Card } from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { auth } from "@/lib/auth/config";
@@ -27,14 +28,28 @@ export default async function Page() {
where: eq(schema.account.userId, session.user.id),
});
// Buscar preferências do usuário
const userPreferencesResult = await db
.select({
disableMagnetlines: schema.userPreferences.disableMagnetlines,
periodMonthsBefore: schema.userPreferences.periodMonthsBefore,
periodMonthsAfter: schema.userPreferences.periodMonthsAfter,
})
.from(schema.userPreferences)
.where(eq(schema.userPreferences.userId, session.user.id))
.limit(1);
const userPreferences = userPreferencesResult[0] || null;
// Se o providerId for "google", o usuário usa Google OAuth
const authProvider = userAccount?.providerId || "credential";
return (
<div className="max-w-3xl">
<Tabs defaultValue="nome" className="w-full">
<TabsList className="w-full grid grid-cols-4 mb-2">
<TabsTrigger value="nome">Altere seu nome</TabsTrigger>
<div className="w-full">
<Tabs defaultValue="preferencias" className="w-full">
<TabsList>
<TabsTrigger value="preferencias">Preferências</TabsTrigger>
<TabsTrigger value="nome">Alterar nome</TabsTrigger>
<TabsTrigger value="senha">Alterar senha</TabsTrigger>
<TabsTrigger value="email">Alterar e-mail</TabsTrigger>
<TabsTrigger value="deletar" className="text-destructive">
@@ -42,56 +57,92 @@ export default async function Page() {
</TabsTrigger>
</TabsList>
<Card className="p-6">
<TabsContent value="nome" className="space-y-4">
<div>
<h2 className="text-lg font-medium mb-1">Alterar nome</h2>
<p className="text-sm text-muted-foreground mb-4">
Atualize como seu nome aparece no Opensheets. Esse nome pode ser
exibido em diferentes seções do app e em comunicações.
</p>
<TabsContent value="preferencias" className="mt-4">
<Card className="p-6">
<div className="space-y-4">
<div>
<h2 className="text-lg font-bold mb-1">Preferências</h2>
<p className="text-sm text-muted-foreground mb-4">
Personalize sua experiência no Opensheets ajustando as
configurações de acordo com suas necessidades.
</p>
</div>
<PreferencesForm
disableMagnetlines={
userPreferences?.disableMagnetlines ?? false
}
periodMonthsBefore={userPreferences?.periodMonthsBefore ?? 3}
periodMonthsAfter={userPreferences?.periodMonthsAfter ?? 3}
/>
</div>
<UpdateNameForm currentName={userName} />
</TabsContent>
</Card>
</TabsContent>
<TabsContent value="senha" className="space-y-4">
<div>
<h2 className="text-lg font-medium mb-1">Alterar senha</h2>
<p className="text-sm text-muted-foreground mb-4">
Defina uma nova senha para sua conta. Guarde-a em local seguro.
</p>
<TabsContent value="nome" className="mt-4">
<Card className="p-6">
<div className="space-y-4">
<div>
<h2 className="text-lg font-bold mb-1">Alterar nome</h2>
<p className="text-sm text-muted-foreground mb-4">
Atualize como seu nome aparece no Opensheets. Esse nome pode
ser exibido em diferentes seções do app e em comunicações.
</p>
</div>
<UpdateNameForm currentName={userName} />
</div>
<UpdatePasswordForm authProvider={authProvider} />
</TabsContent>
</Card>
</TabsContent>
<TabsContent value="email" className="space-y-4">
<div>
<h2 className="text-lg font-medium mb-1">Alterar e-mail</h2>
<p className="text-sm text-muted-foreground mb-4">
Atualize o e-mail associado à sua conta. Você precisará
confirmar os links enviados para o novo e também para o e-mail
atual (quando aplicável) para concluir a alteração.
</p>
<TabsContent value="senha" className="mt-4">
<Card className="p-6">
<div className="space-y-4">
<div>
<h2 className="text-lg font-bold mb-1">Alterar senha</h2>
<p className="text-sm text-muted-foreground mb-4">
Defina uma nova senha para sua conta. Guarde-a em local
seguro.
</p>
</div>
<UpdatePasswordForm authProvider={authProvider} />
</div>
<UpdateEmailForm
currentEmail={userEmail}
authProvider={authProvider}
/>
</TabsContent>
</Card>
</TabsContent>
<TabsContent value="deletar" className="space-y-4">
<div>
<h2 className="text-lg font-medium mb-1 text-destructive">
Deletar conta
</h2>
<p className="text-sm text-muted-foreground mb-4">
Ao prosseguir, sua conta e todos os dados associados serão
excluídos de forma irreversível.
</p>
<TabsContent value="email" className="mt-4">
<Card className="p-6">
<div className="space-y-4">
<div>
<h2 className="text-lg font-bold mb-1">Alterar e-mail</h2>
<p className="text-sm text-muted-foreground mb-4">
Atualize o e-mail associado à sua conta. Você precisará
confirmar os links enviados para o novo e também para o e-mail
atual (quando aplicável) para concluir a alteração.
</p>
</div>
<UpdateEmailForm
currentEmail={userEmail}
authProvider={authProvider}
/>
</div>
<DeleteAccountForm />
</TabsContent>
</Card>
</Card>
</TabsContent>
<TabsContent value="deletar" className="mt-4">
<Card className="p-6">
<div className="space-y-4">
<div>
<h2 className="text-lg font-bold mb-1 text-destructive">
Deletar conta
</h2>
<p className="text-sm text-muted-foreground mb-4">
Ao prosseguir, sua conta e todos os dados associados serão
excluídos de forma irreversível.
</p>
</div>
<DeleteAccountForm />
</div>
</Card>
</TabsContent>
</Tabs>
</div>
);