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:
@@ -5,7 +5,7 @@ import { and, eq, isNull, ne } from "drizzle-orm";
|
|||||||
import { revalidatePath } from "next/cache";
|
import { revalidatePath } from "next/cache";
|
||||||
import { headers } from "next/headers";
|
import { headers } from "next/headers";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { tokensApi, pagadores } from "@/db/schema";
|
import { pagadores, tokensApi } from "@/db/schema";
|
||||||
import { auth } from "@/lib/auth/config";
|
import { auth } from "@/lib/auth/config";
|
||||||
import { db, schema } from "@/lib/db";
|
import { db, schema } from "@/lib/db";
|
||||||
import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants";
|
import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants";
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ import {
|
|||||||
cartoes,
|
cartoes,
|
||||||
categorias,
|
categorias,
|
||||||
contas,
|
contas,
|
||||||
|
insightsSalvos,
|
||||||
lancamentos,
|
lancamentos,
|
||||||
orcamentos,
|
orcamentos,
|
||||||
pagadores,
|
pagadores,
|
||||||
insightsSalvos,
|
|
||||||
} from "@/db/schema";
|
} from "@/db/schema";
|
||||||
import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/accounts/constants";
|
import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/accounts/constants";
|
||||||
import { getUser } from "@/lib/auth/server";
|
import { getUser } from "@/lib/auth/server";
|
||||||
@@ -752,7 +752,10 @@ export async function saveInsightsAction(
|
|||||||
modelId,
|
modelId,
|
||||||
data: JSON.stringify(data),
|
data: JSON.stringify(data),
|
||||||
})
|
})
|
||||||
.returning({ id: insightsSalvos.id, createdAt: insightsSalvos.createdAt });
|
.returning({
|
||||||
|
id: insightsSalvos.id,
|
||||||
|
createdAt: insightsSalvos.createdAt,
|
||||||
|
});
|
||||||
|
|
||||||
const insertedRecord = result[0];
|
const insertedRecord = result[0];
|
||||||
if (!insertedRecord) {
|
if (!insertedRecord) {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { and, asc, desc, eq, inArray, isNull, or } from "drizzle-orm";
|
|||||||
import { revalidatePath } from "next/cache";
|
import { revalidatePath } from "next/cache";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import {
|
import {
|
||||||
categorias,
|
|
||||||
antecipacoesParcelas,
|
antecipacoesParcelas,
|
||||||
|
categorias,
|
||||||
lancamentos,
|
lancamentos,
|
||||||
pagadores,
|
pagadores,
|
||||||
} from "@/db/schema";
|
} from "@/db/schema";
|
||||||
@@ -320,10 +320,7 @@ export async function getInstallmentAnticipationsAction(
|
|||||||
eq(antecipacoesParcelas.lancamentoId, lancamentos.id),
|
eq(antecipacoesParcelas.lancamentoId, lancamentos.id),
|
||||||
)
|
)
|
||||||
.leftJoin(pagadores, eq(antecipacoesParcelas.pagadorId, pagadores.id))
|
.leftJoin(pagadores, eq(antecipacoesParcelas.pagadorId, pagadores.id))
|
||||||
.leftJoin(
|
.leftJoin(categorias, eq(antecipacoesParcelas.categoriaId, categorias.id))
|
||||||
categorias,
|
|
||||||
eq(antecipacoesParcelas.categoriaId, categorias.id),
|
|
||||||
)
|
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(antecipacoesParcelas.seriesId, validatedSeriesId),
|
eq(antecipacoesParcelas.seriesId, validatedSeriesId),
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import { and, desc, eq, type SQL } from "drizzle-orm";
|
|||||||
import {
|
import {
|
||||||
cartoes,
|
cartoes,
|
||||||
categorias,
|
categorias,
|
||||||
|
compartilhamentosPagador,
|
||||||
contas,
|
contas,
|
||||||
lancamentos,
|
lancamentos,
|
||||||
pagadores,
|
pagadores,
|
||||||
compartilhamentosPagador,
|
|
||||||
user as usersTable,
|
user as usersTable,
|
||||||
} from "@/db/schema";
|
} from "@/db/schema";
|
||||||
import { db } from "@/lib/db";
|
import { db } from "@/lib/db";
|
||||||
@@ -30,7 +30,10 @@ export async function fetchPagadorShares(
|
|||||||
userEmail: usersTable.email,
|
userEmail: usersTable.email,
|
||||||
})
|
})
|
||||||
.from(compartilhamentosPagador)
|
.from(compartilhamentosPagador)
|
||||||
.innerJoin(usersTable, eq(compartilhamentosPagador.sharedWithUserId, usersTable.id))
|
.innerJoin(
|
||||||
|
usersTable,
|
||||||
|
eq(compartilhamentosPagador.sharedWithUserId, usersTable.id),
|
||||||
|
)
|
||||||
.where(eq(compartilhamentosPagador.pagadorId, pagadorId));
|
.where(eq(compartilhamentosPagador.pagadorId, pagadorId));
|
||||||
|
|
||||||
return shareRows.map((share) => ({
|
return shareRows.map((share) => ({
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { randomBytes } from "node:crypto";
|
|||||||
import { and, eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
import { revalidatePath } from "next/cache";
|
import { revalidatePath } from "next/cache";
|
||||||
import { z } from "zod";
|
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 { handleActionError, revalidateForEntity } from "@/lib/actions/helpers";
|
||||||
import type { ActionResult } from "@/lib/actions/types";
|
import type { ActionResult } from "@/lib/actions/types";
|
||||||
import { getUser } from "@/lib/auth/server";
|
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();
|
revalidate();
|
||||||
revalidatePath(`/pagadores/${existing.pagadorId}`);
|
revalidatePath(`/pagadores/${existing.pagadorId}`);
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { and, desc, eq, gte } from "drizzle-orm";
|
import { and, desc, eq, gte } from "drizzle-orm";
|
||||||
import type {
|
import type {
|
||||||
InboxItem,
|
InboxItem,
|
||||||
@@ -9,8 +7,8 @@ import {
|
|||||||
cartoes,
|
cartoes,
|
||||||
categorias,
|
categorias,
|
||||||
contas,
|
contas,
|
||||||
preLancamentos,
|
|
||||||
lancamentos,
|
lancamentos,
|
||||||
|
preLancamentos,
|
||||||
} from "@/db/schema";
|
} from "@/db/schema";
|
||||||
import { db } from "@/lib/db";
|
import { db } from "@/lib/db";
|
||||||
import {
|
import {
|
||||||
@@ -26,7 +24,9 @@ export async function fetchInboxItems(
|
|||||||
const items = await db
|
const items = await db
|
||||||
.select()
|
.select()
|
||||||
.from(preLancamentos)
|
.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));
|
.orderBy(desc(preLancamentos.createdAt));
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
@@ -39,7 +39,9 @@ export async function fetchInboxItemById(
|
|||||||
const [item] = await db
|
const [item] = await db
|
||||||
.select()
|
.select()
|
||||||
.from(preLancamentos)
|
.from(preLancamentos)
|
||||||
.where(and(eq(preLancamentos.id, itemId), eq(preLancamentos.userId, userId)))
|
.where(
|
||||||
|
and(eq(preLancamentos.id, itemId), eq(preLancamentos.userId, userId)),
|
||||||
|
)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
return item ?? null;
|
return item ?? null;
|
||||||
@@ -91,7 +93,10 @@ export async function fetchPendingInboxCount(userId: string): Promise<number> {
|
|||||||
.select({ id: preLancamentos.id })
|
.select({ id: preLancamentos.id })
|
||||||
.from(preLancamentos)
|
.from(preLancamentos)
|
||||||
.where(
|
.where(
|
||||||
and(eq(preLancamentos.userId, userId), eq(preLancamentos.status, "pending")),
|
and(
|
||||||
|
eq(preLancamentos.userId, userId),
|
||||||
|
eq(preLancamentos.status, "pending"),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return items.length;
|
return items.length;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { RiBankCard2Line } from "@remixicon/react";
|
|||||||
import PageDescription from "@/components/page-description";
|
import PageDescription from "@/components/page-description";
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: "Relatório de Cartões | Opensheets",
|
title: "Uso de Cartões | Opensheets",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
@@ -14,7 +14,7 @@ export default function RootLayout({
|
|||||||
<section className="space-y-6 px-6">
|
<section className="space-y-6 px-6">
|
||||||
<PageDescription
|
<PageDescription
|
||||||
icon={<RiBankCard2Line />}
|
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."
|
subtitle="Análise detalhada do uso dos seus cartões de crédito."
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { RiFileChartLine } from "@remixicon/react";
|
|||||||
import PageDescription from "@/components/page-description";
|
import PageDescription from "@/components/page-description";
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: "Relatórios | Opensheets",
|
title: "Tendências | Opensheets",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
@@ -14,7 +14,7 @@ export default function RootLayout({
|
|||||||
<section className="space-y-6 px-6">
|
<section className="space-y-6 px-6">
|
||||||
<PageDescription
|
<PageDescription
|
||||||
icon={<RiFileChartLine />}
|
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."
|
subtitle="Acompanhe a evolução dos seus gastos e receitas por categoria ao longo do tempo."
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { and, eq, isNull } from "drizzle-orm";
|
import { and, eq, isNull } from "drizzle-orm";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { tokensApi } from "@/db/schema";
|
import { tokensApi } from "@/db/schema";
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { headers } from "next/headers";
|
import { headers } from "next/headers";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { and, eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
import { headers } from "next/headers";
|
import { headers } from "next/headers";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { desc, eq } from "drizzle-orm";
|
import { desc, eq } from "drizzle-orm";
|
||||||
import { headers } from "next/headers";
|
import { headers } from "next/headers";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { and, eq, isNull } from "drizzle-orm";
|
import { and, eq, isNull } from "drizzle-orm";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { tokensApi } from "@/db/schema";
|
import { tokensApi } from "@/db/schema";
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import { and, eq, isNull } from "drizzle-orm";
|
import { and, eq, isNull } from "drizzle-orm";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { z } from "zod";
|
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 { extractBearerToken, hashToken } from "@/lib/auth/api-token";
|
||||||
import { db } from "@/lib/db";
|
import { db } from "@/lib/db";
|
||||||
import { inboxBatchSchema } from "@/lib/schemas/inbox";
|
import { inboxBatchSchema } from "@/lib/schemas/inbox";
|
||||||
@@ -103,7 +101,6 @@ export async function POST(request: Request) {
|
|||||||
notificationTimestamp: item.notificationTimestamp,
|
notificationTimestamp: item.notificationTimestamp,
|
||||||
parsedName: item.parsedName,
|
parsedName: item.parsedName,
|
||||||
parsedAmount: item.parsedAmount?.toString(),
|
parsedAmount: item.parsedAmount?.toString(),
|
||||||
parsedTransactionType: item.parsedTransactionType,
|
|
||||||
status: "pending",
|
status: "pending",
|
||||||
})
|
})
|
||||||
.returning({ id: preLancamentos.id });
|
.returning({ id: preLancamentos.id });
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import { and, eq, isNull } from "drizzle-orm";
|
import { and, eq, isNull } from "drizzle-orm";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { z } from "zod";
|
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 { extractBearerToken, hashToken } from "@/lib/auth/api-token";
|
||||||
import { db } from "@/lib/db";
|
import { db } from "@/lib/db";
|
||||||
import { inboxItemSchema } from "@/lib/schemas/inbox";
|
import { inboxItemSchema } from "@/lib/schemas/inbox";
|
||||||
@@ -92,7 +90,6 @@ export async function POST(request: Request) {
|
|||||||
notificationTimestamp: data.notificationTimestamp,
|
notificationTimestamp: data.notificationTimestamp,
|
||||||
parsedName: data.parsedName,
|
parsedName: data.parsedName,
|
||||||
parsedAmount: data.parsedAmount?.toString(),
|
parsedAmount: data.parsedAmount?.toString(),
|
||||||
parsedTransactionType: data.parsedTransactionType,
|
|
||||||
status: "pending",
|
status: "pending",
|
||||||
})
|
})
|
||||||
.returning({ id: preLancamentos.id });
|
.returning({ id: preLancamentos.id });
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { RiCalendarCheckLine, RiLoader4Line } from "@remixicon/react";
|
import { RiCalendarCheckLine, RiLoader4Line } from "@remixicon/react";
|
||||||
import { useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { getInstallmentAnticipationsAction } from "@/app/(dashboard)/lancamentos/anticipation-actions";
|
import { getInstallmentAnticipationsAction } from "@/app/(dashboard)/lancamentos/anticipation-actions";
|
||||||
import {
|
import {
|
||||||
@@ -52,14 +52,8 @@ export function AnticipationHistoryDialog({
|
|||||||
onOpenChange,
|
onOpenChange,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Buscar antecipações ao abrir o dialog
|
// Define loadAnticipations before it's used in useEffect
|
||||||
useEffect(() => {
|
const loadAnticipations = useCallback(async () => {
|
||||||
if (dialogOpen) {
|
|
||||||
loadAnticipations();
|
|
||||||
}
|
|
||||||
}, [dialogOpen, loadAnticipations]);
|
|
||||||
|
|
||||||
const loadAnticipations = async () => {
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -80,7 +74,14 @@ export function AnticipationHistoryDialog({
|
|||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
}, [seriesId]);
|
||||||
|
|
||||||
|
// Buscar antecipações ao abrir o dialog
|
||||||
|
useEffect(() => {
|
||||||
|
if (dialogOpen) {
|
||||||
|
loadAnticipations();
|
||||||
|
}
|
||||||
|
}, [dialogOpen, loadAnticipations]);
|
||||||
|
|
||||||
const handleCanceled = () => {
|
const handleCanceled = () => {
|
||||||
// Recarregar lista após cancelamento
|
// Recarregar lista após cancelamento
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { cn } from "@/lib/utils/ui";
|
|
||||||
import type { InboxItem } from "./types";
|
import type { InboxItem } from "./types";
|
||||||
|
|
||||||
interface InboxCardProps {
|
interface InboxCardProps {
|
||||||
@@ -41,7 +40,6 @@ export function InboxCard({
|
|||||||
onViewDetails,
|
onViewDetails,
|
||||||
}: InboxCardProps) {
|
}: InboxCardProps) {
|
||||||
const amount = item.parsedAmount ? parseFloat(item.parsedAmount) : null;
|
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
|
// 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
|
// Precisamos interpretar o valor UTC como se fosse horário de Brasília
|
||||||
@@ -78,16 +76,7 @@ export function InboxCard({
|
|||||||
</span>
|
</span>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
{amount !== null && (
|
{amount !== null && (
|
||||||
<MoneyValues
|
<MoneyValues amount={amount} className="text-sm" />
|
||||||
amount={isReceita ? amount : -amount}
|
|
||||||
showPositiveSign={isReceita}
|
|
||||||
className={cn(
|
|
||||||
"text-sm",
|
|
||||||
isReceita
|
|
||||||
? "text-green-600 dark:text-green-400"
|
|
||||||
: "text-foreground",
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { ptBR } from "date-fns/locale";
|
import { ptBR } from "date-fns/locale";
|
||||||
import MoneyValues from "@/components/money-values";
|
import MoneyValues from "@/components/money-values";
|
||||||
import { TypeBadge } from "@/components/type-badge";
|
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
@@ -15,7 +14,6 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import { cn } from "@/lib/utils/ui";
|
|
||||||
import type { InboxItem } from "./types";
|
import type { InboxItem } from "./types";
|
||||||
|
|
||||||
interface InboxDetailsDialogProps {
|
interface InboxDetailsDialogProps {
|
||||||
@@ -32,7 +30,6 @@ export function InboxDetailsDialog({
|
|||||||
if (!item) return null;
|
if (!item) return null;
|
||||||
|
|
||||||
const amount = item.parsedAmount ? parseFloat(item.parsedAmount) : null;
|
const amount = item.parsedAmount ? parseFloat(item.parsedAmount) : null;
|
||||||
const isReceita = item.parsedTransactionType === "Receita";
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
@@ -86,30 +83,11 @@ export function InboxDetailsDialog({
|
|||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span className="text-muted-foreground">Valor</span>
|
<span className="text-muted-foreground">Valor</span>
|
||||||
{amount !== null ? (
|
{amount !== null ? (
|
||||||
<MoneyValues
|
<MoneyValues amount={amount} className="text-sm" />
|
||||||
amount={isReceita ? amount : -amount}
|
|
||||||
showPositiveSign={isReceita}
|
|
||||||
className={cn(
|
|
||||||
"text-sm",
|
|
||||||
isReceita
|
|
||||||
? "text-green-600 dark:text-green-400"
|
|
||||||
: "text-foreground",
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<span className="text-muted-foreground">Não extraído</span>
|
<span className="text-muted-foreground">Não extraído</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -139,9 +139,6 @@ export function InboxPage({
|
|||||||
? String(Math.abs(Number(itemToProcess.parsedAmount)))
|
? String(Math.abs(Number(itemToProcess.parsedAmount)))
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
const defaultTransactionType =
|
|
||||||
itemToProcess?.parsedTransactionType === "Receita" ? "Receita" : "Despesa";
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex w-full flex-col gap-6">
|
<div className="flex w-full flex-col gap-6">
|
||||||
@@ -182,7 +179,6 @@ export function InboxPage({
|
|||||||
defaultPurchaseDate={defaultPurchaseDate}
|
defaultPurchaseDate={defaultPurchaseDate}
|
||||||
defaultName={defaultName}
|
defaultName={defaultName}
|
||||||
defaultAmount={defaultAmount}
|
defaultAmount={defaultAmount}
|
||||||
defaultTransactionType={defaultTransactionType}
|
|
||||||
forceShowTransactionType
|
forceShowTransactionType
|
||||||
onSuccess={handleLancamentoSuccess}
|
onSuccess={handleLancamentoSuccess}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import type { SelectOption as LancamentoSelectOption } from "@/components/lancamentos/types";
|
import type { SelectOption as LancamentoSelectOption } from "@/components/lancamentos/types";
|
||||||
|
|
||||||
export interface InboxItem {
|
export interface InboxItem {
|
||||||
@@ -11,7 +9,6 @@ export interface InboxItem {
|
|||||||
notificationTimestamp: Date;
|
notificationTimestamp: Date;
|
||||||
parsedName: string | null;
|
parsedName: string | null;
|
||||||
parsedAmount: string | null;
|
parsedAmount: string | null;
|
||||||
parsedTransactionType: string | null;
|
|
||||||
status: string;
|
status: string;
|
||||||
lancamentoId: string | null;
|
lancamentoId: string | null;
|
||||||
processedAt: Date | null;
|
processedAt: Date | null;
|
||||||
@@ -25,7 +22,6 @@ export interface ProcessInboxInput {
|
|||||||
name: string;
|
name: string;
|
||||||
amount: number;
|
amount: number;
|
||||||
purchaseDate: string;
|
purchaseDate: string;
|
||||||
transactionType: "Despesa" | "Receita";
|
|
||||||
condition: string;
|
condition: string;
|
||||||
paymentMethod: string;
|
paymentMethod: string;
|
||||||
categoriaId: string;
|
categoriaId: string;
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export function AppSidebar({
|
|||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<SidebarMenuButton
|
<SidebarMenuButton
|
||||||
asChild
|
asChild
|
||||||
className="data-[slot=sidebar-menu-button]:px-1.5! hover:bg-transparent active:bg-transparent pt-4 justify-center hover:scale-105 transition-all duration-200"
|
className="data-[slot=sidebar-menu-button]:px-1.5! hover:bg-transparent active:bg-transparent pt-4 justify-center hover:scale-105 transition-all duration-200"
|
||||||
>
|
>
|
||||||
<a href="/dashboard">
|
<a href="/dashboard">
|
||||||
<LogoContent />
|
<LogoContent />
|
||||||
|
|||||||
@@ -85,18 +85,13 @@ export function createSidebarNavData(
|
|||||||
return {
|
return {
|
||||||
navMain: [
|
navMain: [
|
||||||
{
|
{
|
||||||
title: "Visão Geral",
|
title: "Gestão Financeira",
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
title: "Dashboard",
|
title: "Dashboard",
|
||||||
url: "/dashboard",
|
url: "/dashboard",
|
||||||
icon: RiDashboardLine,
|
icon: RiDashboardLine,
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Gestão Financeira",
|
|
||||||
items: [
|
|
||||||
{
|
{
|
||||||
title: "Lançamentos",
|
title: "Lançamentos",
|
||||||
url: "/lancamentos",
|
url: "/lancamentos",
|
||||||
@@ -164,11 +159,6 @@ export function createSidebarNavData(
|
|||||||
url: "/categorias",
|
url: "/categorias",
|
||||||
icon: RiPriceTag3Line,
|
icon: RiPriceTag3Line,
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Análise e Anotações",
|
|
||||||
items: [
|
|
||||||
{
|
{
|
||||||
title: "Anotações",
|
title: "Anotações",
|
||||||
url: "/anotacoes",
|
url: "/anotacoes",
|
||||||
@@ -182,23 +172,23 @@ export function createSidebarNavData(
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Análise",
|
||||||
|
items: [
|
||||||
{
|
{
|
||||||
title: "Insights",
|
title: "Insights",
|
||||||
url: "/insights",
|
url: "/insights",
|
||||||
icon: RiSparklingLine,
|
icon: RiSparklingLine,
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Relatórios",
|
|
||||||
items: [
|
|
||||||
{
|
{
|
||||||
title: "Categorias",
|
title: "Tendências",
|
||||||
url: "/relatorios/categorias",
|
url: "/relatorios/categorias",
|
||||||
icon: RiFileChartLine,
|
icon: RiFileChartLine,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Cartões",
|
title: "Uso de Cartões",
|
||||||
url: "/relatorios/cartoes",
|
url: "/relatorios/cartoes",
|
||||||
icon: RiBankCard2Line,
|
icon: RiBankCard2Line,
|
||||||
},
|
},
|
||||||
@@ -206,11 +196,6 @@ export function createSidebarNavData(
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
navSecondary: [
|
navSecondary: [
|
||||||
// {
|
|
||||||
// title: "Changelog",
|
|
||||||
// url: "/changelog",
|
|
||||||
// icon: RiGitCommitLine,
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
title: "Ajustes",
|
title: "Ajustes",
|
||||||
url: "/ajustes",
|
url: "/ajustes",
|
||||||
|
|||||||
@@ -113,9 +113,11 @@ export function NavMain({ sections }: { sections: NavSection[] }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{sections.map((section) => (
|
{sections.map((section, index) => (
|
||||||
<SidebarGroup key={section.title}>
|
<SidebarGroup key={section.title}>
|
||||||
<SidebarGroupLabel>{section.title}</SidebarGroupLabel>
|
<SidebarGroupLabel className="text-xs text-muted-foreground/60">
|
||||||
|
{section.title}
|
||||||
|
</SidebarGroupLabel>
|
||||||
<SidebarGroupContent>
|
<SidebarGroupContent>
|
||||||
<SidebarMenu>
|
<SidebarMenu>
|
||||||
{section.items.map((item) => {
|
{section.items.map((item) => {
|
||||||
|
|||||||
@@ -451,7 +451,6 @@ export const preLancamentos = pgTable(
|
|||||||
// Dados parseados (editáveis pelo usuário antes de processar)
|
// Dados parseados (editáveis pelo usuário antes de processar)
|
||||||
parsedName: text("parsed_name"), // Nome do estabelecimento
|
parsedName: text("parsed_name"), // Nome do estabelecimento
|
||||||
parsedAmount: numeric("parsed_amount", { precision: 12, scale: 2 }),
|
parsedAmount: numeric("parsed_amount", { precision: 12, scale: 2 }),
|
||||||
parsedTransactionType: text("parsed_transaction_type"), // Despesa, Receita
|
|
||||||
|
|
||||||
// Status de processamento
|
// Status de processamento
|
||||||
status: text("status").notNull().default("pending"), // pending, processed, discarded
|
status: text("status").notNull().default("pending"), // pending, processed, discarded
|
||||||
@@ -527,7 +526,9 @@ export const antecipacoesParcelas = pgTable(
|
|||||||
.defaultNow(),
|
.defaultNow(),
|
||||||
},
|
},
|
||||||
(table) => ({
|
(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),
|
userIdIdx: index("antecipacoes_parcelas_user_id_idx").on(table.userId),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
1
drizzle/0014_yielding_jack_flag.sql
Normal file
1
drizzle/0014_yielding_jack_flag.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "pre_lancamentos" DROP COLUMN "parsed_transaction_type";
|
||||||
File diff suppressed because it is too large
Load Diff
2129
drizzle/meta/0014_snapshot.json
Normal file
2129
drizzle/meta/0014_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,104 +1,111 @@
|
|||||||
{
|
{
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"dialect": "postgresql",
|
"dialect": "postgresql",
|
||||||
"entries": [
|
"entries": [
|
||||||
{
|
{
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1762993507299,
|
"when": 1762993507299,
|
||||||
"tag": "0000_flashy_manta",
|
"tag": "0000_flashy_manta",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1765199006435,
|
"when": 1765199006435,
|
||||||
"tag": "0001_young_mister_fear",
|
"tag": "0001_young_mister_fear",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 2,
|
"idx": 2,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1765200545692,
|
"when": 1765200545692,
|
||||||
"tag": "0002_slimy_flatman",
|
"tag": "0002_slimy_flatman",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 3,
|
"idx": 3,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1767102605526,
|
"when": 1767102605526,
|
||||||
"tag": "0003_green_korg",
|
"tag": "0003_green_korg",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 4,
|
"idx": 4,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1767104066872,
|
"when": 1767104066872,
|
||||||
"tag": "0004_acoustic_mach_iv",
|
"tag": "0004_acoustic_mach_iv",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 5,
|
"idx": 5,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1767106121811,
|
"when": 1767106121811,
|
||||||
"tag": "0005_adorable_bruce_banner",
|
"tag": "0005_adorable_bruce_banner",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 6,
|
"idx": 6,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1767107487318,
|
"when": 1767107487318,
|
||||||
"tag": "0006_youthful_mister_fear",
|
"tag": "0006_youthful_mister_fear",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 7,
|
"idx": 7,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1767118780033,
|
"when": 1767118780033,
|
||||||
"tag": "0007_sturdy_kate_bishop",
|
"tag": "0007_sturdy_kate_bishop",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 8,
|
"idx": 8,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1767125796314,
|
"when": 1767125796314,
|
||||||
"tag": "0008_fat_stick",
|
"tag": "0008_fat_stick",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 9,
|
"idx": 9,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1768925100873,
|
"when": 1768925100873,
|
||||||
"tag": "0009_add_dashboard_widgets",
|
"tag": "0009_add_dashboard_widgets",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 10,
|
"idx": 10,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1769369834242,
|
"when": 1769369834242,
|
||||||
"tag": "0010_lame_psynapse",
|
"tag": "0010_lame_psynapse",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 11,
|
"idx": 11,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1769447087678,
|
"when": 1769447087678,
|
||||||
"tag": "0011_remove_unused_inbox_columns",
|
"tag": "0011_remove_unused_inbox_columns",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 12,
|
"idx": 12,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1769533200000,
|
"when": 1769533200000,
|
||||||
"tag": "0012_rename_tables_to_portuguese",
|
"tag": "0012_rename_tables_to_portuguese",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 13,
|
"idx": 13,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1769523352777,
|
"when": 1769523352777,
|
||||||
"tag": "0013_fancy_rick_jones",
|
"tag": "0013_fancy_rick_jones",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
}
|
},
|
||||||
]
|
{
|
||||||
}
|
"idx": 14,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1769619226903,
|
||||||
|
"tag": "0014_yielding_jack_flag",
|
||||||
|
"breakpoints": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
|
|
||||||
const JWT_SECRET =
|
const JWT_SECRET =
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { betterAuth } from "better-auth";
|
import { betterAuth } from "better-auth";
|
||||||
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
||||||
import type { GoogleProfile } from "better-auth/social-providers";
|
import type { GoogleProfile } from "better-auth/social-providers";
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { headers } from "next/headers";
|
import { headers } from "next/headers";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { auth } from "@/lib/auth/config";
|
import { auth } from "@/lib/auth/config";
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { categorias } from "@/db/schema";
|
import { categorias } from "@/db/schema";
|
||||||
import type { CategoryType } from "@/lib/categorias/constants";
|
import type { CategoryType } from "@/lib/categorias/constants";
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { calculatePercentageChange } from "@/lib/utils/math";
|
import { calculatePercentageChange } from "@/lib/utils/math";
|
||||||
import { safeToNumber } from "@/lib/utils/number";
|
import { safeToNumber } from "@/lib/utils/number";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import type { SelectOption } from "@/components/lancamentos/types";
|
import type { SelectOption } from "@/components/lancamentos/types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import type { LancamentoItem } from "@/components/lancamentos/types";
|
import type { LancamentoItem } from "@/components/lancamentos/types";
|
||||||
import { getTodayDateString } from "@/lib/utils/date";
|
import { getTodayDateString } from "@/lib/utils/date";
|
||||||
import { derivePeriodFromDate } from "@/lib/utils/period";
|
import { derivePeriodFromDate } from "@/lib/utils/period";
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { readdir } from "node:fs/promises";
|
import { readdir } from "node:fs/promises";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { and, eq } from "drizzle-orm";
|
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";
|
import { db } from "@/lib/db";
|
||||||
|
|
||||||
export type PagadorWithAccess = typeof pagadores.$inferSelect & {
|
export type PagadorWithAccess = typeof pagadores.$inferSelect & {
|
||||||
@@ -24,7 +28,10 @@ export async function fetchPagadoresWithAccess(
|
|||||||
ownerEmail: usersTable.email,
|
ownerEmail: usersTable.email,
|
||||||
})
|
})
|
||||||
.from(compartilhamentosPagador)
|
.from(compartilhamentosPagador)
|
||||||
.innerJoin(pagadores, eq(compartilhamentosPagador.pagadorId, pagadores.id))
|
.innerJoin(
|
||||||
|
pagadores,
|
||||||
|
eq(compartilhamentosPagador.pagadorId, pagadores.id),
|
||||||
|
)
|
||||||
.leftJoin(usersTable, eq(pagadores.userId, usersTable.id))
|
.leftJoin(usersTable, eq(pagadores.userId, usersTable.id))
|
||||||
.where(eq(compartilhamentosPagador.sharedWithUserId, userId)),
|
.where(eq(compartilhamentosPagador.sharedWithUserId, userId)),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { DEFAULT_PAGADOR_AVATAR } from "./constants";
|
import { DEFAULT_PAGADOR_AVATAR } from "./constants";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { ptBR } from "date-fns/locale";
|
import { ptBR } from "date-fns/locale";
|
||||||
import { and, eq, inArray, isNull, or, sql } from "drizzle-orm";
|
import { and, eq, inArray, isNull, or, sql } from "drizzle-orm";
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { and, eq, inArray, isNull, or, sql } from "drizzle-orm";
|
import { and, eq, inArray, isNull, or, sql } from "drizzle-orm";
|
||||||
import { categorias, lancamentos, pagadores } from "@/db/schema";
|
import { categorias, lancamentos, pagadores } from "@/db/schema";
|
||||||
import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/accounts/constants";
|
import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/accounts/constants";
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { currencyFormatter } from "@/lib/lancamentos/formatting-helpers";
|
import { currencyFormatter } from "@/lib/lancamentos/formatting-helpers";
|
||||||
import { calculatePercentageChange } from "@/lib/utils/math";
|
import { calculatePercentageChange } from "@/lib/utils/math";
|
||||||
import { buildPeriodRange, MONTH_NAMES, parsePeriod } from "@/lib/utils/period";
|
import { buildPeriodRange, MONTH_NAMES, parsePeriod } from "@/lib/utils/period";
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const inboxItemSchema = z.object({
|
export const inboxItemSchema = z.object({
|
||||||
@@ -10,7 +8,6 @@ export const inboxItemSchema = z.object({
|
|||||||
notificationTimestamp: z.string().transform((val) => new Date(val)),
|
notificationTimestamp: z.string().transform((val) => new Date(val)),
|
||||||
parsedName: z.string().optional(),
|
parsedName: z.string().optional(),
|
||||||
parsedAmount: z.coerce.number().optional(),
|
parsedAmount: z.coerce.number().optional(),
|
||||||
parsedTransactionType: z.enum(["Despesa", "Receita"]).optional(),
|
|
||||||
clientId: z.string().optional(), // ID local do app para rastreamento
|
clientId: z.string().optional(), // ID local do app para rastreamento
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import { type ClassValue, clsx } from "clsx";
|
import { type ClassValue, clsx } from "clsx";
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user