diff --git a/accounts/shopify.ts b/accounts/shopify.ts index 82bcbbff..ec05d91f 100644 --- a/accounts/shopify.ts +++ b/accounts/shopify.ts @@ -1,7 +1,2 @@ -import type { ConfigShopify } from "../commerce/shopify/client.ts"; - -function ShopifyAccount(acc: ConfigShopify) { - return acc; -} - -export default ShopifyAccount; +export type { Context } from "deco-sites/std/packs/shopify/accounts/shopify.ts"; +export { default } from "deco-sites/std/packs/shopify/accounts/shopify.ts"; diff --git a/actions/shopify/cart/addItems.ts b/actions/shopify/cart/addItems.ts new file mode 100644 index 00000000..6a7543be --- /dev/null +++ b/actions/shopify/cart/addItems.ts @@ -0,0 +1 @@ +export { default } from "deco-sites/std/packs/shopify/actions/cart/addItems.ts"; diff --git a/actions/shopify/cart/updateCoupons.ts b/actions/shopify/cart/updateCoupons.ts new file mode 100644 index 00000000..34cbee3e --- /dev/null +++ b/actions/shopify/cart/updateCoupons.ts @@ -0,0 +1 @@ +export { default } from "deco-sites/std/packs/shopify/actions/cart/updateCoupons.ts"; diff --git a/actions/shopify/cart/updateItems.ts b/actions/shopify/cart/updateItems.ts new file mode 100644 index 00000000..5cb8a807 --- /dev/null +++ b/actions/shopify/cart/updateItems.ts @@ -0,0 +1 @@ +export { default } from "deco-sites/std/packs/shopify/actions/cart/updateItems.ts"; diff --git a/doccache.zst b/doccache.zst index d40a1529..130c229f 100644 Binary files a/doccache.zst and b/doccache.zst differ diff --git a/live.gen.ts b/live.gen.ts index 498233bb..0036adb1 100644 --- a/live.gen.ts +++ b/live.gen.ts @@ -2,108 +2,112 @@ // This file SHOULD be checked into source version control. // This file is automatically updated during development when running `dev.ts`. -import * as $0 from "./functions/butterCMSPosts.ts"; -import * as $1 from "./functions/butterCMSPage.ts"; -import * as $2 from "./functions/vtexProductListingPage.ts"; -import * as $3 from "./functions/vndaProductList.ts"; -import * as $4 from "./functions/butterCMSAds.ts"; -import * as $5 from "./functions/butterCMSPostDetail.ts"; -import * as $6 from "./functions/vndaProductDetailsPage.ts"; -import * as $7 from "./functions/vtexLegacyProductDetailsPage.ts"; -import * as $8 from "./functions/vtexSuggestions.ts"; -import * as $9 from "./functions/vtexNavbar.ts"; -import * as $10 from "./functions/butterCMSPlaces.ts"; -import * as $11 from "./functions/vtexWishlist.ts"; -import * as $12 from "./functions/shopifyProductListingPage.ts"; -import * as $13 from "./functions/vtexProductList.ts"; -import * as $14 from "./functions/butterCMSFeaturedPosts.ts"; -import * as $15 from "./functions/occProductDetailsPage.ts"; -import * as $16 from "./functions/butterCMSBrands.ts"; -import * as $17 from "./functions/vndaProductListingPage.ts"; -import * as $18 from "./functions/butterCMSRelatedPosts.ts"; +import * as $0 from "./functions/butterCMSAds.ts"; +import * as $1 from "./functions/butterCMSBrands.ts"; +import * as $2 from "./functions/butterCMSCategories.ts"; +import * as $3 from "./functions/butterCMSFeaturedPosts.ts"; +import * as $4 from "./functions/butterCMSPage.ts"; +import * as $5 from "./functions/butterCMSPlaces.ts"; +import * as $6 from "./functions/butterCMSPostDetail.ts"; +import * as $7 from "./functions/butterCMSPosts.ts"; +import * as $8 from "./functions/butterCMSRelatedPosts.ts"; +import * as $9 from "./functions/occProductDetailsPage.ts"; +import * as $10 from "./functions/requestToParam.ts"; +import * as $11 from "./functions/shopifyProductDetailsPage.ts"; +import * as $12 from "./functions/shopifyProductList.ts"; +import * as $13 from "./functions/shopifyProductListingPage.ts"; +import * as $14 from "./functions/vndaProductDetailsPage.ts"; +import * as $15 from "./functions/vndaProductList.ts"; +import * as $16 from "./functions/vndaProductListingPage.ts"; +import * as $17 from "./functions/vtexLegacyProductDetailsPage.ts"; +import * as $18 from "./functions/vtexLegacyProductList.ts"; import * as $19 from "./functions/vtexLegacyProductListingPage.ts"; -import * as $20 from "./functions/vtexProductDetailsPage.ts"; -import * as $21 from "./functions/vtexLegacyProductList.ts"; -import * as $22 from "./functions/butterCMSCategories.ts"; -import * as $23 from "./functions/shopifyProductList.ts"; -import * as $24 from "./functions/shopifyProductDetailsPage.ts"; -import * as $25 from "./functions/vtexLegacyRelatedProductsLoader.ts"; -import * as $26 from "./functions/requestToParam.ts"; +import * as $20 from "./functions/vtexLegacyRelatedProductsLoader.ts"; +import * as $21 from "./functions/vtexNavbar.ts"; +import * as $22 from "./functions/vtexProductDetailsPage.ts"; +import * as $23 from "./functions/vtexProductList.ts"; +import * as $24 from "./functions/vtexProductListingPage.ts"; +import * as $25 from "./functions/vtexSuggestions.ts"; +import * as $26 from "./functions/vtexWishlist.ts"; import * as $$0 from "./accounts/butterCMS.ts"; import * as $$1 from "./accounts/linxImpulse.ts"; -import * as $$2 from "./accounts/vnda.ts"; -import * as $$3 from "./accounts/nuvemShop.ts"; -import * as $$4 from "./accounts/yourViews.ts"; -import * as $$5 from "./accounts/vtex.ts"; -import * as $$6 from "./accounts/shopify.ts"; -import * as $$7 from "./accounts/occ.ts"; -import * as $$$0 from "./loaders/linxImpulse/products/similarItems.ts"; -import * as $$$1 from "./loaders/linxImpulse/search.ts"; -import * as $$$2 from "./loaders/linxImpulse/autocompletes/popular.ts"; -import * as $$$3 from "./loaders/linxImpulse/autocompletes/suggestions.ts"; -import * as $$$4 from "./loaders/linxImpulse/pages/recommendations.ts"; -import * as $$$5 from "./loaders/vtex/legacy/productList.ts"; -import * as $$$6 from "./loaders/vtex/legacy/productDetailsPage.ts"; -import * as $$$7 from "./loaders/vtex/legacy/productListingPage.ts"; -import * as $$$8 from "./loaders/vtex/legacy/relatedProductsLoader.ts"; -import * as $$$9 from "./loaders/vtex/wishlist.ts"; -import * as $$$10 from "./loaders/vtex/navbar.ts"; -import * as $$$11 from "./loaders/vtex/proxy.ts"; -import * as $$$12 from "./loaders/vtex/intelligentSearch/productList.ts"; -import * as $$$13 from "./loaders/vtex/intelligentSearch/productDetailsPage.ts"; -import * as $$$14 from "./loaders/vtex/intelligentSearch/productListingPage.ts"; -import * as $$$15 from "./loaders/vtex/intelligentSearch/suggestions.ts"; -import * as $$$16 from "./loaders/vtex/cart.ts"; -import * as $$$17 from "./loaders/vtex/user.ts"; -import * as $$$18 from "./loaders/vnda/productList.ts"; -import * as $$$19 from "./loaders/vnda/productDetailsPage.ts"; -import * as $$$20 from "./loaders/vnda/productListingPage.ts"; -import * as $$$21 from "./loaders/vnda/proxy.ts"; -import * as $$$22 from "./loaders/vnda/cart.ts"; -import * as $$$23 from "./loaders/nuvemShop/nuvemShopProductDetailsPage.ts"; -import * as $$$24 from "./loaders/nuvemShop/nuvemShopProductList.ts"; -import * as $$$25 from "./loaders/nuvemShop/nuvemShopProductListingPage.ts"; -import * as $$$26 from "./loaders/x/image.ts"; -import * as $$$27 from "./loaders/x/redirectsFromCsv.ts"; -import * as $$$28 from "./loaders/x/font.ts"; +import * as $$2 from "./accounts/nuvemShop.ts"; +import * as $$3 from "./accounts/occ.ts"; +import * as $$4 from "./accounts/shopify.ts"; +import * as $$5 from "./accounts/vnda.ts"; +import * as $$6 from "./accounts/vtex.ts"; +import * as $$7 from "./accounts/yourViews.ts"; +import * as $$$0 from "./loaders/linxImpulse/autocompletes/popular.ts"; +import * as $$$1 from "./loaders/linxImpulse/autocompletes/suggestions.ts"; +import * as $$$2 from "./loaders/linxImpulse/pages/recommendations.ts"; +import * as $$$3 from "./loaders/linxImpulse/products/similarItems.ts"; +import * as $$$4 from "./loaders/linxImpulse/search.ts"; +import * as $$$5 from "./loaders/nuvemShop/nuvemShopProductDetailsPage.ts"; +import * as $$$6 from "./loaders/nuvemShop/nuvemShopProductList.ts"; +import * as $$$7 from "./loaders/nuvemShop/nuvemShopProductListingPage.ts"; +import * as $$$8 from "./loaders/shopify/cart.ts"; +import * as $$$9 from "./loaders/vnda/cart.ts"; +import * as $$$10 from "./loaders/vnda/productDetailsPage.ts"; +import * as $$$11 from "./loaders/vnda/productList.ts"; +import * as $$$12 from "./loaders/vnda/productListingPage.ts"; +import * as $$$13 from "./loaders/vnda/proxy.ts"; +import * as $$$14 from "./loaders/vtex/cart.ts"; +import * as $$$15 from "./loaders/vtex/intelligentSearch/productDetailsPage.ts"; +import * as $$$16 from "./loaders/vtex/intelligentSearch/productList.ts"; +import * as $$$17 from "./loaders/vtex/intelligentSearch/productListingPage.ts"; +import * as $$$18 from "./loaders/vtex/intelligentSearch/suggestions.ts"; +import * as $$$19 from "./loaders/vtex/legacy/productDetailsPage.ts"; +import * as $$$20 from "./loaders/vtex/legacy/productList.ts"; +import * as $$$21 from "./loaders/vtex/legacy/productListingPage.ts"; +import * as $$$22 from "./loaders/vtex/legacy/relatedProductsLoader.ts"; +import * as $$$23 from "./loaders/vtex/navbar.ts"; +import * as $$$24 from "./loaders/vtex/proxy.ts"; +import * as $$$25 from "./loaders/vtex/user.ts"; +import * as $$$26 from "./loaders/vtex/wishlist.ts"; +import * as $$$27 from "./loaders/x/font.ts"; +import * as $$$28 from "./loaders/x/image.ts"; +import * as $$$29 from "./loaders/x/redirectsFromCsv.ts"; import * as $$$$0 from "./routes/404.tsx"; import * as $$$$1 from "./routes/styles.css.ts"; import * as $$$$2 from "./routes/_app.tsx"; -import * as $$$$$$0 from "./handlers/vtex/sitemap.ts"; -import * as $$$$$$1 from "./handlers/sitemap.ts"; -import * as $$$$$$$$0 from "./sections/configYourViews.global.tsx"; +import * as $$$$$$0 from "./handlers/sitemap.ts"; +import * as $$$$$$1 from "./handlers/vtex/sitemap.ts"; +import * as $$$$$$$$0 from "./sections/Analytics.tsx"; import * as $$$$$$$$1 from "./sections/configButterCMS.global.tsx"; -import * as $$$$$$$$2 from "./sections/SEO.tsx"; +import * as $$$$$$$$2 from "./sections/configLinxImpulse.global.tsx"; import * as $$$$$$$$3 from "./sections/configNuvemShop.tsx"; -import * as $$$$$$$$4 from "./sections/configLinxImpulse.global.tsx"; -import * as $$$$$$$$5 from "./sections/SEOPLP.tsx"; -import * as $$$$$$$$6 from "./sections/configOCC.global.tsx"; -import * as $$$$$$$$7 from "./sections/Analytics.tsx"; -import * as $$$$$$$$8 from "./sections/configShopify.global.tsx"; -import * as $$$$$$$$9 from "./sections/VTEXPortalDataLayerCompatibility.tsx"; -import * as $$$$$$$$10 from "./sections/configVTEX.global.tsx"; -import * as $$$$$$$$11 from "./sections/SEOPDP.tsx"; -import * as $$$$$$$$$$$0 from "./actions/vtex/notifyme.ts"; -import * as $$$$$$$$$$$1 from "./actions/vtex/cart/updateCoupons.ts"; -import * as $$$$$$$$$$$2 from "./actions/vtex/cart/updateAttachment.ts"; -import * as $$$$$$$$$$$3 from "./actions/vtex/cart/updateItems.ts"; -import * as $$$$$$$$$$$4 from "./actions/vtex/cart/updateItemAttachment.ts"; -import * as $$$$$$$$$$$5 from "./actions/vtex/cart/updateUser.ts"; -import * as $$$$$$$$$$$6 from "./actions/vtex/cart/addItems.ts"; -import * as $$$$$$$$$$$7 from "./actions/vtex/cart/removeItems.ts"; -import * as $$$$$$$$$$$8 from "./actions/vtex/cart/getInstallment.ts"; -import * as $$$$$$$$$$$9 from "./actions/vtex/cart/updateItemPrice.ts"; -import * as $$$$$$$$$$$10 from "./actions/vtex/cart/updateProfile.ts"; -import * as $$$$$$$$$$$11 from "./actions/vtex/cart/simulation.ts"; -import * as $$$$$$$$$$$12 from "./actions/vtex/cart/removeItemAttachment.ts"; -import * as $$$$$$$$$$$13 from "./actions/vtex/newsletter/subscribe.ts"; -import * as $$$$$$$$$$$14 from "./actions/vtex/wishlist/removeItem.ts"; -import * as $$$$$$$$$$$15 from "./actions/vtex/wishlist/addItem.ts"; -import * as $$$$$$$$$$$16 from "./actions/vtex/analytics/sendEvent.ts"; -import * as $$$$$$$$$$$17 from "./actions/vnda/cart/updateItem.ts"; -import * as $$$$$$$$$$$18 from "./actions/vnda/cart/setShippingAddress.ts"; -import * as $$$$$$$$$$$19 from "./actions/vnda/cart/addItem.ts"; -import * as $$$$$$$$$$$20 from "./actions/vnda/cart/updateCoupon.ts"; +import * as $$$$$$$$4 from "./sections/configOCC.global.tsx"; +import * as $$$$$$$$5 from "./sections/configShopify.global.tsx"; +import * as $$$$$$$$6 from "./sections/configVTEX.global.tsx"; +import * as $$$$$$$$7 from "./sections/configYourViews.global.tsx"; +import * as $$$$$$$$8 from "./sections/SEO.tsx"; +import * as $$$$$$$$9 from "./sections/SEOPDP.tsx"; +import * as $$$$$$$$10 from "./sections/SEOPLP.tsx"; +import * as $$$$$$$$11 from "./sections/VTEXPortalDataLayerCompatibility.tsx"; +import * as $$$$$$$$$$$0 from "./actions/shopify/cart/addItems.ts"; +import * as $$$$$$$$$$$1 from "./actions/shopify/cart/updateCoupons.ts"; +import * as $$$$$$$$$$$2 from "./actions/shopify/cart/updateItems.ts"; +import * as $$$$$$$$$$$3 from "./actions/vnda/cart/addItem.ts"; +import * as $$$$$$$$$$$4 from "./actions/vnda/cart/setShippingAddress.ts"; +import * as $$$$$$$$$$$5 from "./actions/vnda/cart/updateCoupon.ts"; +import * as $$$$$$$$$$$6 from "./actions/vnda/cart/updateItem.ts"; +import * as $$$$$$$$$$$7 from "./actions/vtex/analytics/sendEvent.ts"; +import * as $$$$$$$$$$$8 from "./actions/vtex/cart/addItems.ts"; +import * as $$$$$$$$$$$9 from "./actions/vtex/cart/getInstallment.ts"; +import * as $$$$$$$$$$$10 from "./actions/vtex/cart/removeItemAttachment.ts"; +import * as $$$$$$$$$$$11 from "./actions/vtex/cart/removeItems.ts"; +import * as $$$$$$$$$$$12 from "./actions/vtex/cart/simulation.ts"; +import * as $$$$$$$$$$$13 from "./actions/vtex/cart/updateAttachment.ts"; +import * as $$$$$$$$$$$14 from "./actions/vtex/cart/updateCoupons.ts"; +import * as $$$$$$$$$$$15 from "./actions/vtex/cart/updateItemAttachment.ts"; +import * as $$$$$$$$$$$16 from "./actions/vtex/cart/updateItemPrice.ts"; +import * as $$$$$$$$$$$17 from "./actions/vtex/cart/updateItems.ts"; +import * as $$$$$$$$$$$18 from "./actions/vtex/cart/updateProfile.ts"; +import * as $$$$$$$$$$$19 from "./actions/vtex/cart/updateUser.ts"; +import * as $$$$$$$$$$$20 from "./actions/vtex/newsletter/subscribe.ts"; +import * as $$$$$$$$$$$21 from "./actions/vtex/notifyme.ts"; +import * as $$$$$$$$$$$22 from "./actions/vtex/wishlist/addItem.ts"; +import * as $$$$$$$$$$$23 from "./actions/vtex/wishlist/removeItem.ts"; import { DecoManifest } from "$live/types.ts"; import * as i1$0 from "$live/loaders/secret.ts"; import * as i1$1 from "$live/loaders/state.ts"; @@ -144,80 +148,81 @@ import * as i1$$$$$$$3 from "$live/actions/workflows/start.ts"; const manifest = { "functions": { - "deco-sites/std/functions/butterCMSAds.ts": $4, - "deco-sites/std/functions/butterCMSBrands.ts": $16, - "deco-sites/std/functions/butterCMSCategories.ts": $22, - "deco-sites/std/functions/butterCMSFeaturedPosts.ts": $14, - "deco-sites/std/functions/butterCMSPage.ts": $1, - "deco-sites/std/functions/butterCMSPlaces.ts": $10, - "deco-sites/std/functions/butterCMSPostDetail.ts": $5, - "deco-sites/std/functions/butterCMSPosts.ts": $0, - "deco-sites/std/functions/butterCMSRelatedPosts.ts": $18, - "deco-sites/std/functions/occProductDetailsPage.ts": $15, - "deco-sites/std/functions/requestToParam.ts": $26, - "deco-sites/std/functions/shopifyProductDetailsPage.ts": $24, - "deco-sites/std/functions/shopifyProductList.ts": $23, - "deco-sites/std/functions/shopifyProductListingPage.ts": $12, - "deco-sites/std/functions/vndaProductDetailsPage.ts": $6, - "deco-sites/std/functions/vndaProductList.ts": $3, - "deco-sites/std/functions/vndaProductListingPage.ts": $17, - "deco-sites/std/functions/vtexLegacyProductDetailsPage.ts": $7, - "deco-sites/std/functions/vtexLegacyProductList.ts": $21, + "deco-sites/std/functions/butterCMSAds.ts": $0, + "deco-sites/std/functions/butterCMSBrands.ts": $1, + "deco-sites/std/functions/butterCMSCategories.ts": $2, + "deco-sites/std/functions/butterCMSFeaturedPosts.ts": $3, + "deco-sites/std/functions/butterCMSPage.ts": $4, + "deco-sites/std/functions/butterCMSPlaces.ts": $5, + "deco-sites/std/functions/butterCMSPostDetail.ts": $6, + "deco-sites/std/functions/butterCMSPosts.ts": $7, + "deco-sites/std/functions/butterCMSRelatedPosts.ts": $8, + "deco-sites/std/functions/occProductDetailsPage.ts": $9, + "deco-sites/std/functions/requestToParam.ts": $10, + "deco-sites/std/functions/shopifyProductDetailsPage.ts": $11, + "deco-sites/std/functions/shopifyProductList.ts": $12, + "deco-sites/std/functions/shopifyProductListingPage.ts": $13, + "deco-sites/std/functions/vndaProductDetailsPage.ts": $14, + "deco-sites/std/functions/vndaProductList.ts": $15, + "deco-sites/std/functions/vndaProductListingPage.ts": $16, + "deco-sites/std/functions/vtexLegacyProductDetailsPage.ts": $17, + "deco-sites/std/functions/vtexLegacyProductList.ts": $18, "deco-sites/std/functions/vtexLegacyProductListingPage.ts": $19, - "deco-sites/std/functions/vtexLegacyRelatedProductsLoader.ts": $25, - "deco-sites/std/functions/vtexNavbar.ts": $9, - "deco-sites/std/functions/vtexProductDetailsPage.ts": $20, - "deco-sites/std/functions/vtexProductList.ts": $13, - "deco-sites/std/functions/vtexProductListingPage.ts": $2, - "deco-sites/std/functions/vtexSuggestions.ts": $8, - "deco-sites/std/functions/vtexWishlist.ts": $11, + "deco-sites/std/functions/vtexLegacyRelatedProductsLoader.ts": $20, + "deco-sites/std/functions/vtexNavbar.ts": $21, + "deco-sites/std/functions/vtexProductDetailsPage.ts": $22, + "deco-sites/std/functions/vtexProductList.ts": $23, + "deco-sites/std/functions/vtexProductListingPage.ts": $24, + "deco-sites/std/functions/vtexSuggestions.ts": $25, + "deco-sites/std/functions/vtexWishlist.ts": $26, }, "accounts": { "deco-sites/std/accounts/butterCMS.ts": $$0, "deco-sites/std/accounts/linxImpulse.ts": $$1, - "deco-sites/std/accounts/nuvemShop.ts": $$3, - "deco-sites/std/accounts/occ.ts": $$7, - "deco-sites/std/accounts/shopify.ts": $$6, - "deco-sites/std/accounts/vnda.ts": $$2, - "deco-sites/std/accounts/vtex.ts": $$5, - "deco-sites/std/accounts/yourViews.ts": $$4, + "deco-sites/std/accounts/nuvemShop.ts": $$2, + "deco-sites/std/accounts/occ.ts": $$3, + "deco-sites/std/accounts/shopify.ts": $$4, + "deco-sites/std/accounts/vnda.ts": $$5, + "deco-sites/std/accounts/vtex.ts": $$6, + "deco-sites/std/accounts/yourViews.ts": $$7, }, "loaders": { "$live/loaders/secret.ts": i1$0, "$live/loaders/state.ts": i1$1, "$live/loaders/workflows/events.ts": i1$2, "$live/loaders/workflows/get.ts": i1$3, - "deco-sites/std/loaders/linxImpulse/autocompletes/popular.ts": $$$2, - "deco-sites/std/loaders/linxImpulse/autocompletes/suggestions.ts": $$$3, - "deco-sites/std/loaders/linxImpulse/pages/recommendations.ts": $$$4, - "deco-sites/std/loaders/linxImpulse/products/similarItems.ts": $$$0, - "deco-sites/std/loaders/linxImpulse/search.ts": $$$1, - "deco-sites/std/loaders/nuvemShop/nuvemShopProductDetailsPage.ts": $$$23, - "deco-sites/std/loaders/nuvemShop/nuvemShopProductList.ts": $$$24, - "deco-sites/std/loaders/nuvemShop/nuvemShopProductListingPage.ts": $$$25, - "deco-sites/std/loaders/vnda/cart.ts": $$$22, - "deco-sites/std/loaders/vnda/productDetailsPage.ts": $$$19, - "deco-sites/std/loaders/vnda/productList.ts": $$$18, - "deco-sites/std/loaders/vnda/productListingPage.ts": $$$20, - "deco-sites/std/loaders/vnda/proxy.ts": $$$21, - "deco-sites/std/loaders/vtex/cart.ts": $$$16, + "deco-sites/std/loaders/linxImpulse/autocompletes/popular.ts": $$$0, + "deco-sites/std/loaders/linxImpulse/autocompletes/suggestions.ts": $$$1, + "deco-sites/std/loaders/linxImpulse/pages/recommendations.ts": $$$2, + "deco-sites/std/loaders/linxImpulse/products/similarItems.ts": $$$3, + "deco-sites/std/loaders/linxImpulse/search.ts": $$$4, + "deco-sites/std/loaders/nuvemShop/nuvemShopProductDetailsPage.ts": $$$5, + "deco-sites/std/loaders/nuvemShop/nuvemShopProductList.ts": $$$6, + "deco-sites/std/loaders/nuvemShop/nuvemShopProductListingPage.ts": $$$7, + "deco-sites/std/loaders/shopify/cart.ts": $$$8, + "deco-sites/std/loaders/vnda/cart.ts": $$$9, + "deco-sites/std/loaders/vnda/productDetailsPage.ts": $$$10, + "deco-sites/std/loaders/vnda/productList.ts": $$$11, + "deco-sites/std/loaders/vnda/productListingPage.ts": $$$12, + "deco-sites/std/loaders/vnda/proxy.ts": $$$13, + "deco-sites/std/loaders/vtex/cart.ts": $$$14, "deco-sites/std/loaders/vtex/intelligentSearch/productDetailsPage.ts": - $$$13, - "deco-sites/std/loaders/vtex/intelligentSearch/productList.ts": $$$12, + $$$15, + "deco-sites/std/loaders/vtex/intelligentSearch/productList.ts": $$$16, "deco-sites/std/loaders/vtex/intelligentSearch/productListingPage.ts": - $$$14, - "deco-sites/std/loaders/vtex/intelligentSearch/suggestions.ts": $$$15, - "deco-sites/std/loaders/vtex/legacy/productDetailsPage.ts": $$$6, - "deco-sites/std/loaders/vtex/legacy/productList.ts": $$$5, - "deco-sites/std/loaders/vtex/legacy/productListingPage.ts": $$$7, - "deco-sites/std/loaders/vtex/legacy/relatedProductsLoader.ts": $$$8, - "deco-sites/std/loaders/vtex/navbar.ts": $$$10, - "deco-sites/std/loaders/vtex/proxy.ts": $$$11, - "deco-sites/std/loaders/vtex/user.ts": $$$17, - "deco-sites/std/loaders/vtex/wishlist.ts": $$$9, - "deco-sites/std/loaders/x/font.ts": $$$28, - "deco-sites/std/loaders/x/image.ts": $$$26, - "deco-sites/std/loaders/x/redirectsFromCsv.ts": $$$27, + $$$17, + "deco-sites/std/loaders/vtex/intelligentSearch/suggestions.ts": $$$18, + "deco-sites/std/loaders/vtex/legacy/productDetailsPage.ts": $$$19, + "deco-sites/std/loaders/vtex/legacy/productList.ts": $$$20, + "deco-sites/std/loaders/vtex/legacy/productListingPage.ts": $$$21, + "deco-sites/std/loaders/vtex/legacy/relatedProductsLoader.ts": $$$22, + "deco-sites/std/loaders/vtex/navbar.ts": $$$23, + "deco-sites/std/loaders/vtex/proxy.ts": $$$24, + "deco-sites/std/loaders/vtex/user.ts": $$$25, + "deco-sites/std/loaders/vtex/wishlist.ts": $$$26, + "deco-sites/std/loaders/x/font.ts": $$$27, + "deco-sites/std/loaders/x/image.ts": $$$28, + "deco-sites/std/loaders/x/redirectsFromCsv.ts": $$$29, }, "routes": { "./routes/_app.tsx": $$$$2, @@ -232,8 +237,8 @@ const manifest = { "$live/handlers/router.ts": i1$$4, "$live/handlers/routesSelection.ts": i1$$5, "$live/handlers/workflowRunner.ts": i1$$6, - "deco-sites/std/handlers/sitemap.ts": $$$$$$1, - "deco-sites/std/handlers/vtex/sitemap.ts": $$$$$$0, + "deco-sites/std/handlers/sitemap.ts": $$$$$$0, + "deco-sites/std/handlers/vtex/sitemap.ts": $$$$$$1, }, "sections": { "$live/sections/Conditional_Beta.tsx": i1$$$$0, @@ -241,45 +246,48 @@ const manifest = { "$live/sections/PageInclude.tsx": i1$$$$2, "$live/sections/Slot.tsx": i1$$$$3, "$live/sections/UseSlot.tsx": i1$$$$4, - "deco-sites/std/sections/Analytics.tsx": $$$$$$$$7, + "deco-sites/std/sections/Analytics.tsx": $$$$$$$$0, "deco-sites/std/sections/configButterCMS.global.tsx": $$$$$$$$1, - "deco-sites/std/sections/configLinxImpulse.global.tsx": $$$$$$$$4, + "deco-sites/std/sections/configLinxImpulse.global.tsx": $$$$$$$$2, "deco-sites/std/sections/configNuvemShop.tsx": $$$$$$$$3, - "deco-sites/std/sections/configOCC.global.tsx": $$$$$$$$6, - "deco-sites/std/sections/configShopify.global.tsx": $$$$$$$$8, - "deco-sites/std/sections/configVTEX.global.tsx": $$$$$$$$10, - "deco-sites/std/sections/configYourViews.global.tsx": $$$$$$$$0, - "deco-sites/std/sections/SEO.tsx": $$$$$$$$2, - "deco-sites/std/sections/SEOPDP.tsx": $$$$$$$$11, - "deco-sites/std/sections/SEOPLP.tsx": $$$$$$$$5, - "deco-sites/std/sections/VTEXPortalDataLayerCompatibility.tsx": $$$$$$$$9, + "deco-sites/std/sections/configOCC.global.tsx": $$$$$$$$4, + "deco-sites/std/sections/configShopify.global.tsx": $$$$$$$$5, + "deco-sites/std/sections/configVTEX.global.tsx": $$$$$$$$6, + "deco-sites/std/sections/configYourViews.global.tsx": $$$$$$$$7, + "deco-sites/std/sections/SEO.tsx": $$$$$$$$8, + "deco-sites/std/sections/SEOPDP.tsx": $$$$$$$$9, + "deco-sites/std/sections/SEOPLP.tsx": $$$$$$$$10, + "deco-sites/std/sections/VTEXPortalDataLayerCompatibility.tsx": $$$$$$$$11, }, "actions": { "$live/actions/secrets/encrypt.ts": i1$$$$$$$0, "$live/actions/workflows/cancel.ts": i1$$$$$$$1, "$live/actions/workflows/signal.ts": i1$$$$$$$2, "$live/actions/workflows/start.ts": i1$$$$$$$3, - "deco-sites/std/actions/vnda/cart/addItem.ts": $$$$$$$$$$$19, - "deco-sites/std/actions/vnda/cart/setShippingAddress.ts": $$$$$$$$$$$18, - "deco-sites/std/actions/vnda/cart/updateCoupon.ts": $$$$$$$$$$$20, - "deco-sites/std/actions/vnda/cart/updateItem.ts": $$$$$$$$$$$17, - "deco-sites/std/actions/vtex/analytics/sendEvent.ts": $$$$$$$$$$$16, - "deco-sites/std/actions/vtex/cart/addItems.ts": $$$$$$$$$$$6, - "deco-sites/std/actions/vtex/cart/getInstallment.ts": $$$$$$$$$$$8, - "deco-sites/std/actions/vtex/cart/removeItemAttachment.ts": $$$$$$$$$$$12, - "deco-sites/std/actions/vtex/cart/removeItems.ts": $$$$$$$$$$$7, - "deco-sites/std/actions/vtex/cart/simulation.ts": $$$$$$$$$$$11, - "deco-sites/std/actions/vtex/cart/updateAttachment.ts": $$$$$$$$$$$2, - "deco-sites/std/actions/vtex/cart/updateCoupons.ts": $$$$$$$$$$$1, - "deco-sites/std/actions/vtex/cart/updateItemAttachment.ts": $$$$$$$$$$$4, - "deco-sites/std/actions/vtex/cart/updateItemPrice.ts": $$$$$$$$$$$9, - "deco-sites/std/actions/vtex/cart/updateItems.ts": $$$$$$$$$$$3, - "deco-sites/std/actions/vtex/cart/updateProfile.ts": $$$$$$$$$$$10, - "deco-sites/std/actions/vtex/cart/updateUser.ts": $$$$$$$$$$$5, - "deco-sites/std/actions/vtex/newsletter/subscribe.ts": $$$$$$$$$$$13, - "deco-sites/std/actions/vtex/notifyme.ts": $$$$$$$$$$$0, - "deco-sites/std/actions/vtex/wishlist/addItem.ts": $$$$$$$$$$$15, - "deco-sites/std/actions/vtex/wishlist/removeItem.ts": $$$$$$$$$$$14, + "deco-sites/std/actions/shopify/cart/addItems.ts": $$$$$$$$$$$0, + "deco-sites/std/actions/shopify/cart/updateCoupons.ts": $$$$$$$$$$$1, + "deco-sites/std/actions/shopify/cart/updateItems.ts": $$$$$$$$$$$2, + "deco-sites/std/actions/vnda/cart/addItem.ts": $$$$$$$$$$$3, + "deco-sites/std/actions/vnda/cart/setShippingAddress.ts": $$$$$$$$$$$4, + "deco-sites/std/actions/vnda/cart/updateCoupon.ts": $$$$$$$$$$$5, + "deco-sites/std/actions/vnda/cart/updateItem.ts": $$$$$$$$$$$6, + "deco-sites/std/actions/vtex/analytics/sendEvent.ts": $$$$$$$$$$$7, + "deco-sites/std/actions/vtex/cart/addItems.ts": $$$$$$$$$$$8, + "deco-sites/std/actions/vtex/cart/getInstallment.ts": $$$$$$$$$$$9, + "deco-sites/std/actions/vtex/cart/removeItemAttachment.ts": $$$$$$$$$$$10, + "deco-sites/std/actions/vtex/cart/removeItems.ts": $$$$$$$$$$$11, + "deco-sites/std/actions/vtex/cart/simulation.ts": $$$$$$$$$$$12, + "deco-sites/std/actions/vtex/cart/updateAttachment.ts": $$$$$$$$$$$13, + "deco-sites/std/actions/vtex/cart/updateCoupons.ts": $$$$$$$$$$$14, + "deco-sites/std/actions/vtex/cart/updateItemAttachment.ts": $$$$$$$$$$$15, + "deco-sites/std/actions/vtex/cart/updateItemPrice.ts": $$$$$$$$$$$16, + "deco-sites/std/actions/vtex/cart/updateItems.ts": $$$$$$$$$$$17, + "deco-sites/std/actions/vtex/cart/updateProfile.ts": $$$$$$$$$$$18, + "deco-sites/std/actions/vtex/cart/updateUser.ts": $$$$$$$$$$$19, + "deco-sites/std/actions/vtex/newsletter/subscribe.ts": $$$$$$$$$$$20, + "deco-sites/std/actions/vtex/notifyme.ts": $$$$$$$$$$$21, + "deco-sites/std/actions/vtex/wishlist/addItem.ts": $$$$$$$$$$$22, + "deco-sites/std/actions/vtex/wishlist/removeItem.ts": $$$$$$$$$$$23, }, "pages": { "$live/pages/LivePage.tsx": i1$$$0, diff --git a/loaders/shopify/cart.ts b/loaders/shopify/cart.ts new file mode 100644 index 00000000..b55d15e2 --- /dev/null +++ b/loaders/shopify/cart.ts @@ -0,0 +1 @@ +export { default } from "deco-sites/std/packs/shopify/loaders/cart.ts"; diff --git a/packs/shopify/accounts/shopify.ts b/packs/shopify/accounts/shopify.ts new file mode 100644 index 00000000..b665e0f2 --- /dev/null +++ b/packs/shopify/accounts/shopify.ts @@ -0,0 +1,25 @@ +import type { Account as AccountBlock } from "$live/blocks/account.ts"; +import type { FnContext } from "$live/types.ts"; +import type { Manifest } from "deco-sites/std/live.gen.ts"; + +export interface Account extends AccountBlock { + /** + * @description Shopify store name. + */ + storeName: string; + + /** + * @description Shopify storefront access token. + */ + storefrontAccessToken: string; +} + +export type Context = FnContext<{ + configShopify?: Account; +}, Manifest>; + +function account(acc: Account) { + return acc; +} + +export default account; diff --git a/packs/shopify/actions/cart/addItems.ts b/packs/shopify/actions/cart/addItems.ts new file mode 100644 index 00000000..19774579 --- /dev/null +++ b/packs/shopify/actions/cart/addItems.ts @@ -0,0 +1,51 @@ +import { getCookies } from "std/http/mod.ts"; +import type { Cart } from "../../types.ts"; +import type { Context } from "../../accounts/shopify.ts"; +import { getShopifyClient } from "../../client.ts"; +import { SHOPIFY_COOKIE_NAME } from "../../constants.ts"; +import { CART_QUERY } from "../../utils/cartQuery.ts"; + +const addToCartQuery = `mutation add($cartId: ID!, $lines: [CartLineInput!]!) { + cartLinesAdd(cartId: $cartId, lines: $lines) { + cart ${CART_QUERY} + } +}`; + +export interface addToCartQueryProps { + cartLinesAdd: Cart; +} + +type UpdateLineProps = { + lines: { + merchandiseId: string; + attributes?: Array<{ key: string; value: string }>; + quantity?: number; + sellingPlanId?: string; + }; +}; + +const action = async ( + props: UpdateLineProps, + req: Request, + ctx: Context, +): Promise => { + const { configShopify: config } = ctx; + const client = getShopifyClient(config); + + const reqCookies = getCookies(req.headers); + const cartId = reqCookies[SHOPIFY_COOKIE_NAME]; + const response: addToCartQueryProps | undefined = await client( + addToCartQuery, + [], + { + cartId: cartId, + lines: [props.lines], + }, + ); + + const cartResponse: Cart | undefined = response?.cartLinesAdd; + + return cartResponse || { cart: { id: cartId } }; +}; + +export default action; diff --git a/packs/shopify/actions/cart/updateCoupons.ts b/packs/shopify/actions/cart/updateCoupons.ts new file mode 100644 index 00000000..b912f9c9 --- /dev/null +++ b/packs/shopify/actions/cart/updateCoupons.ts @@ -0,0 +1,50 @@ +import { getCookies } from "std/http/mod.ts"; +import type { Cart } from "../../types.ts"; +import type { Context } from "../../accounts/shopify.ts"; +import { getShopifyClient } from "../../client.ts"; +import { SHOPIFY_COOKIE_NAME } from "../../constants.ts"; +import { CART_QUERY } from "../../utils/cartQuery.ts"; + +const addCouponQuery = + `mutation addCoupon($cartId: ID!, $discountCodes: [String!]!) { + cartDiscountCodesUpdate(cartId: $cartId, discountCodes: $discountCodes) { + cart ${CART_QUERY} + userErrors { + field + message + } + } +}`; + +export interface addCouponQueryProps { + cartDiscountCodesUpdate: Cart; +} + +type AddCouponProps = { + discountCodes: string[]; +}; + +const action = async ( + props: AddCouponProps, + req: Request, + ctx: Context, +): Promise => { + const { configShopify: config } = ctx; + const client = getShopifyClient(config); + + const reqCookies = getCookies(req.headers); + const cartId = reqCookies[SHOPIFY_COOKIE_NAME]; + const response: addCouponQueryProps | undefined = await client( + addCouponQuery, + [], + { + cartId: cartId, + discountCodes: [...props.discountCodes], + }, + ); + const cartResponse: Cart | undefined = response?.cartDiscountCodesUpdate; + + return cartResponse || { cart: { id: cartId } }; +}; + +export default action; diff --git a/packs/shopify/actions/cart/updateItems.ts b/packs/shopify/actions/cart/updateItems.ts new file mode 100644 index 00000000..1db026c7 --- /dev/null +++ b/packs/shopify/actions/cart/updateItems.ts @@ -0,0 +1,49 @@ +import { getCookies } from "std/http/mod.ts"; +import type { Cart } from "../../types.ts"; +import type { Context } from "../../accounts/shopify.ts"; +import { getShopifyClient } from "../../client.ts"; +import { SHOPIFY_COOKIE_NAME } from "../../constants.ts"; +import { CART_QUERY } from "../../utils/cartQuery.ts"; + +const updateCartQuery = + `mutation update($cartId: ID!, $lines: [CartLineUpdateInput!]!) { + cartLinesUpdate(cartId: $cartId, lines: $lines) { + cart ${CART_QUERY} + } +}`; + +export interface updateCartQueryProps { + cartLinesUpdate: Cart; +} + +type UpdateLineProps = { + lines: { + id: string; + quantity?: number; + }; +}; + +const action = async ( + props: UpdateLineProps, + req: Request, + ctx: Context, +): Promise => { + const { configShopify: config } = ctx; + const client = getShopifyClient(config); + + const reqCookies = getCookies(req.headers); + const cartId = reqCookies[SHOPIFY_COOKIE_NAME]; + const response: updateCartQueryProps | undefined = await client( + updateCartQuery, + [], + { + cartId: cartId, + lines: [props.lines], + }, + ); + const cartResponse: Cart | undefined = response?.cartLinesUpdate; + + return cartResponse || { cart: { id: cartId } }; +}; + +export default action; diff --git a/packs/shopify/client.ts b/packs/shopify/client.ts new file mode 100644 index 00000000..3e119d80 --- /dev/null +++ b/packs/shopify/client.ts @@ -0,0 +1,51 @@ +import { fetchAPI } from "deco-sites/std/utils/fetch.ts"; +import type { Account } from "./accounts/shopify.ts"; + +const createShopifyClient = ({ + storeName = "gimenesdevstore", + storefrontAccessToken = "27c1ac16fe30a0fb6c5d634eeb63bf81", +}: Partial = {}) => { + return async ( + query: string, + fragments: string[] = [], + variables: Record = {}, + ) => { + const finalQuery = [query, ...fragments].join("\n"); + const { data, errors } = await fetchAPI<{ data?: T; errors: unknown[] }>( + `https://${storeName}.myshopify.com/api/2022-10/graphql.json`, + { + method: "POST", + body: JSON.stringify({ + query: finalQuery, + variables, + }), + headers: { + "Content-Type": "application/json", + "X-Shopify-Storefront-Access-Token": storefrontAccessToken, + }, + }, + ); + + if (Array.isArray(errors) && errors.length > 0) { + console.error(Deno.inspect(errors, { depth: 100, colors: true })); + + throw new Error( + `Error while running query:\n${finalQuery}\n\n${ + JSON.stringify(variables) + }`, + ); + } + + return data; + }; +}; + +let shopifyClient: ReturnType | undefined; + +export const getShopifyClient = (config: Partial = {}) => { + if (!shopifyClient) { + shopifyClient = createShopifyClient(config); + } + + return shopifyClient; +}; diff --git a/packs/shopify/constants.ts b/packs/shopify/constants.ts new file mode 100644 index 00000000..831d3ffe --- /dev/null +++ b/packs/shopify/constants.ts @@ -0,0 +1 @@ +export const SHOPIFY_COOKIE_NAME = "shopify_cart_id"; diff --git a/packs/shopify/enums.ts b/packs/shopify/enums.ts new file mode 100644 index 00000000..d80648e1 --- /dev/null +++ b/packs/shopify/enums.ts @@ -0,0 +1,438 @@ +export enum CurrencyCode { + AED = "AED", + AFN = "AFN", + ALL = "ALL", + AMD = "AMD", + ANG = "ANG", + AOA = "AOA", + ARS = "ARS", + AUD = "AUD", + AWG = "AWG", + AZN = "AZN", + BAM = "BAM", + BBD = "BBD", + BDT = "BDT", + BGN = "BGN", + BHD = "BHD", + BIF = "BIF", + BMD = "BMD", + BND = "BND", + BOB = "BOB", + BRL = "BRL", + BSD = "BSD", + BTN = "BTN", + BWP = "BWP", + BYN = "BYN", + BZD = "BZD", + CAD = "CAD", + CDF = "CDF", + CHF = "CHF", + CLP = "CLP", + CNY = "CNY", + COP = "COP", + CRC = "CRC", + CVE = "CVE", + CZK = "CZK", + DJF = "DJF", + DKK = "DKK", + DOP = "DOP", + DZD = "DZD", + EGP = "EGP", + ERN = "ERN", + ETB = "ETB", + EUR = "EUR", + FJD = "FJD", + FKP = "FKP", + GBP = "GBP", + GEL = "GEL", + GHS = "GHS", + GIP = "GIP", + GMD = "GMD", + GNF = "GNF", + GTQ = "GTQ", + GYD = "GYD", + HKD = "HKD", + HNL = "HNL", + HRK = "HRK", + HTG = "HTG", + HUF = "HUF", + IDR = "IDR", + ILS = "ILS", + INR = "INR", + IQD = "IQD", + IRR = "IRR", + ISK = "ISK", + JEP = "JEP", + JMD = "JMD", + JOD = "JOD", + JPY = "JPY", + KES = "KES", + KGS = "KGS", + KHR = "KHR", + KID = "KID", + KMF = "KMF", + KRW = "KRW", + KWD = "KWD", + KYD = "KYD", + KZT = "KZT", + LAK = "LAK", + LBP = "LBP", + LKR = "LKR", + LRD = "LRD", + LSL = "LSL", + LTL = "LTL", + LVL = "LVL", + LYD = "LYD", + MAD = "MAD", + MDL = "MDL", + MGA = "MGA", + MKD = "MKD", + MMK = "MMK", + MNT = "MNT", + MOP = "MOP", + MRU = "MRU", + MUR = "MUR", + MVR = "MVR", + MWK = "MWK", + MXN = "MXN", + MYR = "MYR", + MZN = "MZN", + NAD = "NAD", + NGN = "NGN", + NIO = "NIO", + NOK = "NOK", + NPR = "NPR", + NZD = "NZD", + OMR = "OMR", + PAB = "PAB", + PEN = "PEN", + PGK = "PGK", + PHP = "PHP", + PKR = "PKR", + PLN = "PLN", + PYG = "PYG", + QAR = "QAR", + RON = "RON", + RSD = "RSD", + RUB = "RUB", + RWF = "RWF", + SAR = "SAR", + SBD = "SBD", + SCR = "SCR", + SDG = "SDG", + SEK = "SEK", + SGD = "SGD", + SHP = "SHP", + SLL = "SLL", + SOS = "SOS", + SRD = "SRD", + SSP = "SSP", + STN = "STN", + SYP = "SYP", + SZL = "SZL", + THB = "THB", + TJS = "TJS", + TMT = "TMT", + TND = "TND", + TOP = "TOP", + TRY = "TRY", + TTD = "TTD", + TWD = "TWD", + TZS = "TZS", + UAH = "UAH", + UGX = "UGX", + USD = "USD", + UYU = "UYU", + UZS = "UZS", + VED = "VED", + VES = "VES", + VND = "VND", + VUV = "VUV", + WST = "WST", + XAF = "XAF", + XCD = "XCD", + XOF = "XOF", + XPF = "XPF", + XXX = "XXX", + YER = "YER", + ZAR = "ZAR", + ZMW = "ZMW", +} + +export enum CountryCode { + AC = "AC", + AD = "AD", + AE = "AE", + AF = "AF", + AG = "AG", + AI = "AI", + AL = "AL", + AM = "AM", + AN = "AN", + AO = "AO", + AR = "AR", + AT = "AT", + AU = "AU", + AW = "AW", + AX = "AX", + AZ = "AZ", + BA = "BA", + BB = "BB", + BD = "BD", + BE = "BE", + BF = "BF", + BG = "BG", + BH = "BH", + BI = "BI", + BJ = "BJ", + BL = "BL", + BM = "BM", + BN = "BN", + BO = "BO", + BQ = "BQ", + BR = "BR", + BS = "BS", + BT = "BT", + BV = "BV", + BW = "BW", + BY = "BY", + BZ = "BZ", + CA = "CA", + CC = "CC", + CD = "CD", + CF = "CF", + CG = "CG", + CH = "CH", + CI = "CI", + CK = "CK", + CL = "CL", + CM = "CM", + CN = "CN", + CO = "CO", + CR = "CR", + CU = "CU", + CV = "CV", + CW = "CW", + CX = "CX", + CY = "CY", + CZ = "CZ", + DE = "DE", + DJ = "DJ", + DK = "DK", + DM = "DM", + DO = "DO", + DZ = "DZ", + EC = "EC", + EE = "EE", + EG = "EG", + EH = "EH", + ER = "ER", + ES = "ES", + ET = "ET", + FI = "FI", + FJ = "FJ", + FK = "FK", + FO = "FO", + FR = "FR", + GA = "GA", + GB = "GB", + GD = "GD", + GE = "GE", + GF = "GF", + GG = "GG", + GH = "GH", + GI = "GI", + GL = "GL", + GM = "GM", + GN = "GN", + GP = "GP", + GQ = "GQ", + GR = "GR", + GS = "GS", + GT = "GT", + GW = "GW", + GY = "GY", + HK = "HK", + HM = "HM", + HN = "HN", + HR = "HR", + HT = "HT", + HU = "HU", + ID = "ID", + IE = "IE", + IL = "IL", + IM = "IM", + IN = "IN", + IO = "IO", + IQ = "IQ", + IR = "IR", + IS = "IS", + IT = "IT", + JE = "JE", + JM = "JM", + JO = "JO", + JP = "JP", + KE = "KE", + KG = "KG", + KH = "KH", + KI = "KI", + KM = "KM", + KN = "KN", + KP = "KP", + KR = "KR", + KW = "KW", + KY = "KY", + KZ = "KZ", + LA = "LA", + LB = "LB", + LC = "LC", + LI = "LI", + LK = "LK", + LR = "LR", + LS = "LS", + LT = "LT", + LU = "LU", + LV = "LV", + LY = "LY", + MA = "MA", + MC = "MC", + MD = "MD", + ME = "ME", + MF = "MF", + MG = "MG", + MK = "MK", + ML = "ML", + MM = "MM", + MN = "MN", + MO = "MO", + MQ = "MQ", + MR = "MR", + MS = "MS", + MT = "MT", + MU = "MU", + MV = "MV", + MW = "MW", + MX = "MX", + MY = "MY", + MZ = "MZ", + NA = "NA", + NC = "NC", + NE = "NE", + NF = "NF", + NG = "NG", + NI = "NI", + NL = "NL", + NO = "NO", + NP = "NP", + NR = "NR", + NU = "NU", + NZ = "NZ", + OM = "OM", + PA = "PA", + PE = "PE", + PF = "PF", + PG = "PG", + PH = "PH", + PK = "PK", + PL = "PL", + PM = "PM", + PN = "PN", + PS = "PS", + PT = "PT", + PY = "PY", + QA = "QA", + RE = "RE", + RO = "RO", + RS = "RS", + RU = "RU", + RW = "RW", + SA = "SA", + SB = "SB", + SC = "SC", + SD = "SD", + SE = "SE", + SG = "SG", + SH = "SH", + SI = "SI", + SJ = "SJ", + SK = "SK", + SL = "SL", + SM = "SM", + SN = "SN", + SO = "SO", + SR = "SR", + SS = "SS", + ST = "ST", + SV = "SV", + SX = "SX", + SY = "SY", + SZ = "SZ", + TA = "TA", + TC = "TC", + TD = "TD", + TF = "TF", + TG = "TG", + TH = "TH", + TJ = "TJ", + TK = "TK", + TL = "TL", + TM = "TM", + TN = "TN", + TO = "TO", + TR = "TR", + TT = "TT", + TV = "TV", + TW = "TW", + TZ = "TZ", + UA = "UA", + UG = "UG", + UM = "UM", + US = "US", + UY = "UY", + UZ = "UZ", + VA = "VA", + VC = "VC", + VE = "VE", + VG = "VG", + VN = "VN", + VU = "VU", + WF = "WF", + WS = "WS", + XK = "XK", + YE = "YE", + YT = "YT", + ZA = "ZA", + ZM = "ZM", + ZW = "ZW", + ZZ = "ZZ", +} + +export enum OrderCancelReason { + CUSTOMER = "CUSTOMER", + DECLINED = "DECLINED", + FRAUD = "FRAUD", + INVENTORY = "INVENTORY", + OTHER = "OTHER", +} + +export enum OrderFinancialStatus { + AUTHORIZED = "AUTHORIZED", + PAID = "PAID", + PARTIALLY_PAID = "PARTIALLY_PAID", + PARTIALLY_REFUNDED = "PARTIALLY_REFUNDED", + PENDING = "PENDING", + REFUNDED = "REFUNDED", + VOIDED = "VOIDED", +} + +export enum OrderFulfillmentStatus { + FULFILLED = "FULFILLED", + IN_PROGRESS = "IN_PROGRESS", + ON_HOLD = "ON_HOLD", + OPEN = "OPEN", + PARTIALLY_FULFILLED = "PARTIALLY_FULFILLED", + PENDING_FULFILLMENT = "PENDING_FULFILLMENT", + RESTOCKED = "RESTOCKED", + SCHEDULED = "SCHEDULED", + UNFULFILLED = "UNFULFILLED", +} diff --git a/packs/shopify/hooks/context.ts b/packs/shopify/hooks/context.ts new file mode 100644 index 00000000..5d6dfa28 --- /dev/null +++ b/packs/shopify/hooks/context.ts @@ -0,0 +1,73 @@ +import { IS_BROWSER } from "$fresh/runtime.ts"; +import { signal } from "@preact/signals"; +import { Runtime } from "deco-sites/std/runtime.ts"; +import { Cart } from "../types.ts"; + +interface Context { + cart: Cart; +} + +const loading = signal(true); +const context = { + cart: signal(null), +}; + +let queue = Promise.resolve(); +let abort = () => {}; + +const enqueue = ( + cb: (signal: AbortSignal) => Promise> | Partial, +) => { + abort(); + + loading.value = true; + const controller = new AbortController(); + + queue = queue.then(async () => { + try { + const { cart } = await cb(controller.signal); + + controller.signal.throwIfAborted(); + + context.cart.value = { ...context.cart.value, ...cart }; + + loading.value = false; + } catch (error) { + if (error.name === "AbortError") return; + + console.error(error); + loading.value = false; + } + }); + + abort = () => controller.abort(); + + return queue; +}; + +const load = async (signal: AbortSignal) => { + const { cart } = await Runtime.invoke({ + cart: { + key: "deco-sites/std/loaders/shopify/cart.ts", + }, + }, { signal }); + + return { + cart, + }; +}; + +if (IS_BROWSER) { + enqueue(load); + + document.addEventListener( + "visibilitychange", + () => document.visibilityState === "visible" && enqueue(load), + ); +} + +export const state = { + ...context, + loading, + enqueue, +}; diff --git a/packs/shopify/hooks/useCart.ts b/packs/shopify/hooks/useCart.ts new file mode 100644 index 00000000..25886086 --- /dev/null +++ b/packs/shopify/hooks/useCart.ts @@ -0,0 +1,28 @@ +import { Runtime } from "deco-sites/std/runtime.ts"; +import { Cart } from "../types.ts"; +import { state as storeState } from "./context.ts"; + +const { cart, loading } = storeState; + +const wrap = + (action: (p: T, init?: RequestInit | undefined) => Promise) => + (p: T) => + storeState.enqueue(async (signal) => ({ + cart: await action(p, { signal }), + })); + +const state = { + cart, + loading, + addItems: wrap( + Runtime.create("deco-sites/std/actions/shopify/cart/addItems.ts"), + ), + updateItems: wrap( + Runtime.create("deco-sites/std/actions/shopify/cart/updateItems.ts"), + ), + addCouponsToCart: wrap( + Runtime.create("deco-sites/std/actions/shopify/cart/updateCoupons.ts"), + ), +}; + +export const useCart = () => state; diff --git a/packs/shopify/loaders/cart.ts b/packs/shopify/loaders/cart.ts new file mode 100644 index 00000000..dc3576fb --- /dev/null +++ b/packs/shopify/loaders/cart.ts @@ -0,0 +1,80 @@ +import { getCookies, getSetCookies, setCookie } from "std/http/mod.ts"; + +import type { Cart } from "../types.ts"; +import type { Context } from "../accounts/shopify.ts"; +import { getShopifyClient } from "../client.ts"; +import { gql } from "../utils/gql.ts"; +import { SHOPIFY_COOKIE_NAME } from "../constants.ts"; + +import { CART_QUERY } from "../utils/cartQuery.ts"; + +const createCartMutation = gql` + mutation createCart { + payload: cartCreate { + cart { + id + } + } + } +`; + +const cartQuery = `query($id: ID!) { cart(id: $id) ${CART_QUERY} }`; + +type CreateCartPayload = { + payload: { + cart: { + id: string; + }; + }; +}; + +const loader = async ( + _props: unknown, + req: Request, + ctx: Context, +): Promise => { + const { configShopify: config } = ctx; + const client = getShopifyClient(config); + + try { + const r = await client(createCartMutation); + + const reqCookies = getCookies(req.headers); + const cartIdCookie = reqCookies[SHOPIFY_COOKIE_NAME]; + if (cartIdCookie) { + const queryResponse = await client( + cartQuery, + [], + { + id: cartIdCookie, + }, + ); + if (!queryResponse?.cart?.id) { + throw new Error("unable to create a cart"); + } + return queryResponse; + } + + if (!r?.payload?.cart.id) { + throw new Error("unable to create a cart"); + } + const { cart } = r.payload; + + const cookies = getSetCookies(ctx.response.headers); + cookies.push({ name: SHOPIFY_COOKIE_NAME, value: cart.id }); + + for (const cookie of cookies) { + setCookie(ctx.response.headers, { + ...cookie, + domain: new URL(req.url).hostname, + }); + } + + return { cart: { id: cart.id } }; + } catch (error) { + console.error(error); + throw error; + } +}; + +export default loader; diff --git a/packs/shopify/types.ts b/packs/shopify/types.ts new file mode 100644 index 00000000..2a22d350 --- /dev/null +++ b/packs/shopify/types.ts @@ -0,0 +1,183 @@ +import { + CountryCode, + CurrencyCode, + OrderCancelReason, + OrderFinancialStatus, + OrderFulfillmentStatus, +} from "./enums.ts"; + +type Attribute = { + key: string; + value?: string; +}; + +type MailingAddress = { + address1?: string; + address2?: string; + city?: string; + company?: string; + country?: string; + countryCodeV2?: CountryCode; + firstName?: string; + formattedArea?: string; + id: string; + lastName?: string; + latitude?: number; + longitude?: number; + name?: string; + phone?: string; + province?: string; + provinceCode?: string; + zip?: string; +}; + +type MoneyV2 = { + amount: number; + currencyCode: CurrencyCode; +}; + +type AppliedGiftCard = { + amountUsed: MoneyV2; + balance: MoneyV2; + id: string; + lastCharacters: string; + presentmentAmountUsed: MoneyV2; +}; + +type ShippingRate = { + handle: string; + price: MoneyV2; + title: string; +}; + +type AvailableShippingRates = { + ready: boolean; + shippingRates?: ShippingRate[]; +}; + +type CheckoutBuyerIdentity = { + countryCode: CountryCode; +}; + +type Order = { + billingAddress?: MailingAddress; + cancelReason?: OrderCancelReason; + canceledAt?: Date; + currencyCode: CurrencyCode; + currentSubtotalPrice: MoneyV2; + currentTotalDuties?: MoneyV2; + currentTotalPrice: MoneyV2; + currentTotalTax: MoneyV2; + customAttributes: Attribute[]; + customerLocale?: string; + customerUrl?: string; + edited: boolean; + email?: string; + financialStatus?: OrderFinancialStatus; + fulfillmentStatus: OrderFulfillmentStatus; + id: string; + name: string; + orderNumber: number; + originalTotalDuties?: MoneyV2; + originalTotalPrice: MoneyV2; + phone?: string; + processedAt: Date; + shippingAddress?: MailingAddress; +}; + +type Checkout = { + appliedGiftCards: AppliedGiftCard[]; + availableShippingRates?: AvailableShippingRates; + buyerIdentity: CheckoutBuyerIdentity; + completedAt?: Date; + createdAt: Date; + currencyCode: CurrencyCode; + customAttributes: Attribute[]; + email?: string; + id: string; + lineItemsSubtotalPrice: MoneyV2; + note: string; + order: Order; + orderStatusUrl: string; + paymentDue: MoneyV2; + ready: boolean; + requireShipping: boolean; + shippingAddress: MailingAddress; +}; + +type Customer = { + acceptsMarketing: boolean; + createdAt: Date; + defaultAddress: MailingAddress; + displayName: string; + email: string; + firstName: string; + id: string; + checkout: Checkout; +}; + +type CartBuyerIdentity = { + countryCode: string; + customer: Customer; +}; + +export type OldCart = { + attribute?: Attribute; + attributes?: Attribute[]; + buyerIdentity?: CartBuyerIdentity; + id: string; +}; + +export interface Money { + amount: number; + currencyCode: string; +} + +export interface Image { + url: string; + width: number; + height: number; + altText: string; +} + +export interface CartData { + id: string; + lines?: { + nodes: { + id: string; + quantity: number; + merchandise: { + id: string; + title: string; + product: { + title: string; + }; + image: Image; + price: Money; + }; + cost: { + totalAmount: Money; + subtotalAmount: Money; + amountPerQuantity: Money; + compareAtAmountPerQuantity: Money + }; + }[]; + }; + checkoutUrl?: string; + cost?: { + subtotalAmount: Money; + totalAmount: Money; + checkoutChargeAmount: Money; + }; + discountCodes?: { + code: string; + applicable: boolean; + }[]; + discountAllocations?: { + discountedAmount: Money; + }; +} + +export interface Cart { + cart: CartData; +} diff --git a/packs/shopify/utils/cartQuery.ts b/packs/shopify/utils/cartQuery.ts new file mode 100644 index 00000000..b45fc7c9 --- /dev/null +++ b/packs/shopify/utils/cartQuery.ts @@ -0,0 +1,70 @@ +export const CART_QUERY = `{ + id + checkoutUrl + totalQuantity + lines(first: 100) { + nodes { + id + quantity + merchandise { + ...on ProductVariant { + id + title + image { + url + altText + } + product { + title + } + price { + amount + currencyCode + } + } + } + cost { + totalAmount { + amount + currencyCode + } + subtotalAmount{ + amount + currencyCode + } + amountPerQuantity { + amount + currencyCode + } + compareAtAmountPerQuantity { + amount + currencyCode + } + } + } + } + cost { + subtotalAmount { + amount + currencyCode + } + totalAmount { + amount + currencyCode + } + checkoutChargeAmount{ + amount + currencyCode + } + } + discountCodes { + code + applicable + } + discountAllocations{ + discountedAmount { + amount + currencyCode + } + } + }`; diff --git a/packs/shopify/utils/gql.ts b/packs/shopify/utils/gql.ts new file mode 100644 index 00000000..ea9b7aba --- /dev/null +++ b/packs/shopify/utils/gql.ts @@ -0,0 +1 @@ +export const gql = (x: TemplateStringsArray) => x.toString().trim();