import {CartForm, Image, Money} from '@shopify/hydrogen';
import type {CartLineUpdateInput} from '@shopify/hydrogen/storefront-api-types';
import {Link} from '@remix-run/react';
import type {CartApiQueryFragment} from 'storefrontapi.generated';
import {useVariantUrl} from '~/utils';
type CartLine = CartApiQueryFragment['lines']['nodes'][0];
type CartMainProps = {
cart: CartApiQueryFragment | null;
layout: 'page' | 'aside';
};
export function CartMain({layout, cart}: CartMainProps) {
const linesCount = Boolean(cart?.lines?.nodes?.length || 0);
const withDiscount =
cart &&
Boolean(cart.discountCodes.filter((code) => code.applicable).length);
const className = `cart-main ${withDiscount ? 'with-discount' : ''}`;
return (
);
}
function CartDetails({layout, cart}: CartMainProps) {
const cartHasItems = !!cart && cart.totalQuantity > 0;
return (
{cartHasItems && (
)}
);
}
function CartLines({
lines,
layout,
}: {
layout: CartMainProps['layout'];
lines: CartApiQueryFragment['lines'] | undefined;
}) {
if (!lines) return null;
return (
{lines.nodes.map((line) => (
))}
);
}
function CartLineItem({
layout,
line,
}: {
layout: CartMainProps['layout'];
line: CartLine;
}) {
const {id, merchandise} = line;
const {product, title, image, selectedOptions} = merchandise;
const lineItemUrl = useVariantUrl(product.handle, selectedOptions);
return (
{image && (
)}
{
if (layout === 'aside') {
// close the drawer
window.location.href = lineItemUrl;
}
}}
>
{product.title}
{selectedOptions.map((option) => (
-
{option.name}: {option.value}
))}
);
}
function CartCheckoutActions({checkoutUrl}: {checkoutUrl: string}) {
if (!checkoutUrl) return null;
return (
);
}
export function CartSummary({
cost,
layout,
children = null,
}: {
children?: React.ReactNode;
cost: CartApiQueryFragment['cost'];
layout: CartMainProps['layout'];
}) {
const className =
layout === 'page' ? 'cart-summary-page' : 'cart-summary-aside';
return (
Totals
- Subtotal
-
{cost?.subtotalAmount?.amount ? (
) : (
'-'
)}
{children}
);
}
function CartLineRemoveButton({lineIds}: {lineIds: string[]}) {
return (
);
}
function CartLineQuantity({line}: {line: CartLine}) {
if (!line || typeof line?.quantity === 'undefined') return null;
const {id: lineId, quantity} = line;
const prevQuantity = Number(Math.max(0, quantity - 1).toFixed(0));
const nextQuantity = Number((quantity + 1).toFixed(0));
return (
Quantity: {quantity}
);
}
function CartLinePrice({
line,
priceType = 'regular',
...passthroughProps
}: {
line: CartLine;
priceType?: 'regular' | 'compareAt';
[key: string]: any;
}) {
if (!line?.cost?.amountPerQuantity || !line?.cost?.totalAmount) return null;
const moneyV2 =
priceType === 'regular'
? line.cost.totalAmount
: line.cost.compareAtAmountPerQuantity;
if (moneyV2 == null) {
return null;
}
return (
);
}
export function CartEmpty({
hidden = false,
layout = 'aside',
}: {
hidden: boolean;
layout?: CartMainProps['layout'];
}) {
return (
Looks like you haven’t added anything yet, let’s get you
started!
{
if (layout === 'aside') {
window.location.href = '/collections';
}
}}
>
Continue shopping →
);
}
function CartDiscounts({
discountCodes,
}: {
discountCodes: CartApiQueryFragment['discountCodes'];
}) {
const codes: string[] =
discountCodes
?.filter((discount) => discount.applicable)
?.map(({code}) => code) || [];
return (
{/* Have existing discount, display it with a remove option */}
- Discount(s)
{codes?.join(', ')}
{/* Show an input to apply a discount */}
);
}
function UpdateDiscountForm({
discountCodes,
children,
}: {
discountCodes?: string[];
children: React.ReactNode;
}) {
return (
{children}
);
}
function CartLineUpdateButton({
children,
lines,
}: {
children: React.ReactNode;
lines: CartLineUpdateInput[];
}) {
return (
{children}
);
}