Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions accounts/shopify.ts
Original file line number Diff line number Diff line change
@@ -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";
1 change: 1 addition & 0 deletions actions/shopify/cart/addItems.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "deco-sites/std/packs/shopify/actions/cart/addItems.ts";
1 change: 1 addition & 0 deletions actions/shopify/cart/updateCoupons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "deco-sites/std/packs/shopify/actions/cart/updateCoupons.ts";
1 change: 1 addition & 0 deletions actions/shopify/cart/updateItems.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "deco-sites/std/packs/shopify/actions/cart/updateItems.ts";
Binary file modified doccache.zst
Binary file not shown.
384 changes: 196 additions & 188 deletions live.gen.ts

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions loaders/shopify/cart.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "deco-sites/std/packs/shopify/loaders/cart.ts";
25 changes: 25 additions & 0 deletions packs/shopify/accounts/shopify.ts
Original file line number Diff line number Diff line change
@@ -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;
51 changes: 51 additions & 0 deletions packs/shopify/actions/cart/addItems.ts
Original file line number Diff line number Diff line change
@@ -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<Cart> => {
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;
50 changes: 50 additions & 0 deletions packs/shopify/actions/cart/updateCoupons.ts
Original file line number Diff line number Diff line change
@@ -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<Cart> => {
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;
49 changes: 49 additions & 0 deletions packs/shopify/actions/cart/updateItems.ts
Original file line number Diff line number Diff line change
@@ -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<Cart> => {
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;
51 changes: 51 additions & 0 deletions packs/shopify/client.ts
Original file line number Diff line number Diff line change
@@ -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<Account> = {}) => {
return async <T>(
query: string,
fragments: string[] = [],
variables: Record<string, unknown> = {},
) => {
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<typeof createShopifyClient> | undefined;

export const getShopifyClient = (config: Partial<Account> = {}) => {
if (!shopifyClient) {
shopifyClient = createShopifyClient(config);
}

return shopifyClient;
};
1 change: 1 addition & 0 deletions packs/shopify/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const SHOPIFY_COOKIE_NAME = "shopify_cart_id";
Loading