refactor: cart button with icon

This commit is contained in:
Nam Doan
2025-12-08 11:29:41 +07:00
parent 043cc4d11a
commit d8e78b71e4
5 changed files with 265 additions and 44 deletions
@@ -1,8 +1,8 @@
import { retrieveCart } from "@lib/data/cart"
import CartDropdown from "../cart-dropdown"
export default async function CartButton() {
export default async function CartButton({ iconName }: { iconName?: string }) {
const cart = await retrieveCart().catch(() => null)
return <CartDropdown cart={cart} />
return <CartDropdown cart={cart} iconName={iconName} />
}
@@ -9,6 +9,7 @@ import {
import { convertToLocale } from "@lib/util/money"
import { HttpTypes } from "@medusajs/types"
import { Button } from "@medusajs/ui"
import * as MedusaIcons from "@medusajs/icons"
import DeleteButton from "@modules/common/components/delete-button"
import LineItemOptions from "@modules/common/components/line-item-options"
import LineItemPrice from "@modules/common/components/line-item-price"
@@ -19,8 +20,10 @@ import { Fragment, useEffect, useRef, useState } from "react"
const CartDropdown = ({
cart: cartState,
iconName,
}: {
cart?: HttpTypes.StoreCart | null
iconName?: string
}) => {
const [activeTimer, setActiveTimer] = useState<NodeJS.Timer | undefined>(
undefined
@@ -73,6 +76,10 @@ const CartDropdown = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [totalItems, itemRef.current])
const Icon = iconName
? (MedusaIcons as Record<string, React.ComponentType<any>>)[iconName]
: undefined
return (
<div
className="h-full z-50"
@@ -81,11 +88,15 @@ const CartDropdown = ({
>
<Popover className="relative h-full">
<PopoverButton className="h-full">
<LocalizedClientLink
className="hover:text-ui-fg-base"
href="/cart"
data-testid="nav-cart-link"
>{`Cart (${totalItems})`}</LocalizedClientLink>
{Icon ? (
<Icon />
) : (
<LocalizedClientLink
className="hover:text-ui-fg-base"
href="/cart"
data-testid="nav-cart-link"
>{`Cart (${totalItems})`}</LocalizedClientLink>
)}
</PopoverButton>
<Transition
show={cartDropdownOpen}
@@ -1,27 +1,39 @@
import LocalizedClientLink from "@modules/common/components/localized-client-link"
import { LayoutComponentDefinition, LayoutContext } from "vibentec/component-map";
import {
LayoutComponentDefinition,
LayoutContext,
} from "vibentec/component-map"
import { clx } from "@medusajs/ui"
export const AccountButton = ({ nodes, context }: { nodes: LayoutComponentDefinition; context: LayoutContext }) => {
import * as MedusaIcons from "@medusajs/icons"
export const AccountButton = ({
nodes,
context,
}: {
nodes: LayoutComponentDefinition
context: LayoutContext
}) => {
const props = nodes.config ?? {}
const className = clx("hover:text-ui-fg-base", props.className);
const style: React.CSSProperties = {};
if (props.bgColor) style.backgroundColor = props.bgColor;
if (props.textColor) style.color = props.textColor;
const className = clx("hover:text-ui-fg-base", props.className)
const style: React.CSSProperties = {}
if (props.bgColor) style.backgroundColor = props.bgColor
if (props.textColor) style.color = props.textColor
const href = props.href ?? "/account"
const label = props.label ?? "Account"
const iconName = props.icon
const Icon = iconName
? (MedusaIcons as Record<string, React.ComponentType<any>>)[iconName]
: undefined
return (
<div className="flex items-center h-full" style={style}>
<div className="flex items-center h-full">
<LocalizedClientLink
href={href}
className={className}
data-testid="nav-account-link"
>
{label}
{Icon ? <Icon /> : label}
</LocalizedClientLink>
</div>
</div>
)
}
export default AccountButton
export default AccountButton
@@ -3,23 +3,9 @@ import {
LayoutComponentDefinition,
LayoutContext,
} from "vibentec/component-map"
import { clx, IconButton } from "@medusajs/ui"
import { clx } from "@medusajs/ui"
import { Suspense } from "react"
import CartButton from "@modules/layout/components/cart-button"
import { ShoppingBag, ShoppingCart } from "@medusajs/icons"
const IconButtonComponent = ({ className, variant }: { className?: string; variant?: "shoppingBag" | "cart" }) => {
const variants = {
shoppingBag: ShoppingBag,
cart: ShoppingCart,
}
const Icon = variants[variant ?? "shoppingBag"]
return (
<IconButton className={className}>
<Icon />
</IconButton>
)
}
export const VtCartButton = ({
nodes,
@@ -30,15 +16,6 @@ export const VtCartButton = ({
}) => {
const props = nodes.config ?? {}
const className = clx("hover:text-ui-fg-base flex gap-2", props.className)
const variants = {
link: <CartButton />,
shoppingBagbutton: <IconButtonComponent className={className} variant="shoppingBag" />,
cartIconButton: <IconButtonComponent className={className} variant="cart" />,
}
if (!props.variant) return null
const fallBackComp = variants[props.variant as keyof typeof variants]
return (
<Suspense
fallback={
@@ -51,7 +28,7 @@ export const VtCartButton = ({
</LocalizedClientLink>
}
>
{fallBackComp}
<CartButton iconName={props.icon} />
</Suspense>
)
}