Frontend
Let's improve the cart summary page and display a list of cart items along with the cart subtotal, with pictures and prices.
This will also be a good opportunity to create a cart detail component to handle these features.
Modify the cart page by replacing the elements that show the subtotal with a CartDetail
component, which you will create afterwards.
Import the CartDetail
component and render it in cart.tsx
. It will receive a cart property.
// ...
import { CartDetail } from "../components/CartDetail";
const Cart: NextPage<IProps> = ({ cartId }) => {
const { data } = useGetCartQuery({ variables: { id: cartId } });
return (
<div className="min-h-screen flex flex-col">
<Header />
<main className="p-8 min-h-screen">
<div className="mx-auto max-w-xl space-y-8">
<h1 className="text-4xl">Cart</h1>
<CartDetail cart={data?.cart} />
</div>
</main>
</div>
);
};
// ...
Create a file called CartDetail.tsx
inside the components
folder. This file exports a function called CartDetail
, which receives a cart
prop with a type CartFragment
from the autogenerated types file.
This component displays a CartItem
component for every item from the cart
property. It also displays cart Subtotal and Total, with a bit of space and borders between them.
import { CartFragment } from "../types";
import { CartItem } from "./CartDetail";
export function CartDetail({
cart,
}: {
cart: CartFragment | null | undefined;
}) {
return (
<div>
<div className={`space-y-8 relative`}>
{cart?.items.map((item) => (
<CartItem key={item.id} item={item} />
))}
</div>
<div className="border-t my-4 border-neutral-700 pt-4">
<div className="flex justify-between">
<div>Subtotal</div>
<div>{cart?.subTotal.formatted}</div>
</div>
</div>
<div className="border-t border-neutral-700 pt-4">
<div className="flex justify-between font-bold">
<div>Total</div>
<div className="">{cart?.subTotal.formatted}</div>
</div>
</div>
</div>
);
}
The final step to make this cart summary page work is creating the CartItem.tsx
component. It will take an item
prop and use it's data to display an image, name, subtotal and quantity.
import Image from "next/image";
import { CartItem } from "../types";
export function CartItem({ item }: { item: CartItem }) {
return (
<div className="space-y-2">
<div className="flex gap-4">
<Image
src={item.image || ""}
width={75}
height={75}
alt={item.name}
objectFit="cover"
/>
<div className="flex justify-between items-baseline flex-1 gap-2">
<span className="text-lg">{item.name}</span>
<span className="text-sm font-light">{item.unitTotal.formatted}</span>
</div>
</div>
<div className="flex gap-2">
<div className="flex-1 flex">
<div className="px-2 py-1 font-light border border-neutral-700 flex-1">
{item.quantity}
</div>
</div>
</div>
</div>
);
}
To try this out go to http://localhost:3000 and see what the cart item list looks like.