diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b772ab..e5b7aff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,36 @@ Todas as mudanças notáveis deste projeto serão documentadas neste arquivo. O formato é baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/), e este projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR/). +## [1.4.0] - 2026-02-07 + +### Corrigido + +- Widgets de boleto/fatura não atualizavam após pagamento: actions de fatura (`updateInvoicePaymentStatusAction`, `updatePaymentDateAction`) e antecipação de parcelas não invalidavam o cache do dashboard +- Substituídos `revalidatePath()` manuais por `revalidateForEntity()` nas actions de fatura e antecipação +- Expandido `revalidateConfig.cartoes` para incluir `/contas` e `/lancamentos` (afetados por pagamento de fatura) +- Scroll não funcionava em listas Popover+Command (estabelecimento, categorias, filtros): adicionado `modal` ao Popover nos 4 componentes afetados + +### Adicionado + +- Link "detalhes" no card de orçamento para navegar diretamente à página da categoria +- Indicadores de tendência coloridos nos cards de métricas do dashboard (receitas, despesas, balanço, previsto) com cores semânticas sutis +- Tokens semânticos de estado no design system: `--success`, `--warning`, `--info` (com foregrounds) para light e dark mode +- Cores de chart estendidas de 6 para 10 (`--chart-7` a `--chart-10`: teal, violet, cyan, lime) +- Variantes `success` e `info` no componente Badge + +### Alterado + +- Migrados ~60+ componentes de cores hardcoded do Tailwind (`green-500`, `red-600`, `amber-500`, `blue-500`, etc.) para tokens semânticos (`success`, `destructive`, `warning`, `info`) +- Unificados 3 arrays duplicados de cores de categorias (em `category-report-chart.tsx`, `category-history.ts`, `category-history-widget.tsx`) para importação única de `category-colors.ts` +- Month picker migrado de tokens customizados (`--month-picker`) para tokens padrão (`--card`) +- Dark mode normalizado: hues consistentes (~70 warm family) em vez de valores dispersos +- Token `--accent` ajustado para ser visualmente distinto de `--background` +- Token `--card` corrigido para branco limpo (`oklch(100% 0 0)`) + +### Removido + +- Tokens não utilizados: `--dark`, `--dark-foreground`, `--month-picker`, `--month-picker-foreground` + ## [1.3.1] - 2026-02-06 ### Adicionado diff --git a/app/(dashboard)/cartoes/[cartaoId]/fatura/actions.ts b/app/(dashboard)/cartoes/[cartaoId]/fatura/actions.ts index fcd4d71..3ad9cab 100644 --- a/app/(dashboard)/cartoes/[cartaoId]/fatura/actions.ts +++ b/app/(dashboard)/cartoes/[cartaoId]/fatura/actions.ts @@ -1,7 +1,6 @@ "use server"; import { and, eq, sql } from "drizzle-orm"; -import { revalidatePath } from "next/cache"; import { z } from "zod"; import { cartoes, @@ -11,6 +10,7 @@ import { pagadores, } from "@/db/schema"; import { buildInvoicePaymentNote } from "@/lib/accounts/constants"; +import { revalidateForEntity } from "@/lib/actions/helpers"; import { getUser } from "@/lib/auth/server"; import { db } from "@/lib/db"; import { @@ -206,9 +206,7 @@ export async function updateInvoicePaymentStatusAction( } }); - revalidatePath(`/cartoes/${data.cartaoId}/fatura`); - revalidatePath("/cartoes"); - revalidatePath("/contas"); + revalidateForEntity("cartoes"); return { success: true, message: successMessageByStatus[data.status] }; } catch (error) { @@ -275,9 +273,7 @@ export async function updatePaymentDateAction( .where(eq(lancamentos.id, existingPayment.id)); }); - revalidatePath(`/cartoes/${data.cartaoId}/fatura`); - revalidatePath("/cartoes"); - revalidatePath("/contas"); + revalidateForEntity("cartoes"); return { success: true, message: "Data de pagamento atualizada." }; } catch (error) { diff --git a/app/(dashboard)/lancamentos/anticipation-actions.ts b/app/(dashboard)/lancamentos/anticipation-actions.ts index 0927545..d2d5c13 100644 --- a/app/(dashboard)/lancamentos/anticipation-actions.ts +++ b/app/(dashboard)/lancamentos/anticipation-actions.ts @@ -1,7 +1,6 @@ "use server"; import { and, asc, desc, eq, inArray, isNull, or } from "drizzle-orm"; -import { revalidatePath } from "next/cache"; import { z } from "zod"; import { antecipacoesParcelas, @@ -9,7 +8,7 @@ import { lancamentos, pagadores, } from "@/db/schema"; -import { handleActionError } from "@/lib/actions/helpers"; +import { handleActionError, revalidateForEntity } from "@/lib/actions/helpers"; import type { ActionResult } from "@/lib/actions/types"; import { getUser } from "@/lib/auth/server"; import { db } from "@/lib/db"; @@ -263,8 +262,7 @@ export async function createInstallmentAnticipationAction( .where(inArray(lancamentos.id, data.installmentIds)); }); - revalidatePath("/lancamentos"); - revalidatePath("/dashboard"); + revalidateForEntity("lancamentos"); return { success: true, @@ -427,8 +425,7 @@ export async function cancelInstallmentAnticipationAction( .where(eq(antecipacoesParcelas.id, data.anticipationId)); }); - revalidatePath("/lancamentos"); - revalidatePath("/dashboard"); + revalidateForEntity("lancamentos"); return { success: true, diff --git a/app/globals.css b/app/globals.css index 7dd98f8..2595612 100644 --- a/app/globals.css +++ b/app/globals.css @@ -10,7 +10,7 @@ /* Base surfaces - warm cream with subtle orange undertone */ --background: oklch(96.563% 0.00504 67.275); --foreground: oklch(18% 0.02 45); - --card: oklch(100% 0.00011 271.152); + --card: oklch(100% 0 0); --card-foreground: oklch(18% 0.02 45); --popover: oklch(99.5% 0.004 80); --popover-foreground: oklch(18% 0.02 45); @@ -28,9 +28,17 @@ --muted-foreground: oklch(45% 0.015 60); /* Accent - complementary warm tone */ - --accent: oklch(96.563% 0.00504 67.275); + --accent: oklch(94% 0.01 70); --accent-foreground: oklch(22% 0.025 45); + /* Semantic states */ + --success: oklch(55% 0.17 150); + --success-foreground: oklch(98% 0.01 150); + --warning: oklch(75.976% 0.16034 71.493); + --warning-foreground: oklch(20% 0.04 85); + --info: oklch(55% 0.17 250); + --info-foreground: oklch(98% 0.01 250); + /* Destructive - accessible red */ --destructive: oklch(55% 0.22 27); --destructive-foreground: oklch(98% 0.005 30); @@ -40,22 +48,26 @@ --input: oklch(82% 0.012 75); --ring: oklch(69.18% 0.18855 38.353); - /* Charts - harmonious, distinct, accessible */ + /* Charts - 10 harmonious, distinct, accessible colors */ --chart-1: var(--color-emerald-400); --chart-2: var(--color-orange-400); --chart-3: var(--color-indigo-400); --chart-4: var(--color-amber-400); --chart-5: var(--color-pink-400); --chart-6: var(--color-stone-400); + --chart-7: var(--color-teal-400); + --chart-8: var(--color-violet-400); + --chart-9: var(--color-cyan-400); + --chart-10: var(--color-lime-400); /* Sidebar - slight elevation from background */ - --sidebar: oklch(100% 0.00011 271.152); + --sidebar: oklch(100% 0 0); --sidebar-foreground: oklch(20% 0.02 45); --sidebar-primary: oklch(25% 0.025 45); --sidebar-primary-foreground: oklch(98% 0.008 80); --sidebar-accent: oklch(96.563% 0.00504 67.275); --sidebar-accent-foreground: oklch(22% 0.025 45); - --sidebar-border: oklch(58.814% 0.15852 38.26); + --sidebar-border: oklch(69.18% 0.18855 38.353); --sidebar-ring: oklch(69.18% 0.18855 38.353); /* Layout */ @@ -79,46 +91,50 @@ --spacing: 0.25rem; /* Special components */ - --month-picker: oklch(100% 0.00011 271.152); - --month-picker-foreground: oklch(22% 0.015 45); - --dark: oklch(22% 0.015 45); - --dark-foreground: oklch(94% 0.008 80); --welcome-banner: var(--primary); - --welcome-banner-foreground: oklch(98% 0.008 80); + --welcome-banner-foreground: var(--primary-foreground); } .dark { - /* Base surfaces - true dark with minimal saturation */ - --background: oklch(18.674% 0.00002 271.152); - --foreground: oklch(92.189% 0.0186 103.516); - --card: oklch(24.039% 0.00151 16.27); - --card-foreground: oklch(92.189% 0.0186 103.516); - --popover: oklch(24.039% 0.00151 16.27); - --popover-foreground: oklch(92.189% 0.0186 103.516); + /* Base surfaces - warm dark with consistent hue family */ + --background: oklch(18.5% 0.002 70); + --foreground: oklch(92% 0.015 80); + --card: oklch(24% 0.003 70); + --card-foreground: oklch(92% 0.015 80); + --popover: oklch(24% 0.003 70); + --popover-foreground: oklch(92% 0.015 80); /* Primary - vibrant terracotta stands out on dark */ --primary: oklch(69.18% 0.18855 38.353); - --primary-foreground: oklch(20.019% 0.00002 271.152); + --primary-foreground: oklch(20% 0.002 70); /* Secondary - elevated surface */ - --secondary: oklch(22% 0.004 285); - --secondary-foreground: oklch(92.189% 0.0186 103.516); + --secondary: oklch(22% 0.004 70); + --secondary-foreground: oklch(92% 0.015 80); /* Muted - subtle surface variant */ - --muted: oklch(33.674% 0.00531 91.552); - --muted-foreground: oklch(72.285% 0.00436 286.016); + --muted: oklch(33.5% 0.005 70); + --muted-foreground: oklch(72% 0.004 70); /* Accent - subtle highlight */ - --accent: oklch(26.893% 0.00391 84.539); - --accent-foreground: oklch(92.189% 0.0186 103.516); + --accent: oklch(27% 0.004 70); + --accent-foreground: oklch(92% 0.015 80); + + /* Semantic states */ + --success: oklch(65% 0.19 150); + --success-foreground: oklch(15% 0.02 150); + --warning: oklch(75.976% 0.16034 71.493); + --warning-foreground: oklch(15% 0.04 85); + --info: oklch(65% 0.17 250); + --info-foreground: oklch(15% 0.02 250); /* Destructive - accessible red for dark */ --destructive: oklch(62% 0.2 28); --destructive-foreground: oklch(98% 0.005 30); /* Borders and inputs - visible but subtle */ - --border: oklch(37.332% 0.01493 101.928); - --input: oklch(32% 0.005 285); + --border: oklch(37% 0.01 70); + --input: oklch(32% 0.005 70); --ring: oklch(69.18% 0.18855 38.353); /* Charts - bright and distinct on dark */ @@ -128,15 +144,19 @@ --chart-4: var(--color-amber-500); --chart-5: var(--color-pink-500); --chart-6: var(--color-stone-500); + --chart-7: var(--color-teal-500); + --chart-8: var(--color-violet-500); + --chart-9: var(--color-cyan-500); + --chart-10: var(--color-lime-500); /* Sidebar - slight separation from main */ - --sidebar: oklch(24.039% 0.00151 16.27); - --sidebar-foreground: oklch(92.189% 0.0186 103.516); + --sidebar: oklch(24% 0.003 70); + --sidebar-foreground: oklch(92% 0.015 80); --sidebar-primary: oklch(69.18% 0.18855 38.353); - --sidebar-primary-foreground: oklch(12.897% 0.00619 87.19); - --sidebar-accent: oklch(32.242% 0.00447 67.486); - --sidebar-accent-foreground: oklch(92.189% 0.0186 103.516); - --sidebar-border: oklch(26% 0.004 285); + --sidebar-primary-foreground: oklch(13% 0.006 70); + --sidebar-accent: oklch(32% 0.004 70); + --sidebar-accent-foreground: oklch(92% 0.015 80); + --sidebar-border: oklch(26% 0.004 70); --sidebar-ring: oklch(69.18% 0.18855 38.353); /* Layout */ @@ -161,12 +181,8 @@ --spacing: 0.25rem; /* Special components */ - --month-picker: oklch(24.039% 0.00151 16.27); - --month-picker-foreground: oklch(92.189% 0.0186 103.516); - --dark: oklch(92.189% 0.0186 103.516); - --dark-foreground: oklch(18.711% 0.00427 84.566); - --welcome-banner: oklch(24.039% 0.00151 16.27); - --welcome-banner-foreground: oklch(92.189% 0.0186 103.516); + --welcome-banner: var(--card); + --welcome-banner-foreground: var(--card-foreground); } @theme inline { @@ -184,6 +200,12 @@ --color-muted-foreground: var(--muted-foreground); --color-accent: var(--accent); --color-accent-foreground: var(--accent-foreground); + --color-success: var(--success); + --color-success-foreground: var(--success-foreground); + --color-warning: var(--warning); + --color-warning-foreground: var(--warning-foreground); + --color-info: var(--info); + --color-info-foreground: var(--info-foreground); --color-destructive: var(--destructive); --color-destructive-foreground: var(--destructive-foreground); --color-border: var(--border); @@ -195,6 +217,10 @@ --color-chart-4: var(--chart-4); --color-chart-5: var(--chart-5); --color-chart-6: var(--chart-6); + --color-chart-7: var(--chart-7); + --color-chart-8: var(--chart-8); + --color-chart-9: var(--chart-9); + --color-chart-10: var(--chart-10); --color-sidebar: var(--sidebar); --color-sidebar-foreground: var(--sidebar-foreground); --color-sidebar-primary: var(--sidebar-primary); @@ -217,10 +243,6 @@ --shadow-2xl: var(--shadow-2xl); --tracking-normal: var(--tracking-normal); --spacing: var(--spacing); - --color-month-picker: var(--month-picker); - --color-month-picker-foreground: var(--month-picker-foreground); - --color-dark: var(--dark); - --color-dark-foreground: var(--dark-foreground); --color-welcome-banner: var(--welcome-banner); --color-welcome-banner-foreground: var(--welcome-banner-foreground); } diff --git a/components/ajustes/api-tokens-form.tsx b/components/ajustes/api-tokens-form.tsx index 01213c1..65b7a97 100644 --- a/components/ajustes/api-tokens-form.tsx +++ b/components/ajustes/api-tokens-form.tsx @@ -226,14 +226,14 @@ export function ApiTokensForm({ tokens }: ApiTokensFormProps) { onClick={handleCopy} > {copied ? ( - + ) : ( )} -
+

Importante:

  • Guarde este token em local seguro
  • diff --git a/components/ajustes/companion-tab.tsx b/components/ajustes/companion-tab.tsx index 308f300..f697c34 100644 --- a/components/ajustes/companion-tab.tsx +++ b/components/ajustes/companion-tab.tsx @@ -75,7 +75,7 @@ export function CompanionTab({ tokens }: CompanionTabProps) {

    OpenSheets Companion

    - + Android diff --git a/components/ajustes/update-email-form.tsx b/components/ajustes/update-email-form.tsx index c5d6654..e899de4 100644 --- a/components/ajustes/update-email-form.tsx +++ b/components/ajustes/update-email-form.tsx @@ -149,13 +149,13 @@ export function UpdateEmailForm({ aria-invalid={!isEmailDifferent} className={ !isEmailDifferent - ? "border-red-500 focus-visible:ring-red-500" + ? "border-destructive focus-visible:ring-destructive" : "" } /> {!isEmailDifferent && newEmail && (

    O novo e-mail deve ser @@ -188,9 +188,9 @@ export function UpdateEmailForm({ aria-invalid={emailsMatch === false} className={ emailsMatch === false - ? "border-red-500 focus-visible:ring-red-500 pr-10" + ? "border-destructive focus-visible:ring-destructive pr-10" : emailsMatch === true - ? "border-green-500 focus-visible:ring-green-500 pr-10" + ? "border-success focus-visible:ring-success pr-10" : "" } /> @@ -199,12 +199,12 @@ export function UpdateEmailForm({

    {emailsMatch ? ( ) : ( )} @@ -215,7 +215,7 @@ export function UpdateEmailForm({ {emailsMatch === false && (

    Os e-mails coincidem diff --git a/components/ajustes/update-password-form.tsx b/components/ajustes/update-password-form.tsx index 145c063..840ae41 100644 --- a/components/ajustes/update-password-form.tsx +++ b/components/ajustes/update-password-form.tsx @@ -55,9 +55,7 @@ function PasswordRequirement({ met, label }: { met: boolean; label: string }) {

    {met ? ( @@ -133,14 +131,14 @@ export function UpdatePasswordForm({ authProvider }: UpdatePasswordFormProps) { // Se o usuário usa Google OAuth, mostrar aviso if (isGoogleAuth) { return ( -
    +
    - +
    -

    +

    Alteração de senha não disponível

    -

    +

    Você fez login usando sua conta do Google. A senha é gerenciada diretamente pelo Google e não pode ser alterada aqui. Para modificar sua senha, acesse as configurações de segurança da sua @@ -285,9 +283,9 @@ export function UpdatePasswordForm({ authProvider }: UpdatePasswordFormProps) { aria-invalid={passwordsMatch === false} className={ passwordsMatch === false - ? "border-red-500 focus-visible:ring-red-500" + ? "border-destructive focus-visible:ring-destructive" : passwordsMatch === true - ? "border-green-500 focus-visible:ring-green-500" + ? "border-success focus-visible:ring-success" : "" } /> @@ -312,12 +310,12 @@ export function UpdatePasswordForm({ authProvider }: UpdatePasswordFormProps) {

    {passwordsMatch ? ( ) : ( )} @@ -328,7 +326,7 @@ export function UpdatePasswordForm({ authProvider }: UpdatePasswordFormProps) { {passwordsMatch === false && (

    As senhas coincidem diff --git a/components/anotacoes/note-card.tsx b/components/anotacoes/note-card.tsx index de632fe..e79dd0e 100644 --- a/components/anotacoes/note-card.tsx +++ b/components/anotacoes/note-card.tsx @@ -104,7 +104,7 @@ export function NoteCard({

    diff --git a/components/anotacoes/note-details-dialog.tsx b/components/anotacoes/note-details-dialog.tsx index 51d49e0..b88db5a 100644 --- a/components/anotacoes/note-details-dialog.tsx +++ b/components/anotacoes/note-details-dialog.tsx @@ -79,7 +79,7 @@ export function NoteDetailsDialog({
    diff --git a/components/anotacoes/note-dialog.tsx b/components/anotacoes/note-dialog.tsx index 1234cb9..9a17981 100644 --- a/components/anotacoes/note-dialog.tsx +++ b/components/anotacoes/note-dialog.tsx @@ -383,7 +383,7 @@ export function NoteDialog({ className="flex items-center gap-3 px-3 py-2 flex-row mt-1" > handleToggleTask(task.id)} disabled={isPending} diff --git a/components/auth/auth-error-alert.tsx b/components/auth/auth-error-alert.tsx index 7daa9d0..c4b7062 100644 --- a/components/auth/auth-error-alert.tsx +++ b/components/auth/auth-error-alert.tsx @@ -9,7 +9,7 @@ export function AuthErrorAlert({ error }: AuthErrorAlertProps) { if (!error) return null; return ( - + {error} diff --git a/components/auth/signup-form.tsx b/components/auth/signup-form.tsx index 8569ef5..aeb8f35 100644 --- a/components/auth/signup-form.tsx +++ b/components/auth/signup-form.tsx @@ -61,9 +61,7 @@ function PasswordRequirement({ met, label }: { met: boolean; label: string }) {
    {met ? ( diff --git a/components/calendario/calendar-legend.tsx b/components/calendario/calendar-legend.tsx index c88701e..9b31829 100644 --- a/components/calendario/calendar-legend.tsx +++ b/components/calendario/calendar-legend.tsx @@ -12,7 +12,7 @@ const LEGEND_ITEMS: Array<{ { type: "lancamento", label: "Lançamentos" }, { type: "boleto", label: "Boleto com vencimento" }, { type: "cartao", label: "Vencimento de cartão" }, - { label: "Pagamento fatura", dotColor: "bg-green-600" }, + { label: "Pagamento fatura", dotColor: "bg-success" }, ]; export function CalendarLegend() { diff --git a/components/calendario/day-cell.tsx b/components/calendario/day-cell.tsx index c51d042..52a55d3 100644 --- a/components/calendario/day-cell.tsx +++ b/components/calendario/day-cell.tsx @@ -18,13 +18,13 @@ export const EVENT_TYPE_STYLES: Record< > = { lancamento: { wrapper: - "bg-orange-100 text-orange-600 dark:bg-orange-900/10 dark:text-orange-50 border-l-4 border-orange-500", - dot: "bg-orange-600", + "bg-warning/10 text-warning dark:bg-warning/5 dark:text-warning border-l-4 border-warning", + dot: "bg-warning", }, boleto: { wrapper: - "bg-blue-100 text-blue-600 dark:bg-blue-900/10 dark:text-blue-50 border-l-4 border-blue-500", - dot: "bg-blue-600", + "bg-info/10 text-info dark:bg-info/5 dark:text-info border-l-4 border-info", + dot: "bg-info", }, cartao: { wrapper: @@ -87,8 +87,8 @@ const getEventStyle = (event: CalendarEvent) => { if (isPagamentoFatura(event)) { return { wrapper: - "bg-green-100 text-green-600 dark:bg-green-900/10 dark:text-green-50 border-l-4 border-green-500", - dot: "bg-green-600", + "bg-success/10 text-success dark:bg-success/5 dark:text-success border-l-4 border-success", + dot: "bg-success", }; } return eventStyles[event.type]; diff --git a/components/calendario/event-modal.tsx b/components/calendario/event-modal.tsx index 6d753fd..f913035 100644 --- a/components/calendario/event-modal.tsx +++ b/components/calendario/event-modal.tsx @@ -35,7 +35,7 @@ const EventCard = ({ isPagamentoFatura?: boolean; }) => { const style = isPagamentoFatura - ? { dot: "bg-green-600" } + ? { dot: "bg-success" } : EVENT_TYPE_STYLES[type]; return ( @@ -61,7 +61,7 @@ const renderLancamento = (
    {event.lancamento.name} @@ -76,9 +76,7 @@ const renderLancamento = ( {label} diff --git a/components/categorias/category-detail-header.tsx b/components/categorias/category-detail-header.tsx index 0b199d4..5fce78d 100644 --- a/components/categorias/category-detail-header.tsx +++ b/components/categorias/category-detail-header.tsx @@ -1,4 +1,4 @@ -import { RiArrowDownLine, RiArrowUpLine } from "@remixicon/react"; +import { RiArrowDownSFill, RiArrowUpSFill } from "@remixicon/react"; import type { CategoryType } from "@/lib/categorias/constants"; import { currencyFormatter } from "@/lib/lancamentos/formatting-helpers"; import { cn } from "@/lib/utils/ui"; @@ -40,22 +40,22 @@ export function CategoryDetailHeader({ const variationColor = category.type === "receita" ? isIncrease - ? "text-emerald-600" + ? "text-success" : isDecrease - ? "text-rose-600" + ? "text-destructive" : "text-muted-foreground" : isIncrease - ? "text-rose-600" + ? "text-destructive" : isDecrease - ? "text-emerald-600" + ? "text-success" : "text-muted-foreground"; const variationIcon = isIncrease || isDecrease ? ( isIncrease ? ( - + ) : ( - + ) ) : null; diff --git a/components/categorias/category-select-items.tsx b/components/categorias/category-select-items.tsx index 2b72c1b..affc164 100644 --- a/components/categorias/category-select-items.tsx +++ b/components/categorias/category-select-items.tsx @@ -7,13 +7,7 @@ export function TypeSelectContent({ label }: { label: string }) { return ( - + {label} ); diff --git a/components/contas/account-select-items.tsx b/components/contas/account-select-items.tsx index fb4f659..2237493 100644 --- a/components/contas/account-select-items.tsx +++ b/components/contas/account-select-items.tsx @@ -8,11 +8,7 @@ export function StatusSelectContent({ label }: { label: string }) { return ( {label} diff --git a/components/contas/account-statement-card.tsx b/components/contas/account-statement-card.tsx index cf0bea2..e270024 100644 --- a/components/contas/account-statement-card.tsx +++ b/components/contas/account-statement-card.tsx @@ -113,7 +113,7 @@ export function AccountStatementCard({ + {formatCurrency(totalIncomes)} } @@ -137,7 +137,7 @@ export function AccountStatementCard({ className={cn( "font-semibold text-xl", totalIncomes - totalExpenses >= 0 - ? "text-emerald-600" + ? "text-success" : "text-destructive", )} /> diff --git a/components/dashboard/boletos-widget.tsx b/components/dashboard/boletos-widget.tsx index e70c1a6..0b205df 100644 --- a/components/dashboard/boletos-widget.tsx +++ b/components/dashboard/boletos-widget.tsx @@ -182,8 +182,7 @@ export function BoletosWidget({ boletos }: BoletosWidgetProps) { {statusLabel} @@ -203,7 +202,7 @@ export function BoletosWidget({ boletos }: BoletosWidgetProps) { onClick={() => handleOpenModal(boleto.id)} > {boleto.isSettled ? ( - + Pago ) : ( @@ -248,7 +247,7 @@ export function BoletosWidget({ boletos }: BoletosWidgetProps) { > {modalState === "success" ? (
    -
    +
    diff --git a/components/dashboard/category-history-widget.tsx b/components/dashboard/category-history-widget.tsx index fe3af94..ac91f6a 100644 --- a/components/dashboard/category-history-widget.tsx +++ b/components/dashboard/category-history-widget.tsx @@ -28,6 +28,7 @@ import { } from "@/components/ui/popover"; import { WidgetEmptyState } from "@/components/widget-empty-state"; import type { CategoryHistoryData } from "@/lib/dashboard/categories/category-history"; +import { CATEGORY_COLORS } from "@/lib/utils/category-colors"; import { getIconComponent } from "@/lib/utils/icons"; type CategoryHistoryWidgetProps = { @@ -36,14 +37,7 @@ type CategoryHistoryWidgetProps = { const STORAGE_KEY_SELECTED = "dashboard-category-history-selected"; -// Vibrant colors for categories -const CHART_COLORS = [ - "#ef4444", // red-500 - "#3b82f6", // blue-500 - "#10b981", // emerald-500 - "#f59e0b", // amber-500 - "#8b5cf6", // violet-500 -]; +const CHART_COLORS = CATEGORY_COLORS; export function CategoryHistoryWidget({ data }: CategoryHistoryWidgetProps) { const [selectedCategories, setSelectedCategories] = useState([]); @@ -260,7 +254,7 @@ export function CategoryHistoryWidget({ data }: CategoryHistoryWidgetProps) { )} {selectedCategories.length < 5 && availableCategories.length > 0 && ( - + diff --git a/components/month-picker/month-navigation.tsx b/components/month-picker/month-navigation.tsx index 792621d..0fa3966 100644 --- a/components/month-picker/month-navigation.tsx +++ b/components/month-picker/month-navigation.tsx @@ -79,7 +79,7 @@ export default function MonthNavigation() { }; return ( - +
    {exceeded ? ( -
    +
    Excedeu em
    ) : ( -
    +
    Restam {" "} disponíveis.
    @@ -98,6 +103,14 @@ export function BudgetCard({ > editar + {budget.category && ( + + detalhes + + )}