Skip to content

Commit

Permalink
update orders
Browse files Browse the repository at this point in the history
  • Loading branch information
sadmann7 committed Jan 14, 2024
1 parent 1f9e1a2 commit 323bbee
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 128 deletions.
123 changes: 34 additions & 89 deletions src/app/(dashboard)/dashboard/stores/[storeId]/analytics/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import type { Metadata } from "next"
import { notFound } from "next/navigation"
import { db } from "@/db"
import { orders, stores } from "@/db/schema"
import { stores } from "@/db/schema"
import { env } from "@/env.mjs"
import { and, desc, eq, gte, lte, sql } from "drizzle-orm"
import type { SearchParams } from "@/types"
import { eq } from "drizzle-orm"

import { getCustomers, getSalesCount } from "@/lib/fetchers/order"
import { formatNumber, formatPrice } from "@/lib/utils"
import { searchParamsSchema } from "@/lib/validations/params"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
Expand All @@ -16,6 +18,7 @@ import {
CardTitle,
} from "@/components/ui/card"
import { DateRangePicker } from "@/components/date-range-picker"
import { Icons } from "@/components/icons"

export const metadata: Metadata = {
metadataBase: new URL(env.NEXT_PUBLIC_APP_URL),
Expand All @@ -27,9 +30,7 @@ interface AnalyticsPageProps {
params: {
storeId: string
}
searchParams: {
[key: string]: string | string[] | undefined
}
searchParams: SearchParams
}

export default async function AnalyticsPage({
Expand Down Expand Up @@ -64,136 +65,80 @@ export default async function AnalyticsPage({
notFound()
}

const storeOrders = await db
.select({
amount: orders.amount,
createdAt: orders.createdAt,
})
.from(orders)
.where(
and(
eq(orders.storeId, store.id),
// Filter by createdAt
fromDay && toDay
? and(gte(orders.createdAt, fromDay), lte(orders.createdAt, toDay))
: undefined
)
)
const salesCountPromise = getSalesCount({
storeId,
fromDay: fromDay,
toDay: toDay,
})

const sales = storeOrders.reduce(
(acc, order) => acc + Number(order.amount),
0
)
const customersPromise = getCustomers({
storeId,
fromDay: fromDay,
toDay: toDay,
})

const customers = await db
.select({
name: orders.name,
email: orders.email,
totalSpent: sql<number>`sum(${orders.amount})`,
createdAt: sql<string>`min(${orders.createdAt})`,
})
.from(orders)
.where(
and(
eq(orders.storeId, store.id),
// Filter by createdAt
fromDay && toDay
? and(gte(orders.createdAt, fromDay), lte(orders.createdAt, toDay))
: undefined
)
)
.groupBy(orders.email, orders.name)
.orderBy(desc(sql<number>`sum(${orders.amount})`))
const [sales, customers] = await Promise.all([
salesCountPromise,
customersPromise,
])

return (
<div className="space-y-6 p-1">
<div className="flex flex-col gap-4 xs:flex-row xs:items-center xs:justify-between">
<h2 className="text-2xl font-bold tracking-tight">Analytics</h2>
<DateRangePicker align="end" dayCount={360} />
<DateRangePicker align="end" dayCount={30} />
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Revenue</CardTitle>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
<Icons.dollarSign
className="h-4 w-4 text-muted-foreground"
>
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />
</svg>
aria-hidden="true"
/>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">
{formatPrice(sales, {
notation: "standard",
})}
</div>
<p className="text-xs text-muted-foreground">
+20.1% from last month
</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Sales</CardTitle>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
<Icons.credit
className="h-4 w-4 text-muted-foreground"
>
<rect width="20" height="14" x="2" y="5" rx="2" />
<path d="M2 10h20" />
</svg>
aria-hidden="true"
/>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">
{formatPrice(sales, {
notation: "standard",
})}
</div>
<p className="text-xs text-muted-foreground">
+19% from last month
</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Customers</CardTitle>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
<CardTitle className="text-sm font-medium">
Recent Customers
</CardTitle>
<Icons.activity
className="h-4 w-4 text-muted-foreground"
>
<path d="M22 12h-4l-3 9L9 3l-3 9H2" />
</svg>
aria-hidden="true"
/>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{customers.length}</div>
<p className="text-xs text-muted-foreground">
+201 since last hour
</p>
</CardContent>
</Card>
</div>
<Card>
<CardHeader>
<CardTitle>Customers</CardTitle>
<CardTitle>Recent Customers</CardTitle>
<CardDescription>
{customers.length} customers{" "}
{dayCount && `in the last ${dayCount} days`}
Expand Down
61 changes: 27 additions & 34 deletions src/components/cards/error-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,7 @@ import { ExclamationTriangleIcon } from "@radix-ui/react-icons"

import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { Card, CardDescription, CardTitle } from "@/components/ui/card"
import { ClientButton } from "@/components/client-button"

interface ErrorCardProps extends React.ComponentPropsWithoutRef<typeof Card> {
Expand Down Expand Up @@ -41,41 +34,41 @@ export function ErrorCard({
role="alert"
aria-live="assertive"
aria-atomic="true"
className={cn("grid w-full place-items-center", className)}
className={cn(
"flex w-full min-w-0 flex-col items-center justify-center overflow-hidden p-10",
className
)}
{...props}
>
<CardHeader>
<div className="grid h-20 w-20 place-items-center rounded-full bg-muted">
<Icon className="h-10 w-10" aria-hidden="true" />
</div>
</CardHeader>
<CardContent className="flex min-h-[176px] flex-col items-center justify-center space-y-2.5 text-center">
<div className="grid place-items-center rounded-full border border-dashed border-muted-foreground/75 p-6">
<Icon
className="h-10 w-10 text-muted-foreground/75"
aria-hidden="true"
/>
</div>
<div className="flex flex-col items-center justify-center space-y-1.5 py-14 text-center">
<CardTitle className="text-2xl">{title}</CardTitle>
<CardDescription className="line-clamp-4">
{description}
</CardDescription>
</CardContent>
</div>
{retryLink ? (
<CardFooter>
<Link
href={retryLink}
className={cn(
buttonVariants({
variant: "ghost",
})
)}
>
{retryLinkText}
<span className="sr-only">{retryLinkText}</span>
</Link>
</CardFooter>
<Link
href={retryLink}
className={cn(
buttonVariants({
variant: "ghost",
})
)}
>
{retryLinkText}
<span className="sr-only">{retryLinkText}</span>
</Link>
) : null}
{reset ? (
<CardFooter>
<ClientButton aria-label="Retry" variant="ghost" onClick={reset}>
Retry
</ClientButton>
</CardFooter>
<ClientButton aria-label="Retry" variant="ghost" onClick={reset}>
Retry
</ClientButton>
) : null}
</Card>
)
Expand Down
9 changes: 4 additions & 5 deletions src/components/date-range-picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,15 @@ import {
PopoverTrigger,
} from "@/components/ui/popover"

interface DateRangePickerProps extends React.HTMLAttributes<HTMLDivElement> {
interface DateRangePickerProps
extends React.ComponentPropsWithoutRef<typeof PopoverContent> {
dateRange?: DateRange
dayCount?: number
align?: "center" | "start" | "end"
}

export function DateRangePicker({
dateRange,
dayCount,
align = "start",
className,
...props
}: DateRangePickerProps) {
Expand Down Expand Up @@ -82,7 +81,7 @@ export function DateRangePicker({
}, [date?.from, date?.to])

return (
<div className={cn("grid gap-2", className)} {...props}>
<div className="grid gap-2">
<Popover>
<PopoverTrigger asChild>
<Button
Expand All @@ -108,7 +107,7 @@ export function DateRangePicker({
)}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align={align}>
<PopoverContent className={cn("w-auto p-0", className)} {...props}>
<Calendar
initialFocus
mode="range"
Expand Down
14 changes: 14 additions & 0 deletions src/components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,20 @@ export const Icons = {
<path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />
</svg>
),
activity: (props: IconProps) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<path d="M22 12h-4l-3 9L9 3l-3 9H2" />
</svg>
),
bot: (props: IconProps) => (
<svg
xmlns="http://www.w3.org/2000/svg"
Expand Down
Loading

1 comment on commit 323bbee

@vercel
Copy link

@vercel vercel bot commented on 323bbee Jan 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.