Frontend
You will allow users to add and remove items from their cart.
To achieve this, you will first write a GraphQL document to increase and decrease cart items. Then create icons to put on the buttons that update items quantity. And finally you will use the autogenerated mutation hooks in the cart item component.
Create two documents on the documents
folder to call the increaseCartItem and decreaseCartItem mutations.
First create IncreaseCartItem.graphql
:
# import Cart from "./CartFragment"
mutation increaseCartItem($input: IncreaseCartItemInput!) {
increaseCartItem(input: $input) {
...Cart
}
}
The create DecreaseCartItem.graphql
:
# import Cart from "./CartFragment"
mutation decreaseCartItem($input: DecreaseCartItemInput!) {
decreaseCartItem(input: $input) {
...Cart
}
}
Finally run yarn codegen
to update types.ts
.
Now you will create two icons to place on the update quantity buttons.
They will be outlined plus and minus icons, taken from the awesomely handy heroicons library.
Create a file inside components
called PlusIcon.tsx
:
export function PlusIcon() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 4v16m8-8H4"
/>
</svg>
);
}
Now create MinusIcon.tsx
:
export function MinusIcon() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M20 12H4"
/>
</svg>
);
}
With both hooks and icons, you have all the tools you need to add two update quantity buttons to CartItem
.
Call both useDecreaseCartItemMutation
and useIncreaseCartItemMutation
on the top of the component, and make them refetch the GetCartDocument
query once their mutations finish.
After that add an increase and a decrease item buttons, which will call the increaseCartItem
and decreaseCartItem
functions that the hooks returned. You will also add a disabled
property to them so that they are non clickable when the associated mutation is loading.
This is what CartItem.tsx
should look like with those additions:
import Image from "next/image";
import {
CartItem,
GetCartDocument,
useDecreaseCartItemMutation,
useIncreaseCartItemMutation,
} from "../types";
import { MinusIcon } from "./MinusIcon";
import { PlusIcon } from "./PlusIcon";
export function CartItem({ item, cartId }: { item: CartItem; cartId: string }) {
const [increaseCartItem, { loading: increasingCartItem }] =
useIncreaseCartItemMutation({
refetchQueries: [GetCartDocument],
});
const [decreaseCartItem, { loading: decreasingCartItem }] =
useDecreaseCartItemMutation({
refetchQueries: [GetCartDocument],
});
return (
<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>
<button
onClick={() =>
decreaseCartItem({
variables: { input: { id: item.id, cartId } },
})
}
disabled={decreasingCartItem}
className="p-1 font-light border border-neutral-700 hover:bg-black hover:text-white"
>
<MinusIcon />
</button>
<button
onClick={() =>
increaseCartItem({
variables: { input: { id: item.id, cartId } },
})
}
disabled={increasingCartItem}
className="p-1 font-light border border-neutral-700 hover:bg-black hover:text-white"
>
<PlusIcon />
</button>
</div>
</div>
</div>
);
}
Make sure to update CartDetail
with the new cartId
required property in CartItem
.
CartDetail.tsx
<CartItem key={item.id} item={item} cartId={cart.id} />
Try the new update quantity flow by navigating to the cart summary page and adding and removing items.