Skip to content

Commit

Permalink
Merge pull request #22 from deco-cx/chore/migrate-shopify
Browse files Browse the repository at this point in the history
chore: migrate shopify
  • Loading branch information
tlgimenes authored Sep 3, 2023
2 parents a4da133 + f6ff074 commit c577b4d
Show file tree
Hide file tree
Showing 30 changed files with 524 additions and 459 deletions.
6 changes: 3 additions & 3 deletions import_map.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"imports": {
"$live/": "https://deno.land/x/[email protected].2/",
"$live/": "https://denopkg.com/deco-cx/[email protected].3/",
"$fresh/": "https://denopkg.com/denoland/[email protected]/",
"preact": "https://esm.sh/[email protected]",
"preact/": "https://esm.sh/[email protected]/",
Expand All @@ -9,7 +9,7 @@
"@preact/signals-core": "https://esm.sh/@preact/[email protected]",
"std/": "https://deno.land/[email protected]/",
"partytown/": "https://deno.land/x/[email protected]/",
"deco-sites/std/": "https://denopkg.com/deco-sites/[email protected].6/",
"deco/": "https://deno.land/x/[email protected].2/"
"deco-sites/std/": "https://denopkg.com/deco-sites/[email protected].7/",
"deco/": "https://denopkg.com/deco-cx/[email protected].3/"
}
}
29 changes: 17 additions & 12 deletions shopify/actions/cart/addItems.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getCookies } from "std/http/mod.ts";
import { AppContext } from "../../mod.ts";
import { SHOPIFY_COOKIE_NAME } from "../../utils/constants.ts";
import type { Cart } from "../../utils/types.ts";
import { getCartCookie, setCartCookie } from "../../utils/cart.ts";
import { Data, query, Variables } from "../../utils/queries/addItem.ts";
import { Data as CartData } from "../../utils/queries/cart.ts";

type UpdateLineProps = {
lines: {
Expand All @@ -13,20 +13,25 @@ type UpdateLineProps = {
};

const action = async (
props: UpdateLineProps,
{ lines }: UpdateLineProps,
req: Request,
ctx: AppContext,
): Promise<Cart> => {
const { client } = ctx;
): Promise<CartData["cart"]> => {
const { storefront } = ctx;
const cartId = getCartCookie(req.headers);

const reqCookies = getCookies(req.headers);
const cartId = reqCookies[SHOPIFY_COOKIE_NAME];
const response = await client.cart.addItem({
cartId: cartId,
lines: [props.lines],
if (!cartId) {
throw new Error("Missing cart id");
}

const { payload: { cart } } = await storefront.query<Data, Variables>({
variables: { cartId, lines },
query,
});

return response?.cartLinesAdd || { cart: { id: cartId } };
setCartCookie(ctx.response.headers, cartId);

return cart;
};

export default action;
27 changes: 16 additions & 11 deletions shopify/actions/cart/updateCoupons.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getCookies } from "std/http/mod.ts";
import { AppContext } from "../../mod.ts";
import { SHOPIFY_COOKIE_NAME } from "../../utils/constants.ts";
import type { Cart } from "../../utils/types.ts";
import { getCartCookie, setCartCookie } from "../../utils/cart.ts";
import { Data as CartData } from "../../utils/queries/cart.ts";
import { Data, Variables, query } from "../../utils/queries/updateCoupon.ts";

type AddCouponProps = {
discountCodes: string[];
Expand All @@ -11,17 +11,22 @@ const action = async (
props: AddCouponProps,
req: Request,
ctx: AppContext,
): Promise<Cart> => {
const { client } = ctx;
): Promise<CartData["cart"]> => {
const { storefront } = ctx;
const cartId = getCartCookie(req.headers);

const reqCookies = getCookies(req.headers);
const cartId = reqCookies[SHOPIFY_COOKIE_NAME];
const response = await client.cart.addCoupon({
cartId: cartId,
discountCodes: [...props.discountCodes],
if (!cartId) {
throw new Error("Missing cart id");
}

const { payload: { cart } } = await storefront.query<Data, Variables>({
variables: { cartId, discountCodes: props.discountCodes },
query,
});

return response?.cartDiscountCodesUpdate || { cart: { id: cartId } };
setCartCookie(ctx.response.headers, cartId);

return cart;
};

export default action;
40 changes: 20 additions & 20 deletions shopify/actions/cart/updateItems.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
import { getCookies } from "std/http/mod.ts";
import { AppContext } from "../../mod.ts";
import { SHOPIFY_COOKIE_NAME } from "../../utils/constants.ts";
import type { Cart } from "../../utils/types.ts";

export interface updateCartQueryProps {
cartLinesUpdate: Cart;
}
import { getCartCookie, setCartCookie } from "../../utils/cart.ts";
import { Data as CartData } from "../../utils/queries/cart.ts";
import { Data, query, Variables } from "../../utils/queries/updateCart.ts";

type UpdateLineProps = {
lines: {
lines: Array<{
id: string;
quantity?: number;
};
}>;
};

const action = async (
props: UpdateLineProps,
{ lines }: UpdateLineProps,
req: Request,
ctx: AppContext,
): Promise<Cart> => {
const { client } = ctx;
): Promise<CartData["cart"]> => {
const { storefront } = ctx;
const cartId = getCartCookie(req.headers);

if (!cartId) {
throw new Error("Missing cart id");
}

const { payload: { cart } } = await storefront.query<Data, Variables>({
variables: { cartId, lines },
query,
});

const reqCookies = getCookies(req.headers);
const cartId = reqCookies[SHOPIFY_COOKIE_NAME];
const response: updateCartQueryProps | undefined = await client.cart
.updateItems({
cartId: cartId,
lines: [props.lines],
});
setCartCookie(ctx.response.headers, cartId);

return response?.cartLinesUpdate || { cart: { id: cartId } };
return cart;
};

export default action;
15 changes: 6 additions & 9 deletions shopify/hooks/context.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { IS_BROWSER } from "$fresh/runtime.ts";
import { signal } from "@preact/signals";
import { Runtime } from "../runtime.ts";
import { Cart } from "../utils/types.ts";
import { invoke } from "../runtime.ts";
import { Fragment as Cart } from "../utils/fragments/cart.ts";

interface Context {
cart: Cart;
Expand Down Expand Up @@ -45,13 +45,10 @@ const enqueue = (
return queue;
};

const load = async (signal: AbortSignal) => {
const cart = await Runtime.shopify.loaders.cart({}, {signal})

return {
cart,
};
};
const load = (signal: AbortSignal) =>
invoke({
cart: invoke.shopify.loaders.cart(),
}, { signal });

if (IS_BROWSER) {
enqueue(load);
Expand Down
46 changes: 28 additions & 18 deletions shopify/hooks/useCart.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { InvocationFuncFor } from "deco/clients/withManifest.ts";
import type { AnalyticsItem } from "../../commerce/types.ts";
import { Runtime } from "../runtime.ts";
import { Cart, Item } from "../utils/types.ts";
import { Manifest } from "../manifest.gen.ts";
import { invoke } from "../runtime.ts";
import { Fragment as Cart, Item } from "../utils/fragments/cart.ts";
import { state as storeState } from "./context.ts";

export const itemToAnalyticsItem = (
Expand All @@ -9,7 +11,10 @@ export const itemToAnalyticsItem = (
): AnalyticsItem => ({
item_id: item.id,
item_name: item.merchandise.product.title,
discount: item.cost.compareAtAmountPerQuantity ? item.cost.compareAtAmountPerQuantity.amount - item.cost.amountPerQuantity?.amount : 0,
discount: item.cost.compareAtAmountPerQuantity
? item.cost.compareAtAmountPerQuantity.amount -
item.cost.amountPerQuantity?.amount
: 0,
item_variant: item.merchandise.title,
price: item.cost.amountPerQuantity.amount,
index,
Expand All @@ -18,25 +23,30 @@ export const itemToAnalyticsItem = (

const { cart, loading } = storeState;

const wrap =
<T>(action: (p: T, init?: RequestInit | undefined) => Promise<Cart>) =>
(p: T) =>
storeState.enqueue(async (signal) => ({
cart: await action(p, { signal }),
}));
type PropsOf<T> = T extends (props: infer P, r: any, ctx: any) => any ? P
: T extends (props: infer P, r: any) => any ? P
: T extends (props: infer P) => any ? P
: never;

type Actions =
| "shopify/actions/cart/addItems.ts"
| "shopify/actions/cart/updateItems.ts"
| "shopify/actions/cart/updateCoupons.ts";

const action =
(key: Actions) => (props: PropsOf<InvocationFuncFor<Manifest, typeof key>>) =>
storeState.enqueue((signal) =>
invoke({ cart: { key, props } }, { signal }) satisfies Promise<
{ cart: Cart }
>
);

const state = {
cart,
loading,
addItems: wrap(
Runtime.shopify.actions.cart.addItems,
),
updateItems: wrap(
Runtime.shopify.actions.cart.updateItems,
),
addCouponsToCart: wrap(
Runtime.shopify.actions.cart.updateCoupons,
),
addItems: action("shopify/actions/cart/addItems.ts"),
updateItems: action("shopify/actions/cart/updateItems.ts"),
addCouponsToCart: action("shopify/actions/cart/updateCoupons.ts"),
};

export const useCart = () => state;
9 changes: 6 additions & 3 deletions shopify/loaders/ProductDetailsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ProductDetailsPage } from "../../commerce/types.ts";
import { AppContext } from "../../shopify/mod.ts";
import { toProductPage } from "../../shopify/utils/transform.ts";
import type { RequestURLParam } from "../../website/functions/requestToParam.ts";
import { Data, query, Variables } from "../utils/queries/product.ts";

export interface Props {
slug: RequestURLParam;
Expand All @@ -16,16 +17,18 @@ const loader = async (
_req: Request,
ctx: AppContext,
): Promise<ProductDetailsPage | null> => {
const { client } = ctx;
const { storefront } = ctx;
const { slug } = props;

const splitted = slug?.split("-");
const maybeSkuId = Number(splitted[splitted.length - 1]);

const handle = splitted.slice(0, maybeSkuId ? -1 : undefined).join("-");

// search products on Shopify. Feel free to change any of these parameters
const data = await client.product(handle);
const data = await storefront.query<Data, Variables>({
query,
variables: { handle },
});

if (!data?.product) {
return null;
Expand Down
13 changes: 9 additions & 4 deletions shopify/loaders/ProductList.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import type { Product } from "../../commerce/types.ts";
import { AppContext } from "../../shopify/mod.ts";
import {
Data,
query as productsQuery,
Variables,
} from "../utils/queries/products.ts";
import { toProduct } from "../utils/transform.ts";

export interface Props {
Expand All @@ -18,15 +23,15 @@ const loader = async (
_req: Request,
ctx: AppContext,
): Promise<Product[] | null> => {
const { client } = ctx;
const { storefront } = ctx;

const count = props.count ?? 12;
const query = props.query || "";

// search products on Shopify. Feel free to change any of these parameters
const data = await client.products({
first: count,
query,
const data = await storefront.query<Data, Variables>({
query: productsQuery,
variables: { first: count, query },
});

// Transform Shopify product format into schema.org's compatible format
Expand Down
13 changes: 9 additions & 4 deletions shopify/loaders/ProductListingPage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import type { ProductListingPage } from "../../commerce/types.ts";
import { AppContext } from "../../shopify/mod.ts";
import {
Data,
query as productsQuery,
Variables,
} from "../utils/queries/products.ts";
import { toProduct } from "../utils/transform.ts";

export interface Props {
Expand All @@ -24,16 +29,16 @@ const loader = async (
ctx: AppContext,
): Promise<ProductListingPage | null> => {
const url = new URL(req.url);
const { client } = ctx;
const { storefront } = ctx;

const count = props.count ?? 12;
const query = props.query || url.searchParams.get("q") || "";
const page = Number(url.searchParams.get("page")) ?? 0;

// search products on Shopify. Feel free to change any of these parameters
const data = await client.products({
first: count,
query: query,
const data = await storefront.query<Data, Variables>({
query: productsQuery,
variables: { first: count, query: query },
});

// Transform Shopify product format into schema.org's compatible format
Expand Down
Loading

0 comments on commit c577b4d

Please sign in to comment.