forked from git.gladyson/openmonetis
feat: implementar melhorias em importação, compartilhamento e contas inativas
- Corrigir cálculo de valor na importação de lançamentos parcelados
- Exibir valor total (parcela × quantidade) ao invés do valor da parcela individual
- Permite recriar parcelamentos importados com valor correto
- Permitir que usuários compartilhados se descompartilhem de pagadores
- Adicionar componente PagadorLeaveShareCard na aba Perfil
- Usuário filho pode sair do compartilhamento sem precisar do usuário pai
- Manter autorização bidirecionada na action de remoção de share
- Implementar submenu "Inativos" para contas bancárias
- Criar página /contas/inativos seguindo padrão de cartões
- Filtrar contas ativas e inativas em páginas separadas
- Adicionar ícone e navegação no sidebar
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { lancamentos, pagadorShares, user as usersTable } from "@/db/schema";
|
||||
import { lancamentos, pagadorShares, user as usersTable, contas, cartoes, categorias, pagadores } from "@/db/schema";
|
||||
import { db } from "@/lib/db";
|
||||
import { and, desc, eq, type SQL } from "drizzle-orm";
|
||||
|
||||
@@ -37,17 +37,54 @@ export async function fetchPagadorShares(
|
||||
}));
|
||||
}
|
||||
|
||||
export async function fetchPagadorLancamentos(filters: SQL[]) {
|
||||
const lancamentoRows = await db.query.lancamentos.findMany({
|
||||
where: and(...filters),
|
||||
with: {
|
||||
pagador: true,
|
||||
conta: true,
|
||||
cartao: true,
|
||||
categoria: true,
|
||||
export async function fetchCurrentUserShare(
|
||||
pagadorId: string,
|
||||
userId: string
|
||||
): Promise<{ id: string; createdAt: string } | null> {
|
||||
const shareRow = await db.query.pagadorShares.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
createdAt: true,
|
||||
},
|
||||
orderBy: desc(lancamentos.purchaseDate),
|
||||
where: and(
|
||||
eq(pagadorShares.pagadorId, pagadorId),
|
||||
eq(pagadorShares.sharedWithUserId, userId)
|
||||
),
|
||||
});
|
||||
|
||||
return lancamentoRows;
|
||||
if (!shareRow) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
id: shareRow.id,
|
||||
createdAt: shareRow.createdAt?.toISOString() ?? new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchPagadorLancamentos(filters: SQL[]) {
|
||||
const lancamentoRows = await db
|
||||
.select({
|
||||
lancamento: lancamentos,
|
||||
pagador: pagadores,
|
||||
conta: contas,
|
||||
cartao: cartoes,
|
||||
categoria: categorias,
|
||||
})
|
||||
.from(lancamentos)
|
||||
.leftJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id))
|
||||
.leftJoin(contas, eq(lancamentos.contaId, contas.id))
|
||||
.leftJoin(cartoes, eq(lancamentos.cartaoId, cartoes.id))
|
||||
.leftJoin(categorias, eq(lancamentos.categoriaId, categorias.id))
|
||||
.where(and(...filters))
|
||||
.orderBy(desc(lancamentos.purchaseDate), desc(lancamentos.createdAt));
|
||||
|
||||
// Transformar resultado para o formato esperado
|
||||
return lancamentoRows.map((row: any) => ({
|
||||
...row.lancamento,
|
||||
pagador: row.pagador,
|
||||
conta: row.conta,
|
||||
cartao: row.cartao,
|
||||
categoria: row.categoria,
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { PagadorInfoCard } from "@/components/pagadores/details/pagador-info-car
|
||||
import { PagadorMonthlySummaryCard } from "@/components/pagadores/details/pagador-monthly-summary-card";
|
||||
import { PagadorBoletoCard } from "@/components/pagadores/details/pagador-payment-method-cards";
|
||||
import { PagadorSharingCard } from "@/components/pagadores/details/pagador-sharing-card";
|
||||
import { PagadorLeaveShareCard } from "@/components/pagadores/details/pagador-leave-share-card";
|
||||
import { LancamentosPage as LancamentosSection } from "@/components/lancamentos/page/lancamentos-page";
|
||||
import type {
|
||||
ContaCartaoFilterOption,
|
||||
@@ -39,7 +40,7 @@ import {
|
||||
fetchPagadorMonthlyBreakdown,
|
||||
} from "@/lib/pagadores/details";
|
||||
import { notFound } from "next/navigation";
|
||||
import { fetchPagadorLancamentos, fetchPagadorShares } from "./data";
|
||||
import { fetchPagadorLancamentos, fetchPagadorShares, fetchCurrentUserShare } from "./data";
|
||||
|
||||
type PageSearchParams = Promise<ResolvedSearchParams>;
|
||||
|
||||
@@ -92,9 +93,13 @@ export default async function Page({ params, searchParams }: PageProps) {
|
||||
} = parsePeriodParam(periodoParamRaw);
|
||||
const periodLabel = `${capitalize(monthName)} de ${year}`;
|
||||
|
||||
const allSearchFilters = extractLancamentoSearchFilters(resolvedSearchParams);
|
||||
const searchFilters = canEdit
|
||||
? extractLancamentoSearchFilters(resolvedSearchParams)
|
||||
: EMPTY_FILTERS;
|
||||
? allSearchFilters
|
||||
: {
|
||||
...EMPTY_FILTERS,
|
||||
searchFilter: allSearchFilters.searchFilter, // Permitir busca mesmo em modo read-only
|
||||
};
|
||||
|
||||
let filterSources: Awaited<
|
||||
ReturnType<typeof fetchLancamentoFilterSources>
|
||||
@@ -133,6 +138,10 @@ export default async function Page({ params, searchParams }: PageProps) {
|
||||
? fetchPagadorShares(pagador.id)
|
||||
: Promise.resolve([]);
|
||||
|
||||
const currentUserSharePromise = !canEdit
|
||||
? fetchCurrentUserShare(pagador.id, userId)
|
||||
: Promise.resolve(null);
|
||||
|
||||
const [
|
||||
lancamentoRows,
|
||||
monthlyBreakdown,
|
||||
@@ -140,6 +149,7 @@ export default async function Page({ params, searchParams }: PageProps) {
|
||||
cardUsage,
|
||||
boletoStats,
|
||||
shareRows,
|
||||
currentUserShare,
|
||||
estabelecimentos,
|
||||
] = await Promise.all([
|
||||
fetchPagadorLancamentos(filters),
|
||||
@@ -164,6 +174,7 @@ export default async function Page({ params, searchParams }: PageProps) {
|
||||
period: selectedPeriod,
|
||||
}),
|
||||
sharesPromise,
|
||||
currentUserSharePromise,
|
||||
getRecentEstablishmentsAction(),
|
||||
]);
|
||||
|
||||
@@ -281,6 +292,13 @@ export default async function Page({ params, searchParams }: PageProps) {
|
||||
shares={pagadorSharesData}
|
||||
/>
|
||||
) : null}
|
||||
{!canEdit && currentUserShare ? (
|
||||
<PagadorLeaveShareCard
|
||||
shareId={currentUserShare.id}
|
||||
pagadorName={pagadorData.name}
|
||||
createdAt={currentUserShare.createdAt}
|
||||
/>
|
||||
) : null}
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="painel" className="space-y-4">
|
||||
|
||||
Reference in New Issue
Block a user