Skip to content

Commit

Permalink
Merge pull request Shopify#341 from Shopify/jl-better-evicted-cart-su…
Browse files Browse the repository at this point in the history
…pport

Add better evicted cart support
  • Loading branch information
jplhomer committed Jan 6, 2023
2 parents 44ec893 + 5e4f1d2 commit 83096b5
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 19 deletions.
15 changes: 10 additions & 5 deletions rfc/cart.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ export async function action({request, context}) {
const {session, storefront} = context;
const headers = new Headers();

const [formData, cartId] = await Promise.all([
const [formData, storedCartId] = await Promise.all([
request.formData(),
session.get('cartId'),
]);

let cartId = storedCartId;

const cartAction = formData.get('cartAction');
invariant(cartAction, 'No cartAction defined');

Expand All @@ -42,10 +44,6 @@ export async function action({request, context}) {
input: {lines},
storefront,
});

// cart created - we only need a Set-Cookie header if we're creating
session.set('cartId', result.cart.id);
headers.set('Set-Cookie', await session.commit());
} else {
// Add line(s) to existing cart
result = await cartAdd({
Expand All @@ -54,6 +52,9 @@ export async function action({request, context}) {
storefront,
});
}

cartId = result.cart.id;

break;
default:
invariant(false, `${cartAction} cart action is not defined`);
Expand All @@ -65,6 +66,10 @@ export async function action({request, context}) {
headers.set('Location', redirectTo);
}

// The Cart ID may change after each mutation. We need to update it each time in the session.
session.set('cartId', cartId);
headers.set('Set-Cookie', await session.commit());

const {cart, errors} = result;
return json({cart, errors}, {status, headers});
}
Expand Down
4 changes: 1 addition & 3 deletions templates/demo-store/app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ const CART_QUERY = `#graphql
export async function getCart({storefront}: AppLoadContext, cartId: string) {
invariant(storefront, 'missing storefront client in cart query');

const {cart} = await storefront.query<{cart: Cart}>(CART_QUERY, {
const {cart} = await storefront.query<{cart?: Cart}>(CART_QUERY, {
variables: {
cartId,
country: storefront.i18n?.country,
Expand All @@ -276,7 +276,5 @@ export async function getCart({storefront}: AppLoadContext, cartId: string) {
cache: storefront.CacheNone(),
});

invariant(cart, 'No data returned from Shopify API');

return cart;
}
34 changes: 23 additions & 11 deletions templates/demo-store/app/routes/cart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ export async function action({request, context}: ActionArgs) {
const {session, storefront} = context;
const headers = new Headers();

const [formData, cartId, customerAccessToken] = await Promise.all([
const [formData, storedCartId, customerAccessToken] = await Promise.all([
request.formData(),
session.get('cartId'),
session.get('customerAccessToken'),
]);

let cartId = storedCartId;

const cartAction = formData.get('cartAction') as CartActions;
invariant(cartAction, 'No cartAction defined');

Expand All @@ -49,24 +51,24 @@ export async function action({request, context}: ActionArgs) {
: ([] as CartLineInput[]);
invariant(lines.length, 'No lines to add');

//! Flow A — no previous cart, create and add line(s)
/**
* If no previous cart exists, create one with the lines.
*/
if (!cartId) {
result = await cartCreate({
input: countryCode ? {lines, buyerIdentity: {countryCode}} : {lines},
storefront,
});

// cart created - we only need a Set-Cookie header if we're creating
session.set('cartId', result.cart.id);
headers.set('Set-Cookie', await session.commit());
} else {
//! Flow B — add line(s) to existing cart
result = await cartAdd({
cartId,
lines,
storefront,
});
}

cartId = result.cart.id;

break;
case CartAction.REMOVE_FROM_CART:
const lineIds = formData.get('linesIds')
Expand All @@ -80,6 +82,8 @@ export async function action({request, context}: ActionArgs) {
storefront,
});

cartId = result.cart.id;

break;
case CartAction.UPDATE_CART:
const updateLines = formData.get('lines')
Expand All @@ -93,6 +97,8 @@ export async function action({request, context}: ActionArgs) {
storefront,
});

cartId = result.cart.id;

break;
case CartAction.UPDATE_DISCOUNT:
invariant(cartId, 'Missing cartId');
Expand All @@ -105,6 +111,9 @@ export async function action({request, context}: ActionArgs) {
discountCodes,
storefront,
});

cartId = result.cart.id;

break;
case CartAction.UPDATE_BUYER_IDENTITY:
const buyerIdentity = formData.get('buyerIdentity')
Expand All @@ -113,8 +122,6 @@ export async function action({request, context}: ActionArgs) {
) as CartBuyerIdentityInput)
: ({} as CartBuyerIdentityInput);

//! if we have an existing cart, we update the identity,
//! else we create a new cart with the passed identity
result = cartId
? await cartUpdateBuyerIdentity({
cartId,
Expand All @@ -134,14 +141,19 @@ export async function action({request, context}: ActionArgs) {
storefront,
});

session.set('cartId', result.cart.id);
headers.set('Set-Cookie', await session.commit());
cartId = result.cart.id;

break;
default:
invariant(false, `${cartAction} cart action is not defined`);
}

/**
* The Cart ID may change after each mutation. We need to update it each time in the session.
*/
session.set('cartId', cartId);
headers.set('Set-Cookie', await session.commit());

const redirectTo = formData.get('redirectTo') ?? null;
if (typeof redirectTo === 'string' && isLocalPath(redirectTo)) {
status = 303;
Expand Down

0 comments on commit 83096b5

Please sign in to comment.