Template
Redesign cart and collections, fix product pagination
- Cart drawer: single-column layout matching the site — no bag icon, no dividers, square images, tighter type, discount code form, estimated total, and a Go to Checkout button - Cart: per-line loading state so one row's update no longer disables every other row or the checkout button - Discounts: cartDiscountCodesUpdate mutation plus discountCodes on the cart fragment, wired to an applyDiscountCode store action - Products: fix "load more" returning the same first page — the query now takes an `after` cursor and getProductsPage exposes pageInfo - Collections: cards match the product cards (no border, radius, blurb, or CTA row) at 4-up on desktop and 2-up on mobile; section headers match the products section - Shop Pay: cart permalink with payment=shop_pay instead of the hosted shop-js element - Buttons converted to the shadcn Button component throughout - PDP: swipeable image carousel with dots on mobile, sticky info column, colour swatches never fall back to variant photos - Rename the store from Stride to Shop; larger header wordmark Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jWbNNJLksC1QG8z8845FX
This commit is contained in:
co-authored by
Claude Opus 5
parent
69f7435d6e
commit
e04f1e0405
@@ -7,6 +7,7 @@ import {
|
||||
ADD_CART_LINES_MUTATION,
|
||||
UPDATE_CART_LINES_MUTATION,
|
||||
REMOVE_CART_LINES_MUTATION,
|
||||
UPDATE_CART_DISCOUNT_CODES_MUTATION,
|
||||
GET_CART_QUERY,
|
||||
} from '@/graphql/cart';
|
||||
import { useEffect } from 'react';
|
||||
@@ -59,10 +60,16 @@ interface CartLine {
|
||||
};
|
||||
}
|
||||
|
||||
export interface CartDiscountCode {
|
||||
code: string;
|
||||
applicable: boolean;
|
||||
}
|
||||
|
||||
export interface Cart {
|
||||
id: string;
|
||||
checkoutUrl: string;
|
||||
totalQuantity: number;
|
||||
discountCodes?: CartDiscountCode[];
|
||||
cost: {
|
||||
subtotalAmount: {
|
||||
amount: string;
|
||||
@@ -147,6 +154,24 @@ async function removeCartLinesApi(
|
||||
return response.data.cartLinesRemove.cart;
|
||||
}
|
||||
|
||||
async function updateCartDiscountCodesApi(
|
||||
cartId: string,
|
||||
discountCodes: string[]
|
||||
): Promise<Cart> {
|
||||
const response = await shopifyFetch({
|
||||
query: UPDATE_CART_DISCOUNT_CODES_MUTATION,
|
||||
variables: { cartId, discountCodes },
|
||||
});
|
||||
|
||||
if (response.data.cartDiscountCodesUpdate.userErrors.length > 0) {
|
||||
throw new Error(
|
||||
response.data.cartDiscountCodesUpdate.userErrors[0].message
|
||||
);
|
||||
}
|
||||
|
||||
return response.data.cartDiscountCodesUpdate.cart;
|
||||
}
|
||||
|
||||
async function getCartApi(cartId: string): Promise<Cart | null> {
|
||||
const response = await shopifyFetch({
|
||||
query: GET_CART_QUERY,
|
||||
@@ -186,6 +211,7 @@ interface CartState {
|
||||
addItem: (variantId: string, quantity?: number) => Promise<Cart>;
|
||||
removeItem: (lineId: string) => Promise<Cart>;
|
||||
updateItemQuantity: (lineId: string, quantity: number) => Promise<Cart>;
|
||||
applyDiscountCode: (code: string) => Promise<Cart>;
|
||||
refreshCart: () => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -312,6 +338,29 @@ export const useCartStore = create<CartState>((set, get) => ({
|
||||
}
|
||||
},
|
||||
|
||||
// Apply a discount code. Shopify accepts unknown codes and reports them back
|
||||
// as `applicable: false`, so callers should check the returned cart.
|
||||
applyDiscountCode: async (code: string) => {
|
||||
const { cartId } = get();
|
||||
if (!cartId) throw new Error('No cart exists');
|
||||
|
||||
try {
|
||||
set({ loading: true, error: null });
|
||||
const trimmed = code.trim();
|
||||
const updatedCart = await updateCartDiscountCodesApi(
|
||||
cartId,
|
||||
trimmed ? [trimmed] : []
|
||||
);
|
||||
set({ cart: updatedCart, loading: false });
|
||||
return updatedCart;
|
||||
} catch (err) {
|
||||
const errorMessage =
|
||||
err instanceof Error ? err.message : 'Failed to apply discount code';
|
||||
set({ error: errorMessage, loading: false });
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
// Refresh cart from Shopify
|
||||
refreshCart: async () => {
|
||||
const storedCartId = localStorage.getItem(CART_ID_KEY);
|
||||
@@ -374,6 +423,7 @@ export function useShopifyCart() {
|
||||
addItem: store.addItem,
|
||||
removeItem: store.removeItem,
|
||||
updateItemQuantity: store.updateItemQuantity,
|
||||
applyDiscountCode: store.applyDiscountCode,
|
||||
refreshCart: store.refreshCart,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user