mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 11:01:45 +00:00
- 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>
75 lines
2.0 KiB
TypeScript
75 lines
2.0 KiB
TypeScript
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,
|
|
};
|
|
}
|