Skip to content

Commit

Permalink
update product page
Browse files Browse the repository at this point in the history
  • Loading branch information
sadmann7 committed Dec 7, 2023
1 parent 8484809 commit e08d334
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 91 deletions.
8 changes: 4 additions & 4 deletions src/app/(checkout)/checkout/[storeId]/loading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,21 @@ export default function CheckoutLoading() {
<ScrollArea className="h-full">
<div className="container grid max-w-xl gap-5 lg:ml-0 lg:mr-auto">
{Array.from({ length: 4 }).map((_, j) => (
<fieldset key={j} className="space-y-2">
<div key={j} className="space-y-2">
<Skeleton className="h-4 w-8 bg-muted/10" />
<div className="flex h-11 items-center rounded border border-muted/10 bg-transparent px-3 py-1">
<Skeleton className="h-3.5 w-14 bg-muted/10" />
</div>
</fieldset>
</div>
))}
<div className="flex flex-col items-center gap-2 xxs:flex-row">
{Array.from({ length: 2 }).map((_, k) => (
<fieldset key={k} className="w-full space-y-2">
<div key={k} className="w-full space-y-2">
<Skeleton className="h-4 w-8 bg-muted/10" />
<div className="flex h-11 items-center rounded border border-muted/10 bg-transparent px-3 py-1">
<Skeleton className="h-3.5 w-14 bg-muted/10" />
</div>
</fieldset>
</div>
))}
</div>
<Skeleton className="h-8 w-full bg-muted/10" />
Expand Down
2 changes: 1 addition & 1 deletion src/app/(dashboard)/dashboard/stores/[storeId]/loading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Skeleton } from "@/components/ui/skeleton"

export default function StoreLoading() {
return (
<div className="space-y-6">
<div className="space-y-10">
<Card>
<CardHeader className="space-y-2">
<Skeleton className="h-6 w-1/4" />
Expand Down
77 changes: 9 additions & 68 deletions src/app/(dashboard)/dashboard/stores/[storeId]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { type Metadata } from "next"
import { revalidatePath } from "next/cache"
import Link from "next/link"
import { notFound, redirect } from "next/navigation"
import { notFound } from "next/navigation"
import { db } from "@/db"
import { products, stores } from "@/db/schema"
import { stores } from "@/db/schema"
import { env } from "@/env.mjs"
import { and, eq, not } from "drizzle-orm"
import { eq } from "drizzle-orm"

import { deleteStore, updateStore } from "@/lib/actions/store"
import { getStripeAccount } from "@/lib/fetchers/stripe"
import { cn, formatDate } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"
Expand Down Expand Up @@ -41,55 +41,6 @@ export default async function UpdateStorePage({
}: UpdateStorePageProps) {
const storeId = Number(params.storeId)

async function updateStore(fd: FormData) {
"use server"

const name = fd.get("name") as string
const description = fd.get("description") as string

const storeWithSameName = await db.query.stores.findFirst({
where: and(eq(stores.name, name), not(eq(stores.id, storeId))),
columns: {
id: true,
},
})

if (storeWithSameName) {
throw new Error("Store name already taken")
}

await db
.update(stores)
.set({ name, description })
.where(eq(stores.id, storeId))

revalidatePath(`/dashboard/stores/${storeId}`)
}

async function deleteStore() {
"use server"

const store = await db.query.stores.findFirst({
where: eq(stores.id, storeId),
columns: {
id: true,
},
})

if (!store) {
throw new Error("Store not found")
}

await db.delete(stores).where(eq(stores.id, storeId))

// Delete all products of this store
await db.delete(products).where(eq(products.storeId, storeId))

const path = "/dashboard/stores"
revalidatePath(path)
redirect(path)
}

const store = await db.query.stores.findFirst({
where: eq(stores.id, storeId),
columns: {
Expand All @@ -108,13 +59,9 @@ export default async function UpdateStorePage({
})

return (
<div className="space-y-6">
<div className="space-y-10">
{stripeAccount ? (
<Card
as="section"
id="manage-stripe-account"
aria-labelledby="manage-stripe-account-heading"
>
<Card as="section">
<CardHeader className="space-y-1">
<CardTitle className="line-clamp-1 text-2xl">
Manage Stripe account
Expand Down Expand Up @@ -201,11 +148,7 @@ export default async function UpdateStorePage({
</CardContent>
</Card>
)}
<Card
as="section"
id="update-store"
aria-labelledby="update-store-heading"
>
<Card as="section">
<CardHeader className="space-y-1">
<CardTitle className="text-2xl">Update your store</CardTitle>
<CardDescription>
Expand All @@ -214,8 +157,7 @@ export default async function UpdateStorePage({
</CardHeader>
<CardContent>
<form
// eslint-disable-next-line @typescript-eslint/no-misused-promises
action={updateStore}
action={updateStore.bind(null, storeId)}
className="grid w-full max-w-xl gap-5"
>
<div className="grid gap-2.5">
Expand Down Expand Up @@ -249,8 +191,7 @@ export default async function UpdateStorePage({
<span className="sr-only">Update store</span>
</LoadingButton>
<LoadingButton
// eslint-disable-next-line @typescript-eslint/no-misused-promises
formAction={deleteStore}
formAction={deleteStore.bind(null, storeId)}
variant="destructive"
>
Delete store
Expand Down
34 changes: 25 additions & 9 deletions src/app/(lobby)/product/[productId]/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { cn } from "@/lib/utils"
import { AspectRatio } from "@/components/ui/aspect-ratio"
import { Card, CardContent, CardFooter, CardHeader } from "@/components/ui/card"
import { Separator } from "@/components/ui/separator"
Expand Down Expand Up @@ -46,17 +47,32 @@ export default function ProductLoading() {
<Skeleton className="h-6 w-10" />
<Skeleton className="h-6 w-14" />
</div>
<Separator className="my-1.5" />
<div className="flex items-center space-x-2">
<Skeleton className="h-8 w-[7.5rem]" />
<Skeleton className="h-8 w-24" />
<Separator className="my-4" />
<Skeleton className="h-4 w-20" />
<div className="flex items-center justify-between">
<Skeleton className="h-4 w-24" />
<Skeleton className="h-6 w-6" />
</div>
<Separator className="mb-2.5 mt-5" />
<div className="flex items-center">
<Skeleton className="h-7 w-16" />
<Skeleton className="ml-auto h-4 w-4" />
<div className="flex max-w-[260px] items-center space-x-2.5">
<Skeleton className="h-8 w-full" />
<Skeleton className="h-8 w-full" />
</div>
<Separator className="mt-2.5" />
<Separator className="my-5" />
<div className="space-y-6">
<div className="flex items-center justify-between space-x-4">
<Skeleton className="h-4 w-16" />
<Skeleton className="h-4 w-4" />
</div>
<div className="space-y-2">
{Array.from({ length: 3 }).map((_, i) => (
<Skeleton
key={i}
className={cn("h-4 w-full", i === 2 && "w-1/2")}
/>
))}
</div>
</div>
<Separator className="md:hidden" />
</div>
</div>
<div className="overflow-hidden md:pt-6">
Expand Down
9 changes: 5 additions & 4 deletions src/app/(lobby)/product/[productId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export default async function ProductPage({ params }: ProductPageProps) {
: []

return (
<Shell>
<Shell className="pb-12 md:pb-14">
<Breadcrumbs
segments={[
{
Expand Down Expand Up @@ -166,22 +166,23 @@ export default async function ProductPage({ params }: ProductPageProps) {
className="w-full"
defaultValue="description"
>
<AccordionItem value="description">
<AccordionItem value="description" className="border-none">
<AccordionTrigger>Description</AccordionTrigger>
<AccordionContent>
{product.description ??
"No description is available for this product."}
</AccordionContent>
</AccordionItem>
</Accordion>
<Separator className="md:hidden" />
</div>
</div>
{store && otherProducts.length > 0 ? (
<div className="overflow-hidden md:pt-6">
<div className="space-y-6 overflow-hidden">
<h2 className="line-clamp-1 flex-1 text-2xl font-bold">
More products from {store.name}
</h2>
<ScrollArea orientation="horizontal" className="pb-3.5 pt-6">
<ScrollArea orientation="horizontal" className="pb-3.5">
<div className="flex gap-4">
{otherProducts.map((product) => (
<ProductCard
Expand Down
4 changes: 2 additions & 2 deletions src/components/forms/add-to-cart-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ export function AddToCartForm({ productId }: AddToCartFormProps) {
return (
<Form {...form}>
<form
className="max-w-xs space-y-4"
onSubmit={(...args) => void form.handleSubmit(onSubmit)(...args)}
className="max-w-[260px] space-y-4"
onSubmit={form.handleSubmit(onSubmit)}
>
<div className="flex items-center">
<Button
Expand Down
3 changes: 2 additions & 1 deletion src/components/loading-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ const LoadingButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
return (
<Button
className={cn(buttonVariants({ variant, size, className }))}
{...props}
ref={ref}
disabled={pending}
{...props}
>
{pending && (
<Icons.spinner
Expand Down
56 changes: 54 additions & 2 deletions src/lib/actions/store.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"use server"

import { revalidatePath } from "next/cache"
import { redirect } from "next/navigation"
import { db } from "@/db"
import { stores } from "@/db/schema"
import { eq } from "drizzle-orm"
import { and, eq, not } from "drizzle-orm"
import { products } from "drizzle/schema"
import { z } from "zod"

import { slugify } from "@/lib/utils"
import { storeSchema } from "@/lib/validations/store"
import { storeSchema, updateStoreSchema } from "@/lib/validations/store"

const extendedStoreSchema = storeSchema.extend({
userId: z.string(),
Expand All @@ -33,3 +35,53 @@ export async function addStore(rawInput: z.infer<typeof extendedStoreSchema>) {

revalidatePath("/dashboard/stores")
}

export async function updateStore(storeId: number, fd: FormData) {
const input = updateStoreSchema.parse({
name: fd.get("name"),
description: fd.get("description"),
})

const storeWithSameName = await db.query.stores.findFirst({
where: and(eq(stores.name, input.name), not(eq(stores.id, storeId))),
columns: {
id: true,
},
})

if (storeWithSameName) {
throw new Error("Store name already taken")
}

await db
.update(stores)
.set({
name: input.name,
description: input.description,
})
.where(eq(stores.id, storeId))

revalidatePath(`/dashboard/stores/${storeId}`)
}

export async function deleteStore(storeId: number) {
const store = await db.query.stores.findFirst({
where: eq(stores.id, storeId),
columns: {
id: true,
},
})

if (!store) {
throw new Error("Store not found")
}

await db.delete(stores).where(eq(stores.id, storeId))

// Delete all products of this store
await db.delete(products).where(eq(products.storeId, storeId))

const path = "/dashboard/stores"
revalidatePath(path)
redirect(path)
}
5 changes: 5 additions & 0 deletions src/lib/validations/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ export const getStoresSchema = z.object({
statuses: z.string().optional().nullable(),
userId: z.string().optional(),
})

export const updateStoreSchema = z.object({
name: z.string().min(3).max(50),
description: z.string().optional(),
})

1 comment on commit e08d334

@vercel
Copy link

@vercel vercel bot commented on e08d334 Dec 7, 2023

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.