Skip to content

Commit

Permalink
update cart icon
Browse files Browse the repository at this point in the history
  • Loading branch information
sadmann7 committed Jun 24, 2023
1 parent bfb4148 commit 1121b9e
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 42 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ CLERK_SECRET_KEY=

# uploadthing
UPLOADTHING_SECRET=
UPLOADTHING_APP_ID=
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This is an open source e-commerce skateshop build with everything new in Next.js
## Features

- Authentication with Clerk
- File uploads with uploadthing
- Subscription, payment, and billing with Stripe
- Storefront with products and categories
- Seller and customer workflows
Expand Down
35 changes: 15 additions & 20 deletions src/app/(lobby)/build-a-board/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ import { eq } from "drizzle-orm"

import { productCategories } from "@/config/products"
import { cn } from "@/lib/utils"
import { Card, CardTitle } from "@/components/ui/card"
import { BoardBuilder } from "@/components/board-builder"
import { Header } from "@/components/header"
import { Icons } from "@/components/icons"
import { Shell } from "@/components/shell"
import { getProductsAction } from "@/app/_actions/product"

Expand All @@ -33,7 +31,8 @@ export default async function BuildABoardPage({
// Products transaction
const limit = typeof per_page === "string" ? parseInt(per_page) : 8
const offset = typeof page === "string" ? (parseInt(page) - 1) * limit : 0
const activeSubcategory = typeof subcategory === "string" ? subcategory : 'decks'
const activeSubcategory =
typeof subcategory === "string" ? subcategory : "decks"

const productsTransaction = await getProductsAction({
limit,
Expand All @@ -53,37 +52,33 @@ export default async function BuildABoardPage({
},
where: eq(carts.id, cartId),
})
const cartItemProductIds = cart?.items?.map((item) => item.productId) ?? []
console.log(cartItemProductIds)
const cartProductIds = cart?.items?.map((item) => item.productId) ?? []
console.log(cartProductIds)

return (
<Shell className="gap-0">
<Shell className="gap-4">
<Header
title="Build a Board"
description="Select the components for your board"
size="sm"
/>
<div className="sticky top-14 z-30 w-full shrink-0 overflow-hidden bg-background pb-7 pt-8">
<div className="flex w-full items-center justify-between gap-4 overflow-x-auto pb-1">
<div className="sticky top-14 z-30 w-full shrink-0 overflow-hidden bg-background pt-4">
<div className="inline-flex w-full items-center overflow-x-auto border-b p-1 text-muted-foreground shadow-2xl">
{productCategories[0]?.subcategories.map((subcategory) => (
<Link
aria-label={`Go to ${subcategory.title}`}
aria-label={subcategory.title}
key={subcategory.title}
href={`/build-a-board?subcategory=${subcategory.slug}`}
>
<Card
<div
className={cn(
"grid h-24 w-44 place-items-center gap-2 p-6 hover:bg-muted",
subcategory.slug === activeSubcategory && "bg-muted"
"inline-flex items-center justify-center whitespace-nowrap rounded border-b-2 border-transparent px-3 py-1.5 text-sm font-medium ring-offset-background transition-all hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
subcategory.slug === activeSubcategory &&
"rounded-none border-primary text-foreground shadow hover:rounded-t"
)}
>
{subcategory.slug === searchParams?.[subcategory.slug] ? (
<Icons.check className="h-4 w-4" />
) : (
<Icons.circle className="h-4 w-4" />
)}
<CardTitle>{subcategory.title}</CardTitle>
</Card>
{subcategory.title}
</div>
</Link>
))}
</div>
Expand All @@ -92,7 +87,7 @@ export default async function BuildABoardPage({
products={productsTransaction.items}
pageCount={pageCount}
subcategory={activeSubcategory}
cartItemProductIds={cartItemProductIds}
cartProductIds={cartProductIds}
/>
</Shell>
)
Expand Down
6 changes: 3 additions & 3 deletions src/app/(lobby)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ export default async function IndexPage() {
<h2 className="text-2xl font-medium">
Join our newsletter to get the latest news and updates
</h2>
<a
href="/https://www.youtube.com/watch?v=dQw4w9WgXcQ"
<Link
href={"/https://www.youtube.com/watch?v=dQw4w9WgXcQ"}
target="_blank"
rel="noopener noreferrer"
>
Expand All @@ -165,7 +165,7 @@ export default async function IndexPage() {
<span className="sr-only">
Join our newsletter to get the latest news and updates
</span>
</a>
</Link>
</Card>
<div className="flex flex-wrap items-center justify-center gap-4">
{productCategories[
Expand Down
20 changes: 20 additions & 0 deletions src/app/_actions/cart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,26 @@ export async function getCartAction(): Promise<CartLineItem[]> {
return cartLineItems
}

export async function getCartItemsAction() {
const cartId = Number(cookies().get("cartId")?.value)

if (!cartId) {
throw new Error("cartId not found, please try again.")
}

if (isNaN(cartId)) {
throw new Error("Invalid cartId, please try again.")
}

const cart = await db.query.carts.findFirst({
where: eq(carts.id, cartId),
})

if (!cart) return []

return cart.items
}

export async function addToCartAction(input: CartItem) {
const cookieStore = cookies()
const cartId = Number(cookieStore.get("cartId")?.value)
Expand Down
16 changes: 9 additions & 7 deletions src/components/board-builder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ interface BoardBuilderProps {
products: Product[]
pageCount: number
subcategory: string | null
cartItemProductIds: number[]
cartProductIds: number[]
}

export function BoardBuilder({
products,
pageCount,
subcategory,
cartItemProductIds,
cartProductIds,
}: BoardBuilderProps) {
const router = useRouter()
const pathname = usePathname()
Expand Down Expand Up @@ -93,10 +93,12 @@ export function BoardBuilder({
// Add to cart
const addToCart = React.useCallback(
async (product: Product) => {
console.log(product.id)

try {
if (!cartItemProductIds.includes(product.id)) {
if (!cartProductIds.includes(product.id)) {
// Only allow one product per subcategory in cart
const productIdWithSameSubcategory = cartItemProductIds.find(
const productIdWithSameSubcategory = cartProductIds.find(
(id) =>
product.subcategory &&
products.find(
Expand Down Expand Up @@ -131,11 +133,11 @@ export function BoardBuilder({
: toast.error("Something went wrong, please try again.")
}
},
[cartItemProductIds, products, subcategory]
[cartProductIds, products, subcategory]
)

return (
<div className="flex flex-col space-y-6">
<div className="mt-4 flex flex-col space-y-6">
<div className="flex items-center space-x-2">
<Sheet>
<SheetTrigger asChild>
Expand Down Expand Up @@ -264,7 +266,7 @@ export function BoardBuilder({
key={product.id}
variant="switchable"
product={product}
isAddedToCart={cartItemProductIds.includes(product.id)}
isAddedToCart={cartProductIds.includes(product.id)}
onSwitch={() => addToCart(product)}
/>
))}
Expand Down
2 changes: 1 addition & 1 deletion src/components/combobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export function Combobox() {
<CommandItem
key={item.id}
onSelect={() =>
handleSelect(() => router.push(`/products/${item.id}`))
handleSelect(() => router.push(`/product/${item.id}`))
}
>
{item.name}
Expand Down
7 changes: 3 additions & 4 deletions src/components/layouts/site-footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,12 @@ export function SiteFooter() {
<div
className={cn(
buttonVariants({
size: "sm",
size: "icon",
variant: "ghost",
}),
"w-9 px-0"
})
)}
>
<Icons.gitHub className="h-5 w-5" />
<Icons.gitHub className="h-5 w-5" aria-hidden="true" />
<span className="sr-only">GitHub</span>
</div>
</Link>
Expand Down
22 changes: 17 additions & 5 deletions src/components/layouts/site-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { User } from "@clerk/nextjs/dist/types/server"
import { dashboardConfig } from "@/config/dashboard"
import { siteConfig } from "@/config/site"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Badge } from "@/components/ui/badge"
import { Button, buttonVariants } from "@/components/ui/button"
import {
DropdownMenu,
Expand All @@ -19,19 +20,22 @@ import { Combobox } from "@/components/combobox"
import { Icons } from "@/components/icons"
import { MainNav } from "@/components/layouts/main-nav"
import { MobileNav } from "@/components/layouts/mobile-nav"
import { getCartItemsAction } from "@/app/_actions/cart"

interface SiteHeaderProps {
user: User | null
}

export function SiteHeader({ user }: SiteHeaderProps) {
export async function SiteHeader({ user }: SiteHeaderProps) {
const initials = `${user?.firstName?.charAt(0) ?? ""} ${
user?.lastName?.charAt(0) ?? ""
}`
const email =
user?.emailAddresses?.find((e) => e.id === user.primaryEmailAddressId)
?.emailAddress ?? ""

const cartItems = await getCartItemsAction()

return (
<header className="sticky top-0 z-40 w-full border-b bg-background">
<div className="container flex h-16 items-center">
Expand All @@ -41,15 +45,23 @@ export function SiteHeader({ user }: SiteHeaderProps) {
sidebarNavItems={dashboardConfig.sidebarNav}
/>
<div className="flex flex-1 items-center justify-end space-x-4">
<nav className="flex items-center space-x-1">
<nav className="flex items-center space-x-2">
<Combobox />
<Button
aria-label="Cart"
variant="outline"
size="sm"
className="w-9 px-0"
size="icon"
className="relative"
>
<Icons.cart className="h-5 w-5" />
{cartItems?.length && (
<Badge
variant="secondary"
className="absolute -right-2 -top-2 h-6 w-6 rounded-full p-2"
>
{cartItems.reduce((acc, item) => acc + item.quantity, 0)}
</Badge>
)}
<Icons.cart className="h-5 w-5" aria-hidden="true" />
</Button>
{user ? (
<DropdownMenu>
Expand Down
3 changes: 1 addition & 2 deletions src/components/layouts/theme-toggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ export function ThemeToggle() {
return (
<Button
variant="ghost"
size="sm"
className="w-9 px-0"
size="icon"
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
>
<Icons.sun className="rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
Expand Down

0 comments on commit 1121b9e

Please sign in to comment.