first build commit
This commit is contained in:
104
src/app/(app)/dashboard/page.tsx
Normal file
104
src/app/(app)/dashboard/page.tsx
Normal file
@@ -0,0 +1,104 @@
|
||||
import { auth } from '@/lib/auth'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import { monthBounds, monthLabel } from '@/lib/utils/dates'
|
||||
import { NetWorthCard } from '@/components/dashboard/NetWorthCard'
|
||||
import { CashFlowCard } from '@/components/dashboard/CashFlowCard'
|
||||
import { RecentTransactions } from '@/components/dashboard/RecentTransactions'
|
||||
import { BudgetSummary } from '@/components/dashboard/BudgetSummary'
|
||||
|
||||
export default async function DashboardPage() {
|
||||
const session = await auth()
|
||||
if (!session?.user?.id) return null
|
||||
|
||||
const userId = session.user.id
|
||||
const { start, end } = monthBounds()
|
||||
|
||||
const [accounts, cashFlowRows, budgets, spendRows, recentTx] = await Promise.all([
|
||||
prisma.account.findMany({
|
||||
where: { userId, isActive: true },
|
||||
select: { id: true, name: true, type: true, currentBalanceCents: true },
|
||||
orderBy: { name: 'asc' },
|
||||
}),
|
||||
prisma.$queryRaw<{ type: string; total: bigint }[]>`
|
||||
SELECT t.type, COALESCE(SUM(t."amountCents"), 0)::bigint AS total
|
||||
FROM "Transaction" t
|
||||
JOIN "Account" a ON t."accountId" = a.id
|
||||
WHERE a."userId" = ${userId}
|
||||
AND a.type = 'BANK'
|
||||
AND t.date >= ${start}
|
||||
AND t.date <= ${end}
|
||||
GROUP BY t.type
|
||||
`,
|
||||
prisma.budget.findMany({
|
||||
where: { userId, isActive: true },
|
||||
orderBy: { name: 'asc' },
|
||||
}),
|
||||
prisma.$queryRaw<{ budgetId: string; total: bigint }[]>`
|
||||
SELECT t."budgetId", COALESCE(SUM(t."amountCents"), 0)::bigint AS total
|
||||
FROM "Transaction" t
|
||||
JOIN "Account" a ON t."accountId" = a.id
|
||||
WHERE a."userId" = ${userId}
|
||||
AND t."budgetId" IS NOT NULL
|
||||
AND t.type = 'DEBIT'
|
||||
AND t.date >= ${start}
|
||||
AND t.date <= ${end}
|
||||
GROUP BY t."budgetId"
|
||||
`,
|
||||
prisma.transaction.findMany({
|
||||
where: { account: { userId } },
|
||||
include: { account: { select: { name: true } } },
|
||||
orderBy: { date: 'desc' },
|
||||
take: 5,
|
||||
}),
|
||||
])
|
||||
|
||||
const bankAccounts = accounts.filter((a) => a.type === 'BANK')
|
||||
const netWorthCents = bankAccounts.reduce((s, a) => s + a.currentBalanceCents, 0)
|
||||
|
||||
const cfMap = Object.fromEntries(cashFlowRows.map((r) => [r.type, Number(r.total)]))
|
||||
const creditsCents = cfMap['CREDIT'] ?? 0
|
||||
const debitsCents = cfMap['DEBIT'] ?? 0
|
||||
|
||||
const spendMap = new Map(spendRows.map((r) => [r.budgetId, Number(r.total)]))
|
||||
|
||||
const recentTransactions = recentTx.map((t) => ({
|
||||
id: t.id,
|
||||
date: t.date.toISOString(),
|
||||
description: t.description,
|
||||
amountCents: t.amountCents,
|
||||
type: t.type,
|
||||
accountName: t.account.name,
|
||||
}))
|
||||
|
||||
const budgetsWithSpend = budgets.map((b) => ({
|
||||
id: b.id,
|
||||
name: b.name,
|
||||
limitCents: b.limitCents,
|
||||
color: b.color,
|
||||
spendCents: spendMap.get(b.id) ?? 0,
|
||||
}))
|
||||
|
||||
return (
|
||||
<div className="p-6 space-y-6">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold">Dashboard</h1>
|
||||
<p className="text-sm text-muted-foreground">{monthLabel()}</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
<NetWorthCard netWorthCents={netWorthCents} bankAccounts={bankAccounts} />
|
||||
<CashFlowCard
|
||||
monthLabel={monthLabel()}
|
||||
creditsCents={creditsCents}
|
||||
debitsCents={debitsCents}
|
||||
netCents={creditsCents - debitsCents}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 lg:grid-cols-2">
|
||||
<RecentTransactions transactions={recentTransactions} />
|
||||
<BudgetSummary budgets={budgetsWithSpend} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user