mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 19:01:47 +00:00
feat(dashboard): novos widgets de anexos, inbox e tendências de categoria
- Widget Anexos: resumo de arquivos do período (total, imagens, PDFs, recentes) - Widget Inbox: snapshot de pré-lançamentos pendentes do Companion - Widget Tendências de Categoria: redireciona para relatório de tendências - fetch-dashboard-data: busca attachmentsSnapshot e inboxSnapshot em paralelo - widgets-config: tipo DashboardWidgetQuickActionOptions centralizado; props adminPayerSlug e quickActionOptions adicionadas ao contrato do widget - dashboard-grid-editable: usa o novo tipo unificado de quickActionOptions - proxy.ts: frame-src adicionado à CSP para preview de PDFs via S3 - rota /attachments criada com layout próprio Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
74
src/features/dashboard/inbox-snapshot-queries.ts
Normal file
74
src/features/dashboard/inbox-snapshot-queries.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { and, count, desc, eq } from "drizzle-orm";
|
||||
import { cacheLife, cacheTag } from "next/cache";
|
||||
import { cards, financialAccounts, inboxItems } from "@/db/schema";
|
||||
import { db } from "@/shared/lib/db";
|
||||
|
||||
export type DashboardInboxItem = {
|
||||
id: string;
|
||||
sourceAppName: string | null;
|
||||
parsedName: string | null;
|
||||
parsedAmount: string | null;
|
||||
originalText: string;
|
||||
notificationTimestamp: Date;
|
||||
createdAt: Date;
|
||||
};
|
||||
|
||||
export type DashboardInboxSnapshot = {
|
||||
pendingCount: number;
|
||||
recentItems: DashboardInboxItem[];
|
||||
logoMap: Record<string, string>;
|
||||
};
|
||||
|
||||
export async function fetchDashboardInboxSnapshot(
|
||||
userId: string,
|
||||
): Promise<DashboardInboxSnapshot> {
|
||||
"use cache";
|
||||
cacheTag(`dashboard-${userId}`);
|
||||
cacheLife({ revalidate: 3 });
|
||||
|
||||
const [countRows, items, userCards, userAccounts] = await Promise.all([
|
||||
db
|
||||
.select({ total: count() })
|
||||
.from(inboxItems)
|
||||
.where(
|
||||
and(eq(inboxItems.userId, userId), eq(inboxItems.status, "pending")),
|
||||
),
|
||||
db
|
||||
.select({
|
||||
id: inboxItems.id,
|
||||
sourceAppName: inboxItems.sourceAppName,
|
||||
parsedName: inboxItems.parsedName,
|
||||
parsedAmount: inboxItems.parsedAmount,
|
||||
originalText: inboxItems.originalText,
|
||||
notificationTimestamp: inboxItems.notificationTimestamp,
|
||||
createdAt: inboxItems.createdAt,
|
||||
})
|
||||
.from(inboxItems)
|
||||
.where(
|
||||
and(eq(inboxItems.userId, userId), eq(inboxItems.status, "pending")),
|
||||
)
|
||||
.orderBy(desc(inboxItems.notificationTimestamp))
|
||||
.limit(10),
|
||||
db
|
||||
.select({ name: cards.name, logo: cards.logo })
|
||||
.from(cards)
|
||||
.where(eq(cards.userId, userId)),
|
||||
db
|
||||
.select({ name: financialAccounts.name, logo: financialAccounts.logo })
|
||||
.from(financialAccounts)
|
||||
.where(eq(financialAccounts.userId, userId)),
|
||||
]);
|
||||
|
||||
const logoMap: Record<string, string> = {};
|
||||
for (const item of [...userCards, ...userAccounts]) {
|
||||
if (item.logo) {
|
||||
logoMap[item.name.toLowerCase()] = item.logo;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
pendingCount: Number(countRows[0]?.total ?? 0),
|
||||
recentItems: items,
|
||||
logoMap,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user