refactor(sidebar): reorganizar navegação e aplicar formatação Biome

- Simplifica estrutura da sidebar combinando seções "Visão Geral" e "Gestão Financeira"
- Renomeia itens de relatórios para maior clareza ("Tendências", "Uso de Cartões")
- Aplica correções de formatação do Biome (ordenação de imports, quebras de linha)
- Remove código comentado não utilizado
- Adiciona migração 0014 do Drizzle

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Felipe Coutinho
2026-01-29 13:16:39 +00:00
parent 120da3659b
commit df1d149e4a
43 changed files with 4446 additions and 2515 deletions

View File

@@ -5,7 +5,7 @@ import { and, eq, isNull, ne } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { headers } from "next/headers";
import { z } from "zod";
import { tokensApi, pagadores } from "@/db/schema";
import { pagadores, tokensApi } from "@/db/schema";
import { auth } from "@/lib/auth/config";
import { db, schema } from "@/lib/db";
import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants";

View File

@@ -11,10 +11,10 @@ import {
cartoes,
categorias,
contas,
insightsSalvos,
lancamentos,
orcamentos,
pagadores,
insightsSalvos,
} from "@/db/schema";
import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/accounts/constants";
import { getUser } from "@/lib/auth/server";
@@ -752,7 +752,10 @@ export async function saveInsightsAction(
modelId,
data: JSON.stringify(data),
})
.returning({ id: insightsSalvos.id, createdAt: insightsSalvos.createdAt });
.returning({
id: insightsSalvos.id,
createdAt: insightsSalvos.createdAt,
});
const insertedRecord = result[0];
if (!insertedRecord) {

View File

@@ -4,8 +4,8 @@ import { and, asc, desc, eq, inArray, isNull, or } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { z } from "zod";
import {
categorias,
antecipacoesParcelas,
categorias,
lancamentos,
pagadores,
} from "@/db/schema";
@@ -320,10 +320,7 @@ export async function getInstallmentAnticipationsAction(
eq(antecipacoesParcelas.lancamentoId, lancamentos.id),
)
.leftJoin(pagadores, eq(antecipacoesParcelas.pagadorId, pagadores.id))
.leftJoin(
categorias,
eq(antecipacoesParcelas.categoriaId, categorias.id),
)
.leftJoin(categorias, eq(antecipacoesParcelas.categoriaId, categorias.id))
.where(
and(
eq(antecipacoesParcelas.seriesId, validatedSeriesId),

View File

@@ -2,10 +2,10 @@ import { and, desc, eq, type SQL } from "drizzle-orm";
import {
cartoes,
categorias,
compartilhamentosPagador,
contas,
lancamentos,
pagadores,
compartilhamentosPagador,
user as usersTable,
} from "@/db/schema";
import { db } from "@/lib/db";
@@ -30,7 +30,10 @@ export async function fetchPagadorShares(
userEmail: usersTable.email,
})
.from(compartilhamentosPagador)
.innerJoin(usersTable, eq(compartilhamentosPagador.sharedWithUserId, usersTable.id))
.innerJoin(
usersTable,
eq(compartilhamentosPagador.sharedWithUserId, usersTable.id),
)
.where(eq(compartilhamentosPagador.pagadorId, pagadorId));
return shareRows.map((share) => ({

View File

@@ -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 { pagadores, compartilhamentosPagador, user } from "@/db/schema";
import { compartilhamentosPagador, pagadores, user } from "@/db/schema";
import { handleActionError, revalidateForEntity } from "@/lib/actions/helpers";
import type { ActionResult } from "@/lib/actions/types";
import { getUser } from "@/lib/auth/server";
@@ -287,7 +287,9 @@ export async function deletePagadorShareAction(
};
}
await db.delete(compartilhamentosPagador).where(eq(compartilhamentosPagador.id, data.shareId));
await db
.delete(compartilhamentosPagador)
.where(eq(compartilhamentosPagador.id, data.shareId));
revalidate();
revalidatePath(`/pagadores/${existing.pagadorId}`);

View File

@@ -1,5 +1,3 @@
import { and, desc, eq, gte } from "drizzle-orm";
import type {
InboxItem,
@@ -9,8 +7,8 @@ import {
cartoes,
categorias,
contas,
preLancamentos,
lancamentos,
preLancamentos,
} from "@/db/schema";
import { db } from "@/lib/db";
import {
@@ -26,7 +24,9 @@ export async function fetchInboxItems(
const items = await db
.select()
.from(preLancamentos)
.where(and(eq(preLancamentos.userId, userId), eq(preLancamentos.status, status)))
.where(
and(eq(preLancamentos.userId, userId), eq(preLancamentos.status, status)),
)
.orderBy(desc(preLancamentos.createdAt));
return items;
@@ -39,7 +39,9 @@ export async function fetchInboxItemById(
const [item] = await db
.select()
.from(preLancamentos)
.where(and(eq(preLancamentos.id, itemId), eq(preLancamentos.userId, userId)))
.where(
and(eq(preLancamentos.id, itemId), eq(preLancamentos.userId, userId)),
)
.limit(1);
return item ?? null;
@@ -91,7 +93,10 @@ export async function fetchPendingInboxCount(userId: string): Promise<number> {
.select({ id: preLancamentos.id })
.from(preLancamentos)
.where(
and(eq(preLancamentos.userId, userId), eq(preLancamentos.status, "pending")),
and(
eq(preLancamentos.userId, userId),
eq(preLancamentos.status, "pending"),
),
);
return items.length;

View File

@@ -2,7 +2,7 @@ import { RiBankCard2Line } from "@remixicon/react";
import PageDescription from "@/components/page-description";
export const metadata = {
title: "Relatório de Cartões | Opensheets",
title: "Uso de Cartões | Opensheets",
};
export default function RootLayout({
@@ -14,7 +14,7 @@ export default function RootLayout({
<section className="space-y-6 px-6">
<PageDescription
icon={<RiBankCard2Line />}
title="Relatório de Cartões"
title="Uso de Cartões"
subtitle="Análise detalhada do uso dos seus cartões de crédito."
/>
{children}

View File

@@ -2,7 +2,7 @@ import { RiFileChartLine } from "@remixicon/react";
import PageDescription from "@/components/page-description";
export const metadata = {
title: "Relatórios | Opensheets",
title: "Tendências | Opensheets",
};
export default function RootLayout({
@@ -14,7 +14,7 @@ export default function RootLayout({
<section className="space-y-6 px-6">
<PageDescription
icon={<RiFileChartLine />}
title="Relatórios de Categorias"
title="Tendências"
subtitle="Acompanhe a evolução dos seus gastos e receitas por categoria ao longo do tempo."
/>
{children}

View File

@@ -1,5 +1,3 @@
import { and, eq, isNull } from "drizzle-orm";
import { NextResponse } from "next/server";
import { tokensApi } from "@/db/schema";

View File

@@ -1,5 +1,3 @@
import { headers } from "next/headers";
import { NextResponse } from "next/server";
import { z } from "zod";

View File

@@ -1,5 +1,3 @@
import { and, eq } from "drizzle-orm";
import { headers } from "next/headers";
import { NextResponse } from "next/server";

View File

@@ -1,5 +1,3 @@
import { desc, eq } from "drizzle-orm";
import { headers } from "next/headers";
import { NextResponse } from "next/server";

View File

@@ -1,5 +1,3 @@
import { and, eq, isNull } from "drizzle-orm";
import { NextResponse } from "next/server";
import { tokensApi } from "@/db/schema";

View File

@@ -1,9 +1,7 @@
import { and, eq, isNull } from "drizzle-orm";
import { NextResponse } from "next/server";
import { z } from "zod";
import { tokensApi, preLancamentos } from "@/db/schema";
import { preLancamentos, tokensApi } from "@/db/schema";
import { extractBearerToken, hashToken } from "@/lib/auth/api-token";
import { db } from "@/lib/db";
import { inboxBatchSchema } from "@/lib/schemas/inbox";
@@ -103,7 +101,6 @@ export async function POST(request: Request) {
notificationTimestamp: item.notificationTimestamp,
parsedName: item.parsedName,
parsedAmount: item.parsedAmount?.toString(),
parsedTransactionType: item.parsedTransactionType,
status: "pending",
})
.returning({ id: preLancamentos.id });

View File

@@ -1,9 +1,7 @@
import { and, eq, isNull } from "drizzle-orm";
import { NextResponse } from "next/server";
import { z } from "zod";
import { tokensApi, preLancamentos } from "@/db/schema";
import { preLancamentos, tokensApi } from "@/db/schema";
import { extractBearerToken, hashToken } from "@/lib/auth/api-token";
import { db } from "@/lib/db";
import { inboxItemSchema } from "@/lib/schemas/inbox";
@@ -92,7 +90,6 @@ export async function POST(request: Request) {
notificationTimestamp: data.notificationTimestamp,
parsedName: data.parsedName,
parsedAmount: data.parsedAmount?.toString(),
parsedTransactionType: data.parsedTransactionType,
status: "pending",
})
.returning({ id: preLancamentos.id });

View File

@@ -1,7 +1,7 @@
"use client";
import { RiCalendarCheckLine, RiLoader4Line } from "@remixicon/react";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { toast } from "sonner";
import { getInstallmentAnticipationsAction } from "@/app/(dashboard)/lancamentos/anticipation-actions";
import {
@@ -52,14 +52,8 @@ export function AnticipationHistoryDialog({
onOpenChange,
);
// Buscar antecipações ao abrir o dialog
useEffect(() => {
if (dialogOpen) {
loadAnticipations();
}
}, [dialogOpen, loadAnticipations]);
const loadAnticipations = async () => {
// Define loadAnticipations before it's used in useEffect
const loadAnticipations = useCallback(async () => {
setIsLoading(true);
try {
@@ -80,7 +74,14 @@ export function AnticipationHistoryDialog({
} finally {
setIsLoading(false);
}
};
}, [seriesId]);
// Buscar antecipações ao abrir o dialog
useEffect(() => {
if (dialogOpen) {
loadAnticipations();
}
}, [dialogOpen, loadAnticipations]);
const handleCanceled = () => {
// Recarregar lista após cancelamento

View File

@@ -24,7 +24,6 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { cn } from "@/lib/utils/ui";
import type { InboxItem } from "./types";
interface InboxCardProps {
@@ -41,7 +40,6 @@ export function InboxCard({
onViewDetails,
}: InboxCardProps) {
const amount = item.parsedAmount ? parseFloat(item.parsedAmount) : null;
const isReceita = item.parsedTransactionType === "Receita";
// O timestamp vem do app Android em horário local mas salvo como UTC
// Precisamos interpretar o valor UTC como se fosse horário de Brasília
@@ -78,16 +76,7 @@ export function InboxCard({
</span>
</CardTitle>
{amount !== null && (
<MoneyValues
amount={isReceita ? amount : -amount}
showPositiveSign={isReceita}
className={cn(
"text-sm",
isReceita
? "text-green-600 dark:text-green-400"
: "text-foreground",
)}
/>
<MoneyValues amount={amount} className="text-sm" />
)}
</div>

View File

@@ -3,7 +3,6 @@
import { format } from "date-fns";
import { ptBR } from "date-fns/locale";
import MoneyValues from "@/components/money-values";
import { TypeBadge } from "@/components/type-badge";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
@@ -15,7 +14,6 @@ import {
DialogTitle,
} from "@/components/ui/dialog";
import { Separator } from "@/components/ui/separator";
import { cn } from "@/lib/utils/ui";
import type { InboxItem } from "./types";
interface InboxDetailsDialogProps {
@@ -32,7 +30,6 @@ export function InboxDetailsDialog({
if (!item) return null;
const amount = item.parsedAmount ? parseFloat(item.parsedAmount) : null;
const isReceita = item.parsedTransactionType === "Receita";
return (
<Dialog open={open} onOpenChange={onOpenChange}>
@@ -86,30 +83,11 @@ export function InboxDetailsDialog({
<div className="flex justify-between items-center">
<span className="text-muted-foreground">Valor</span>
{amount !== null ? (
<MoneyValues
amount={isReceita ? amount : -amount}
showPositiveSign={isReceita}
className={cn(
"text-sm",
isReceita
? "text-green-600 dark:text-green-400"
: "text-foreground",
)}
/>
<MoneyValues amount={amount} className="text-sm" />
) : (
<span className="text-muted-foreground">Não extraído</span>
)}
</div>
<div className="flex justify-between items-center">
<span className="text-muted-foreground">Tipo</span>
{item.parsedTransactionType ? (
<TypeBadge type={item.parsedTransactionType} />
) : (
<span className="text-muted-foreground">
Não identificado
</span>
)}
</div>
</div>
</div>

View File

@@ -139,9 +139,6 @@ export function InboxPage({
? String(Math.abs(Number(itemToProcess.parsedAmount)))
: null;
const defaultTransactionType =
itemToProcess?.parsedTransactionType === "Receita" ? "Receita" : "Despesa";
return (
<>
<div className="flex w-full flex-col gap-6">
@@ -182,7 +179,6 @@ export function InboxPage({
defaultPurchaseDate={defaultPurchaseDate}
defaultName={defaultName}
defaultAmount={defaultAmount}
defaultTransactionType={defaultTransactionType}
forceShowTransactionType
onSuccess={handleLancamentoSuccess}
/>

View File

@@ -1,5 +1,3 @@
import type { SelectOption as LancamentoSelectOption } from "@/components/lancamentos/types";
export interface InboxItem {
@@ -11,7 +9,6 @@ export interface InboxItem {
notificationTimestamp: Date;
parsedName: string | null;
parsedAmount: string | null;
parsedTransactionType: string | null;
status: string;
lancamentoId: string | null;
processedAt: Date | null;
@@ -25,7 +22,6 @@ export interface ProcessInboxInput {
name: string;
amount: number;
purchaseDate: string;
transactionType: "Despesa" | "Receita";
condition: string;
paymentMethod: string;
categoriaId: string;

View File

@@ -85,18 +85,13 @@ export function createSidebarNavData(
return {
navMain: [
{
title: "Visão Geral",
title: "Gestão Financeira",
items: [
{
title: "Dashboard",
url: "/dashboard",
icon: RiDashboardLine,
},
],
},
{
title: "Gestão Financeira",
items: [
{
title: "Lançamentos",
url: "/lancamentos",
@@ -164,11 +159,6 @@ export function createSidebarNavData(
url: "/categorias",
icon: RiPriceTag3Line,
},
],
},
{
title: "Análise e Anotações",
items: [
{
title: "Anotações",
url: "/anotacoes",
@@ -182,23 +172,23 @@ export function createSidebarNavData(
},
],
},
],
},
{
title: "Análise",
items: [
{
title: "Insights",
url: "/insights",
icon: RiSparklingLine,
},
],
},
{
title: "Relatórios",
items: [
{
title: "Categorias",
title: "Tendências",
url: "/relatorios/categorias",
icon: RiFileChartLine,
},
{
title: "Cartões",
title: "Uso de Cartões",
url: "/relatorios/cartoes",
icon: RiBankCard2Line,
},
@@ -206,11 +196,6 @@ export function createSidebarNavData(
},
],
navSecondary: [
// {
// title: "Changelog",
// url: "/changelog",
// icon: RiGitCommitLine,
// },
{
title: "Ajustes",
url: "/ajustes",

View File

@@ -113,9 +113,11 @@ export function NavMain({ sections }: { sections: NavSection[] }) {
return (
<>
{sections.map((section) => (
{sections.map((section, index) => (
<SidebarGroup key={section.title}>
<SidebarGroupLabel>{section.title}</SidebarGroupLabel>
<SidebarGroupLabel className="text-xs text-muted-foreground/60">
{section.title}
</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{section.items.map((item) => {

View File

@@ -451,7 +451,6 @@ export const preLancamentos = pgTable(
// Dados parseados (editáveis pelo usuário antes de processar)
parsedName: text("parsed_name"), // Nome do estabelecimento
parsedAmount: numeric("parsed_amount", { precision: 12, scale: 2 }),
parsedTransactionType: text("parsed_transaction_type"), // Despesa, Receita
// Status de processamento
status: text("status").notNull().default("pending"), // pending, processed, discarded
@@ -527,7 +526,9 @@ export const antecipacoesParcelas = pgTable(
.defaultNow(),
},
(table) => ({
seriesIdIdx: index("antecipacoes_parcelas_series_id_idx").on(table.seriesId),
seriesIdIdx: index("antecipacoes_parcelas_series_id_idx").on(
table.seriesId,
),
userIdIdx: index("antecipacoes_parcelas_user_id_idx").on(table.userId),
}),
);

View File

@@ -0,0 +1 @@
ALTER TABLE "pre_lancamentos" DROP COLUMN "parsed_transaction_type";

View File

@@ -93,12 +93,8 @@
"name": "account_userId_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -172,12 +168,8 @@
"name": "anotacoes_user_id_user_id_fk",
"tableFrom": "anotacoes",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -317,12 +309,8 @@
"name": "antecipacoes_parcelas_lancamento_id_lancamentos_id_fk",
"tableFrom": "antecipacoes_parcelas",
"tableTo": "lancamentos",
"columnsFrom": [
"lancamento_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["lancamento_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -330,12 +318,8 @@
"name": "antecipacoes_parcelas_pagador_id_pagadores_id_fk",
"tableFrom": "antecipacoes_parcelas",
"tableTo": "pagadores",
"columnsFrom": [
"pagador_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["pagador_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -343,12 +327,8 @@
"name": "antecipacoes_parcelas_categoria_id_categorias_id_fk",
"tableFrom": "antecipacoes_parcelas",
"tableTo": "categorias",
"columnsFrom": [
"categoria_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["categoria_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -356,12 +336,8 @@
"name": "antecipacoes_parcelas_user_id_user_id_fk",
"tableFrom": "antecipacoes_parcelas",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -479,12 +455,8 @@
"name": "cartoes_user_id_user_id_fk",
"tableFrom": "cartoes",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -492,12 +464,8 @@
"name": "cartoes_conta_id_contas_id_fk",
"tableFrom": "cartoes",
"tableTo": "contas",
"columnsFrom": [
"conta_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["conta_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "cascade"
}
@@ -579,12 +547,8 @@
"name": "categorias_user_id_user_id_fk",
"tableFrom": "categorias",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -667,12 +631,8 @@
"name": "compartilhamentos_pagador_pagador_id_pagadores_id_fk",
"tableFrom": "compartilhamentos_pagador",
"tableTo": "pagadores",
"columnsFrom": [
"pagador_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["pagador_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -680,12 +640,8 @@
"name": "compartilhamentos_pagador_shared_with_user_id_user_id_fk",
"tableFrom": "compartilhamentos_pagador",
"tableTo": "user",
"columnsFrom": [
"shared_with_user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["shared_with_user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -693,12 +649,8 @@
"name": "compartilhamentos_pagador_created_by_user_id_user_id_fk",
"tableFrom": "compartilhamentos_pagador",
"tableTo": "user",
"columnsFrom": [
"created_by_user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["created_by_user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -813,12 +765,8 @@
"name": "contas_user_id_user_id_fk",
"tableFrom": "contas",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -921,12 +869,8 @@
"name": "faturas_user_id_user_id_fk",
"tableFrom": "faturas",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -934,12 +878,8 @@
"name": "faturas_cartao_id_cartoes_id_fk",
"tableFrom": "faturas",
"tableTo": "cartoes",
"columnsFrom": [
"cartao_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["cartao_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "cascade"
}
@@ -1028,12 +968,8 @@
"name": "insights_salvos_user_id_user_id_fk",
"tableFrom": "insights_salvos",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1331,12 +1267,8 @@
"name": "lancamentos_antecipacao_id_antecipacoes_parcelas_id_fk",
"tableFrom": "lancamentos",
"tableTo": "antecipacoes_parcelas",
"columnsFrom": [
"antecipacao_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["antecipacao_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -1344,12 +1276,8 @@
"name": "lancamentos_user_id_user_id_fk",
"tableFrom": "lancamentos",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1357,12 +1285,8 @@
"name": "lancamentos_cartao_id_cartoes_id_fk",
"tableFrom": "lancamentos",
"tableTo": "cartoes",
"columnsFrom": [
"cartao_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["cartao_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "cascade"
},
@@ -1370,12 +1294,8 @@
"name": "lancamentos_conta_id_contas_id_fk",
"tableFrom": "lancamentos",
"tableTo": "contas",
"columnsFrom": [
"conta_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["conta_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "cascade"
},
@@ -1383,12 +1303,8 @@
"name": "lancamentos_categoria_id_categorias_id_fk",
"tableFrom": "lancamentos",
"tableTo": "categorias",
"columnsFrom": [
"categoria_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["categoria_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "cascade"
},
@@ -1396,12 +1312,8 @@
"name": "lancamentos_pagador_id_pagadores_id_fk",
"tableFrom": "lancamentos",
"tableTo": "pagadores",
"columnsFrom": [
"pagador_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["pagador_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "cascade"
}
@@ -1483,12 +1395,8 @@
"name": "orcamentos_user_id_user_id_fk",
"tableFrom": "orcamentos",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1496,12 +1404,8 @@
"name": "orcamentos_categoria_id_categorias_id_fk",
"tableFrom": "orcamentos",
"tableTo": "categorias",
"columnsFrom": [
"categoria_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["categoria_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "cascade"
}
@@ -1657,12 +1561,8 @@
"name": "pagadores_user_id_user_id_fk",
"tableFrom": "pagadores",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1827,12 +1727,8 @@
"name": "pre_lancamentos_user_id_user_id_fk",
"tableFrom": "pre_lancamentos",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1840,12 +1736,8 @@
"name": "pre_lancamentos_lancamento_id_lancamentos_id_fk",
"tableFrom": "pre_lancamentos",
"tableTo": "lancamentos",
"columnsFrom": [
"lancamento_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["lancamento_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1907,12 +1799,8 @@
"name": "preferencias_usuario_user_id_user_id_fk",
"tableFrom": "preferencias_usuario",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1922,9 +1810,7 @@
"preferencias_usuario_user_id_unique": {
"name": "preferencias_usuario_user_id_unique",
"nullsNotDistinct": false,
"columns": [
"user_id"
]
"columns": ["user_id"]
}
},
"policies": {},
@@ -1990,12 +1876,8 @@
"name": "session_userId_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2005,9 +1887,7 @@
"session_token_unique": {
"name": "session_token_unique",
"nullsNotDistinct": false,
"columns": [
"token"
]
"columns": ["token"]
}
},
"policies": {},
@@ -2118,12 +1998,8 @@
"name": "tokens_api_user_id_user_id_fk",
"tableFrom": "tokens_api",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2188,9 +2064,7 @@
"user_email_unique": {
"name": "user_email_unique",
"nullsNotDistinct": false,
"columns": [
"email"
]
"columns": ["email"]
}
},
"policies": {},

File diff suppressed because it is too large Load Diff

View File

@@ -99,6 +99,13 @@
"when": 1769523352777,
"tag": "0013_fancy_rick_jones",
"breakpoints": true
},
{
"idx": 14,
"version": "7",
"when": 1769619226903,
"tag": "0014_yielding_jack_flag",
"breakpoints": true
}
]
}

View File

@@ -1,5 +1,3 @@
import crypto from "node:crypto";
const JWT_SECRET =

View File

@@ -1,5 +1,3 @@
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import type { GoogleProfile } from "better-auth/social-providers";

View File

@@ -1,5 +1,3 @@
import { headers } from "next/headers";
import { redirect } from "next/navigation";
import { auth } from "@/lib/auth/config";

View File

@@ -1,5 +1,3 @@
import { eq } from "drizzle-orm";
import { categorias } from "@/db/schema";
import type { CategoryType } from "@/lib/categorias/constants";

View File

@@ -1,5 +1,3 @@
import { calculatePercentageChange } from "@/lib/utils/math";
import { safeToNumber } from "@/lib/utils/number";

View File

@@ -1,5 +1,3 @@
import type { SelectOption } from "@/components/lancamentos/types";
/**

View File

@@ -1,5 +1,3 @@
import type { LancamentoItem } from "@/components/lancamentos/types";
import { getTodayDateString } from "@/lib/utils/date";
import { derivePeriodFromDate } from "@/lib/utils/period";

View File

@@ -1,5 +1,3 @@
import { readdir } from "node:fs/promises";
import path from "node:path";

View File

@@ -1,5 +1,9 @@
import { and, eq } from "drizzle-orm";
import { pagadores, compartilhamentosPagador, user as usersTable } from "@/db/schema";
import {
compartilhamentosPagador,
pagadores,
user as usersTable,
} from "@/db/schema";
import { db } from "@/lib/db";
export type PagadorWithAccess = typeof pagadores.$inferSelect & {
@@ -24,7 +28,10 @@ export async function fetchPagadoresWithAccess(
ownerEmail: usersTable.email,
})
.from(compartilhamentosPagador)
.innerJoin(pagadores, eq(compartilhamentosPagador.pagadorId, pagadores.id))
.innerJoin(
pagadores,
eq(compartilhamentosPagador.pagadorId, pagadores.id),
)
.leftJoin(usersTable, eq(pagadores.userId, usersTable.id))
.where(eq(compartilhamentosPagador.sharedWithUserId, userId)),
]);

View File

@@ -1,5 +1,3 @@
import { DEFAULT_PAGADOR_AVATAR } from "./constants";
/**

View File

@@ -1,5 +1,3 @@
import { format } from "date-fns";
import { ptBR } from "date-fns/locale";
import { and, eq, inArray, isNull, or, sql } from "drizzle-orm";

View File

@@ -1,5 +1,3 @@
import { and, eq, inArray, isNull, or, sql } from "drizzle-orm";
import { categorias, lancamentos, pagadores } from "@/db/schema";
import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/accounts/constants";

View File

@@ -1,5 +1,3 @@
import { currencyFormatter } from "@/lib/lancamentos/formatting-helpers";
import { calculatePercentageChange } from "@/lib/utils/math";
import { buildPeriodRange, MONTH_NAMES, parsePeriod } from "@/lib/utils/period";

View File

@@ -1,5 +1,3 @@
import { z } from "zod";
export const inboxItemSchema = z.object({
@@ -10,7 +8,6 @@ export const inboxItemSchema = z.object({
notificationTimestamp: z.string().transform((val) => new Date(val)),
parsedName: z.string().optional(),
parsedAmount: z.coerce.number().optional(),
parsedTransactionType: z.enum(["Despesa", "Receita"]).optional(),
clientId: z.string().optional(), // ID local do app para rastreamento
});

View File

@@ -1,5 +1,3 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";