Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update sidebar and cards #135

Merged
merged 4 commits into from
May 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/app/(auth)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function AuthLayout({ children }: React.PropsWithChildren) {
<div className="relative aspect-video size-full">
<Image
src="/images/auth-layout.webp"
alt="A skateboarder doing a high drop"
alt="A skateboarder dropping into a bowl"
fill
className="absolute inset-0 object-cover"
priority
Expand Down
2 changes: 1 addition & 1 deletion src/app/(checkout)/checkout/[storeId]/error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// Error components must be Client Components
import * as React from "react"

import { ErrorCard } from "@/components/cards/error-card"
import { ErrorCard } from "@/components/error-card"
import { Shell } from "@/components/shell"

export default function StoreCheckoutError({
Expand Down
14 changes: 2 additions & 12 deletions src/app/(dashboard)/dashboard/_components/dashboard-header.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import Link from "next/link"
import type { User } from "@clerk/nextjs/server"

import { siteConfig } from "@/config/site"
import { Icons } from "@/components/icons"
import { AuthDropdown } from "@/components/layouts/auth-dropdown"

interface DashboardHeaderProps {
Expand All @@ -12,15 +9,8 @@ interface DashboardHeaderProps {

export function DashboardHeader({ user, children }: DashboardHeaderProps) {
return (
<header className="sticky top-0 z-50 w-full border-b bg-background">
<div className="container flex h-16 items-center">
<Link href="/" className="hidden items-center space-x-2 lg:flex">
<Icons.logo className="size-6" aria-hidden="true" />
<span className="hidden font-bold lg:inline-block">
{siteConfig.name}
</span>
<span className="sr-only">Home</span>
</Link>
<header className="sticky top-0 z-50 w-full border-b border-border/60 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="flex h-14 items-center px-6">
{children}
<div className="flex flex-1 items-center justify-end space-x-4">
<nav className="flex items-center space-x-2">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

import Link from "next/link"

import { siteConfig } from "@/config/site"
import { cn } from "@/lib/utils"
import { useMediaQuery } from "@/hooks/use-media-query"
import { Button, type ButtonProps } from "@/components/ui/button"
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"
import {
Sheet,
SheetClose,
SheetContent,
SheetTrigger,
} from "@/components/ui/sheet"
import { Icons } from "@/components/icons"

import { useSidebar } from "./sidebar-provider"
Expand Down Expand Up @@ -41,19 +45,16 @@ export function DashboardSidebarSheet({
</SheetTrigger>
<SheetContent
side="left"
className="inset-y-0 flex h-auto w-[300px] flex-col items-center px-0 pt-9"
className="inset-y-0 flex h-auto w-[18.75rem] flex-col items-center gap-4 px-0 py-4"
>
<div className="w-full self-start px-7">
<SheetClose asChild>
<Link
href="/"
className="flex items-center"
onClick={() => setOpen(false)}
className="mx-6 flex items-center self-start font-heading tracking-wider text-foreground/90 transition-colors hover:text-foreground"
>
<Icons.logo className="mr-2 size-4" aria-hidden="true" />
<span className="font-bold">{siteConfig.name}</span>
<span className="sr-only">Home</span>
<Icons.logo className="size-6" aria-hidden="true" />
</Link>
</div>
</SheetClose>
{children}
</SheetContent>
</Sheet>
Expand Down
20 changes: 17 additions & 3 deletions src/app/(dashboard)/dashboard/_components/dashboard-sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import * as React from "react"
import Link from "next/link"

import { dashboardConfig } from "@/config/dashboard"
import { siteConfig } from "@/config/site"
import { cn } from "@/lib/utils"
import { ScrollArea } from "@/components/ui/scroll-area"
import { Icons } from "@/components/icons"
import { SidebarNav } from "@/components/layouts/sidebar-nav"

interface DashboardSidebarProps extends React.HTMLAttributes<HTMLElement> {
Expand All @@ -15,9 +18,20 @@ export function DashboardSidebar({
...props
}: DashboardSidebarProps) {
return (
<aside className={cn("w-full", className)} {...props}>
<div className="pr-6 pt-4 lg:pt-6">{children}</div>
<ScrollArea className="h-[calc(100vh-8rem)] py-2.5 pr-6">
<aside className={cn("h-screen w-full", className)} {...props}>
<div className="hidden h-[3.55rem] items-center border-b border-border/60 px-6 lg:flex">
<Link
href="/"
className="flex w-fit items-center font-heading tracking-wider text-foreground/90 transition-colors hover:text-foreground"
>
<Icons.logo className="mb-1 mr-2 size-6" aria-hidden="true" />
{siteConfig.name}
</Link>
</div>
<div className="flex flex-col gap-2.5 px-4 pt-2 lg:px-6 lg:pt-4">
{children}
</div>
<ScrollArea className="h-[calc(100vh-8rem)] px-3 py-2.5 lg:px-5">
<SidebarNav items={dashboardConfig.sidebarNav} className="p-1 pt-4" />
</ScrollArea>
</aside>
Expand Down
32 changes: 26 additions & 6 deletions src/app/(dashboard)/dashboard/_components/store-switcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import * as React from "react"
import { useParams, usePathname, useRouter } from "next/navigation"
import { DialogTitle } from "@radix-ui/react-dialog"
import {
CaretSortIcon,
CheckIcon,
FrameIcon,
PlusCircledIcon,
ShadowIcon,
} from "@radix-ui/react-icons"

import { type getStoresByUserId } from "@/lib/actions/store"
Expand All @@ -22,11 +23,13 @@ import {
CommandList,
CommandSeparator,
} from "@/components/ui/command"
import { Dialog, DialogContent, DialogHeader } from "@/components/ui/dialog"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { RateLimitAlert } from "@/components/rate-limit-alert"

import { CreateStoreDialog } from "../stores/_components/create-store-dialog"

Expand All @@ -49,9 +52,12 @@ export function StoreSwitcher({
const pathname = usePathname()
const [open, setOpen] = React.useState(false)
const [showNewStoreDialog, setShowNewStoreDialog] = React.useState(false)
const [showRateLimitDialog, setShowRateLimitDialog] = React.useState(false)

const stores = React.use(storesPromise)
const planMetrics = React.use(planMetricsPromise)
const rateLimitExceeded =
planMetrics.storeLimitExceeded || planMetrics.productLimitExceeded

const selectedStore = stores.find((store) => store.id === storeId)

Expand All @@ -62,8 +68,15 @@ export function StoreSwitcher({
planMetricsPromise={planMetricsPromise}
open={showNewStoreDialog}
onOpenChange={setShowNewStoreDialog}
showTrigger={false}
/>
<Dialog open={showRateLimitDialog} onOpenChange={setShowRateLimitDialog}>
<DialogContent className="gap-0">
<DialogHeader className="text-left">
<DialogTitle>Rate limit exceeded</DialogTitle>
</DialogHeader>
<RateLimitAlert planMetrics={planMetrics} />
</DialogContent>
</Dialog>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
Expand All @@ -76,7 +89,7 @@ export function StoreSwitcher({
>
{selectedStore?.name ?? "Select a store"}
<CaretSortIcon
className="ml-auto size-3.5 shrink-0 opacity-50"
className="ml-auto size-4 shrink-0 opacity-50"
aria-hidden="true"
/>
</Button>
Expand All @@ -98,7 +111,10 @@ export function StoreSwitcher({
}}
className="text-sm"
>
<ShadowIcon className="mr-2 size-5" aria-hidden="true" />
<FrameIcon
className="mr-2 size-4 text-muted-foreground"
aria-hidden="true"
/>
{store.name}
<CheckIcon
className={cn(
Expand All @@ -118,12 +134,16 @@ export function StoreSwitcher({
<CommandGroup>
<CommandItem
onSelect={() => {
if (rateLimitExceeded) {
setShowRateLimitDialog(true)
return
}

setOpen(false)
setShowNewStoreDialog(true)
}}
disabled={planMetrics.storeLimitExceeded}
>
<PlusCircledIcon className="mr-2 size-5" aria-hidden="true" />
<PlusCircledIcon className="mr-2 size-4" aria-hidden="true" />
Create store
</CommandItem>
</CommandGroup>
Expand Down
4 changes: 2 additions & 2 deletions src/app/(dashboard)/dashboard/billing/_components/billing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { UsageCard } from "@/components/cards/usage-card"
import { ManageSubscriptionForm } from "@/components/manage-subscription-form"
import { UsageCard } from "@/components/usage-card"

interface BillingProps {
subscriptionPlanPromise: Promise<UserSubscriptionPlan | null>
Expand Down Expand Up @@ -121,7 +121,7 @@ export async function Billing({
stripePriceId={plan.stripePriceId}
stripeCustomerId={subscriptionPlan?.stripeCustomerId}
stripeSubscriptionId={subscriptionPlan?.stripeSubscriptionId}
isSubscribed={subscriptionPlan?.isSubscribed ?? false}
isSubscribed={subscriptionPlan?.isSubscribed}
isCurrentPlan={subscriptionPlan?.title === plan.title}
/>
)}
Expand Down
49 changes: 21 additions & 28 deletions src/app/(dashboard)/dashboard/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { redirect } from "next/navigation"

import { getStoresByUserId } from "@/lib/actions/store"
import { getCachedUser, getUserPlanMetrics } from "@/lib/queries/user"
import { SiteFooter } from "@/components/layouts/site-footer"

import { DashboardHeader } from "./_components/dashboard-header"
import { DashboardSidebar } from "./_components/dashboard-sidebar"
Expand All @@ -24,34 +23,28 @@ export default async function DashboardLayout({

return (
<SidebarProvider>
<div className="flex min-h-screen flex-col">
<DashboardHeader user={user}>
<DashboardSidebarSheet className="lg:hidden">
<DashboardSidebar className="pl-4">
<StoreSwitcher
userId={user.id}
storesPromise={storesPromise}
planMetricsPromise={planMetricsPromise}
/>
</DashboardSidebar>
</DashboardSidebarSheet>
</DashboardHeader>
<div className="container flex-1 items-start lg:grid lg:grid-cols-[240px_minmax(0,1fr)] lg:gap-10">
<DashboardSidebar
// the top-16 class is used for the dashboard-header of h-16, added extra 0.1rem to fix the sticky layout shift issue
className="top-[calc(theme('spacing.16')_+_0.1rem)] z-30 hidden border-r lg:sticky lg:block"
>
<StoreSwitcher
userId={user.id}
storesPromise={storesPromise}
planMetricsPromise={planMetricsPromise}
/>
</DashboardSidebar>
<main className="flex w-full flex-col overflow-hidden">
{children}
</main>
<div className="grid min-h-screen w-full lg:grid-cols-[17.5rem_1fr]">
<DashboardSidebar className="top-0 z-30 hidden flex-col gap-4 border-r border-border/60 lg:sticky lg:block">
<StoreSwitcher
userId={user.id}
storesPromise={storesPromise}
planMetricsPromise={planMetricsPromise}
/>
</DashboardSidebar>
<div className="flex flex-col">
<DashboardHeader user={user}>
<DashboardSidebarSheet className="lg:hidden">
<DashboardSidebar>
<StoreSwitcher
userId={user.id}
storesPromise={storesPromise}
planMetricsPromise={planMetricsPromise}
/>
</DashboardSidebar>
</DashboardSidebarSheet>
</DashboardHeader>
<main className="flex-1 overflow-hidden px-6">{children}</main>
</div>
<SiteFooter />
</div>
</SidebarProvider>
)
Expand Down
2 changes: 1 addition & 1 deletion src/app/(dashboard)/dashboard/stores/[storeId]/error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// Error components must be Client Components
import * as React from "react"

import { ErrorCard } from "@/components/cards/error-card"
import { ErrorCard } from "@/components/error-card"

export default function UpdateStoreError({
error,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ErrorCard } from "@/components/cards/error-card"
import { ErrorCard } from "@/components/error-card"
import { Shell } from "@/components/shell"

export default function StoreNotFound() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ import {
SelectValue,
} from "@/components/ui/select"
import { Textarea } from "@/components/ui/textarea"
import { FilesCard } from "@/components/cards/FilesCard"
import { FileUploader } from "@/components/file-uploader"
import { Files } from "@/components/files"
import { Icons } from "@/components/icons"

interface UpdateProductFormProps {
Expand Down Expand Up @@ -279,7 +279,7 @@ export function UpdateProductForm({
<FormMessage />
</FormItem>
{uploadedFiles.length > 0 ? (
<FilesCard files={uploadedFiles} />
<Files files={uploadedFiles} />
) : null}
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ErrorCard } from "@/components/cards/error-card"
import { ErrorCard } from "@/components/error-card"
import { Shell } from "@/components/shell"

interface ProductNotFoundProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ import {
SelectValue,
} from "@/components/ui/select"
import { Textarea } from "@/components/ui/textarea"
import { FilesCard } from "@/components/cards/FilesCard"
import { FileUploader } from "@/components/file-uploader"
import { Files } from "@/components/files"
import { Icons } from "@/components/icons"

interface CreateProductFormProps {
Expand Down Expand Up @@ -307,7 +307,7 @@ export function CreateProductForm({
<FormMessage />
</FormItem>
{uploadedFiles.length > 0 ? (
<FilesCard files={uploadedFiles} />
<Files files={uploadedFiles} />
) : null}
</div>
)}
Expand Down
Loading