Skip to content

Commit

Permalink
recent transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
collinschaafsma committed Oct 12, 2024
1 parent 4827b7b commit 53aedb8
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 26 deletions.
109 changes: 84 additions & 25 deletions app/(app)/dashboard/_components/recent-transactions-card.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { Suspense } from "react"
import { analytic } from "@/services/analytic"
import { invoice } from "@/services/invoice"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { Skeleton } from "@/components/ui/skeleton"
import {
Table,
TableBody,
Expand All @@ -13,26 +17,87 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table"
import { ErrorBoundary } from "@/components/error-boundary"

export function RecentTransactionsCard({ className }: { className?: string }) {
const recentTransactions = [
{ id: 1, email: "[email protected]", amount: 1200, status: "Completed" },
{ id: 2, email: "[email protected]", amount: 850, status: "Pending" },
{ id: 3, email: "[email protected]", amount: 2300, status: "Completed" },
{ id: 4, email: "[email protected]", amount: 1750, status: "Failed" },
{
id: 5,
email: "[email protected]",
amount: 3100,
status: "Completed",
},
]
async function LoadRecentTransactions() {
const recentTransactions = await invoice.list({
range: { from: new Date(1978, 0, 1), to: new Date() },
limit: 5,
})

if (recentTransactions.length === 0) {
return (
<TableRow>
<TableCell colSpan={2}>No transactions found</TableCell>
</TableRow>
)
}

return (
<>
{recentTransactions.map(transaction => (
<TableRow key={transaction.id}>
<TableCell className="font-medium">
{transaction.user.email}
</TableCell>
<TableCell>${transaction.amountPaid / 100}</TableCell>
<TableCell className="text-right">{transaction.status}</TableCell>
</TableRow>
))}
</>
)
}

function RecentTransactionsSkeleton() {
return (
<TableRow>
<TableCell colSpan={2}>
<Skeleton className="h-6 w-full" />
</TableCell>
</TableRow>
)
}

function RecentTransactionsErrorFallback() {
return (
<TableRow>
<TableCell colSpan={2}>
<div className="text-red-500">Failed to load recent transactions</div>
</TableCell>
</TableRow>
)
}

async function SalesThisMonth() {
const salesCountThisMonth = await analytic.salesCount({
from: new Date(new Date().getFullYear(), new Date().getMonth(), 1),
to: new Date(),
})

return (
<>
You made {salesCountThisMonth}{" "}
{salesCountThisMonth === 1 ? "sale" : "sales"} this month.
</>
)
}

function SalesThisMonthSkeleton() {
return <>You made 0 sales this month.</>
}

export function RecentTransactionsCard({ className }: { className?: string }) {
return (
<Card className={className}>
<CardHeader>
<CardTitle>Recent Transactions</CardTitle>
<CardDescription>You made 265 sales this month.</CardDescription>
<CardDescription>
<ErrorBoundary fallback={null}>
<Suspense fallback={<SalesThisMonthSkeleton />}>
<SalesThisMonth />
</Suspense>
</ErrorBoundary>
</CardDescription>
</CardHeader>
<CardContent>
<Table>
Expand All @@ -44,17 +109,11 @@ export function RecentTransactionsCard({ className }: { className?: string }) {
</TableRow>
</TableHeader>
<TableBody>
{recentTransactions.map(transaction => (
<TableRow key={transaction.id}>
<TableCell className="font-medium">
{transaction.email}
</TableCell>
<TableCell>${transaction.amount}</TableCell>
<TableCell className="text-right">
{transaction.status}
</TableCell>
</TableRow>
))}
<ErrorBoundary fallback={<RecentTransactionsErrorFallback />}>
<Suspense fallback={<RecentTransactionsSkeleton />}>
<LoadRecentTransactions />
</Suspense>
</ErrorBoundary>
</TableBody>
</Table>
</CardContent>
Expand Down
7 changes: 7 additions & 0 deletions drizzle/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,13 @@ export const invoices = pgTable("invoice", {
.references(() => users.id),
})

export const invoicesRelations = relations(invoices, ({ one }) => ({
user: one(users, {
fields: [invoices.userId],
references: [users.id],
}),
}))

// Product types
export type Product = InferSelectModel<typeof products>
export type NewProduct = InferInsertModel<typeof products>
Expand Down
26 changes: 25 additions & 1 deletion services/analytic.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { unstable_cache as ioCache } from "next/cache"
import { and, between, count, eq } from "drizzle-orm"
import { ListContactsResponse, Resend } from "resend"
import { db } from "@/drizzle/db"
import { checkoutSessions } from "@/drizzle/schema"
import { resendAudienceId, resendEnabled } from "@/lib/constants"
import { logger } from "@/lib/logger"
import { customer } from "./customer"
Expand Down Expand Up @@ -198,7 +201,7 @@ export const analytic = {
* @returns {Promise<number>} - The calculated gross.
*/
async gross(range: { from: Date; to: Date }) {
const invoices = await invoice.list(range)
const invoices = await invoice.list({ range })
const gross = invoices.reduce((acc, invoice) => {
return acc + invoice.amountPaid
}, 0)
Expand All @@ -216,4 +219,25 @@ export const analytic = {
async customerCount(range: { from: Date; to: Date }) {
return (await customer.count(range))[0].count
},
/**
* Sales Count
*
* This function calculates the sales count for the dashboard.
*
* @returns {Promise<number>} - The calculated sales count.
*/
async salesCount(range: { from: Date; to: Date }) {
return (
await db
.select({ count: count() })
.from(checkoutSessions)
.where(
and(
between(checkoutSessions.created, range.from, range.to),
eq(checkoutSessions.status, "complete"),
eq(checkoutSessions.paymentStatus, "paid")
)
)
)[0].count
},
}

0 comments on commit 53aedb8

Please sign in to comment.