-
Notifications
You must be signed in to change notification settings - Fork 286
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add magic cart and discount routes to skeleton template (#1309)
* add magic cart link route * add magic discount code route * update route map for cart cli generate command * add changeset * Update templates/skeleton/app/routes/cart.$lines.tsx Co-authored-by: Bret Little <[email protected]> --------- Co-authored-by: Bret Little <[email protected]>
- Loading branch information
1 parent
d8dc1ac
commit 33ae6ab
Showing
4 changed files
with
120 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
'@shopify/cli-hydrogen': patch | ||
'@shopify/create-hydrogen': patch | ||
--- | ||
|
||
Add magic cart and discount routes to skeleton template |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import {redirect, type LoaderArgs} from '@shopify/remix-oxygen'; | ||
|
||
/** | ||
* Automatically creates a new cart based on the URL and redirects straight to checkout. | ||
* Expected URL structure: | ||
* ```ts | ||
* /cart/<variant_id>:<quantity> | ||
* | ||
* ``` | ||
* More than one `<variant_id>:<quantity>` separated by a comma, can be supplied in the URL, for | ||
* carts with more than one product variant. | ||
* | ||
* @param `?discount` an optional discount code to apply to the cart | ||
* @example | ||
* Example path creating a cart with two product variants, different quantities, and a discount code: | ||
* ```ts | ||
* /cart/41007289663544:1,41007289696312:2?discount=HYDROBOARD | ||
* | ||
* ``` | ||
* @preserve | ||
*/ | ||
export async function loader({request, context, params}: LoaderArgs) { | ||
const {cart} = context; | ||
const {lines} = params; | ||
if (!lines) return redirect('/cart'); | ||
const linesMap = lines.split(',').map((line) => { | ||
const lineDetails = line.split(':'); | ||
const variantId = lineDetails[0]; | ||
const quantity = parseInt(lineDetails[1], 10); | ||
|
||
return { | ||
merchandiseId: `gid://shopify/ProductVariant/${variantId}`, | ||
quantity, | ||
}; | ||
}); | ||
|
||
const url = new URL(request.url); | ||
const searchParams = new URLSearchParams(url.search); | ||
|
||
const discount = searchParams.get('discount'); | ||
const discountArray = discount ? [discount] : []; | ||
|
||
// create a cart | ||
const result = await cart.create({ | ||
lines: linesMap, | ||
discountCodes: discountArray, | ||
}); | ||
|
||
const cartResult = result.cart; | ||
|
||
if (result.errors?.length || !cartResult) { | ||
throw new Response('Link may be expired. Try checking the URL.', { | ||
status: 410, | ||
}); | ||
} | ||
|
||
// Update cart id in cookie | ||
const headers = cart.setCartId(cartResult.id); | ||
|
||
// redirect to checkout | ||
if (cartResult.checkoutUrl) { | ||
return redirect(cartResult.checkoutUrl, {headers}); | ||
} else { | ||
throw new Error('No checkout URL found'); | ||
} | ||
} | ||
|
||
export default function Component() { | ||
return null; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import {redirect, type LoaderArgs} from '@shopify/remix-oxygen'; | ||
|
||
/** | ||
* Automatically applies a discount found on the url | ||
* If a cart exists it's updated with the discount, otherwise a cart is created with the discount already applied | ||
* @param ?redirect an optional path to return to otherwise return to the home page | ||
* @example | ||
* Example path applying a discount and redirecting | ||
* ```ts | ||
* /discount/FREESHIPPING?redirect=/products | ||
* | ||
* ``` | ||
* @preserve | ||
*/ | ||
export async function loader({request, context, params}: LoaderArgs) { | ||
const {cart} = context; | ||
const {code} = params; | ||
|
||
const url = new URL(request.url); | ||
const searchParams = new URLSearchParams(url.search); | ||
const redirectParam = | ||
searchParams.get('redirect') || searchParams.get('return_to') || '/'; | ||
|
||
searchParams.delete('redirect'); | ||
searchParams.delete('return_to'); | ||
|
||
const redirectUrl = `${redirectParam}?${searchParams}`; | ||
|
||
if (!code) { | ||
return redirect(redirectUrl); | ||
} | ||
|
||
const result = await cart.updateDiscountCodes([code]); | ||
const headers = cart.setCartId(result.cart.id); | ||
|
||
// Using set-cookie on a 303 redirect will not work if the domain origin have port number (:3000) | ||
// If there is no cart id and a new cart id is created in the progress, it will not be set in the cookie | ||
// on localhost:3000 | ||
return redirect(redirectUrl, { | ||
status: 303, | ||
headers, | ||
}); | ||
} |