From 529605cf185b25a091fa0bef2e1ed667f4cd9211 Mon Sep 17 00:00:00 2001 From: "Juan P. Prieto" Date: Thu, 12 Jan 2023 10:44:58 -0800 Subject: [PATCH 1/6] add support for parsing complex gids and fix failing test --- packages/react/src/analytics-utils.ts | 56 ++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/packages/react/src/analytics-utils.ts b/packages/react/src/analytics-utils.ts index 7abb3899..5de2d921 100644 --- a/packages/react/src/analytics-utils.ts +++ b/packages/react/src/analytics-utils.ts @@ -23,29 +23,65 @@ export function schemaWrapper(schemaId: string, payload: object) { } /** - * Parses global id (gid) and returns the resource type and id. + * Parses global id (gid) and returns the resource, subResource (complex gid only) and id. * @see https://shopify.dev/api/usage/gids * @param gid - A shopify GID (string) - * @returns \{ id: number, resource: string \} + * @returns \{ id: string | number | null, resource: string| null, subResource: string | null \} * * @example * ```ts * const {id, resource} = parseGid('gid://shopify/Order/123') * // => id = 123, resource = 'Order' + * + * * const {id, resource} = parseGid('gid://shopify/Cart/abc123') + * // => id = "abc123", resource = 'Cart' + * * ``` **/ export function parseGid(gid: string | undefined): { - id: number | null; + id: string | number | null; resource: string | null; + subResource: string | null; } { - if (typeof gid !== 'string') return {id: null, resource: null}; - const matches = gid.match(/^gid:\/\/.hopify\/(\w+)\/(\d+)/); - if (!matches || matches.length === 1) { - return {id: null, resource: null}; + const defaultReturn = {id: null, resource: null, subResource: null}; + + if (typeof gid !== 'string') { + return defaultReturn; + } + + // complex gids have the following format https://shopify.dev/api/usage/gids#parameterized-global-ids + // TODO: add support for parsing query parameters on complex gids + const isComplexGid = /gid:\/\/shopify\/(\w+)\/(\w+)\/([a-z0-9]+)/.test(gid); + + let matches, + id, + resource, + subResource = null; + + if (isComplexGid) { + matches = gid.match(/^gid:\/\/.hopify\/(\w+)\/(\w+)\/([a-z0-9]+)/); + + if (!matches || matches.length === 1) { + return defaultReturn; + } + id = matches[3] ? matches[3] : null; + subResource = matches[2] ? matches[2] : null; + resource = matches[1] ? matches[1] : null; + } else { + matches = gid.match(/^gid:\/\/.hopify\/(\w+)\/([a-z0-9]+)/); + + if (!matches || matches.length === 1) { + return defaultReturn; + } + id = matches[2] ? matches[2] : null; + resource = matches[1] ? matches[1] : null; + } + + // if id is comprasied of only numbers, return as an integer + if (id && /^\d+$/.test(id)) { + return {id: parseInt(id, 10), resource, subResource}; } - const id = matches[2] ? parseInt(matches[2], 10) : null; - const resource = matches[1] ? matches[1] : null; - return {id, resource}; + return {id, resource, subResource}; } /** From 851d24cdc0222356fcde2e5323af9038a18d8d59 Mon Sep 17 00:00:00 2001 From: "Juan P. Prieto" Date: Thu, 12 Jan 2023 10:50:04 -0800 Subject: [PATCH 2/6] shorten cond checks --- packages/react/src/analytics-utils.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/react/src/analytics-utils.ts b/packages/react/src/analytics-utils.ts index 5de2d921..0abefab4 100644 --- a/packages/react/src/analytics-utils.ts +++ b/packages/react/src/analytics-utils.ts @@ -64,17 +64,17 @@ export function parseGid(gid: string | undefined): { if (!matches || matches.length === 1) { return defaultReturn; } - id = matches[3] ? matches[3] : null; - subResource = matches[2] ? matches[2] : null; - resource = matches[1] ? matches[1] : null; + id = matches[3] ?? null; + subResource = matches[2] ?? null; + resource = matches[1] ?? null; } else { matches = gid.match(/^gid:\/\/.hopify\/(\w+)\/([a-z0-9]+)/); if (!matches || matches.length === 1) { return defaultReturn; } - id = matches[2] ? matches[2] : null; - resource = matches[1] ? matches[1] : null; + id = matches[2] ?? null; + resource = matches[1] ?? null; } // if id is comprasied of only numbers, return as an integer From 61cbd46177e17d79d71d411a07b3115a3478a330 Mon Sep 17 00:00:00 2001 From: "Juan P. Prieto" Date: Thu, 12 Jan 2023 10:57:34 -0800 Subject: [PATCH 3/6] remove incorrect complex id parsing --- packages/react/src/analytics-utils.ts | 41 +++++++-------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/packages/react/src/analytics-utils.ts b/packages/react/src/analytics-utils.ts index 0abefab4..0f210426 100644 --- a/packages/react/src/analytics-utils.ts +++ b/packages/react/src/analytics-utils.ts @@ -23,10 +23,10 @@ export function schemaWrapper(schemaId: string, payload: object) { } /** - * Parses global id (gid) and returns the resource, subResource (complex gid only) and id. + * Parses global id (gid) and returns the resource type and id. * @see https://shopify.dev/api/usage/gids * @param gid - A shopify GID (string) - * @returns \{ id: string | number | null, resource: string| null, subResource: string | null \} + * @returns \{ id: string | number | null, resource: string| null \} * * @example * ```ts @@ -35,53 +35,32 @@ export function schemaWrapper(schemaId: string, payload: object) { * * * const {id, resource} = parseGid('gid://shopify/Cart/abc123') * // => id = "abc123", resource = 'Cart' - * * ``` **/ export function parseGid(gid: string | undefined): { id: string | number | null; resource: string | null; - subResource: string | null; } { - const defaultReturn = {id: null, resource: null, subResource: null}; + const defaultReturn = {id: null, resource: null}; if (typeof gid !== 'string') { return defaultReturn; } - // complex gids have the following format https://shopify.dev/api/usage/gids#parameterized-global-ids // TODO: add support for parsing query parameters on complex gids - const isComplexGid = /gid:\/\/shopify\/(\w+)\/(\w+)\/([a-z0-9]+)/.test(gid); - - let matches, - id, - resource, - subResource = null; + const matches = gid.match(/^gid:\/\/.hopify\/(\w+)\/([a-z0-9]+)/); - if (isComplexGid) { - matches = gid.match(/^gid:\/\/.hopify\/(\w+)\/(\w+)\/([a-z0-9]+)/); - - if (!matches || matches.length === 1) { - return defaultReturn; - } - id = matches[3] ?? null; - subResource = matches[2] ?? null; - resource = matches[1] ?? null; - } else { - matches = gid.match(/^gid:\/\/.hopify\/(\w+)\/([a-z0-9]+)/); - - if (!matches || matches.length === 1) { - return defaultReturn; - } - id = matches[2] ?? null; - resource = matches[1] ?? null; + if (!matches || matches.length === 1) { + return defaultReturn; } + const id = matches[2] ?? null; + const resource = matches[1] ?? null; // if id is comprasied of only numbers, return as an integer if (id && /^\d+$/.test(id)) { - return {id: parseInt(id, 10), resource, subResource}; + return {id: parseInt(id, 10), resource}; } - return {id, resource, subResource}; + return {id, resource}; } /** From d6e9a10ff95422433b9beb82cf7d19ac396c83cd Mon Sep 17 00:00:00 2001 From: "Juan P. Prieto" Date: Thu, 12 Jan 2023 10:59:50 -0800 Subject: [PATCH 4/6] fix typo --- packages/react/src/analytics-utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/analytics-utils.ts b/packages/react/src/analytics-utils.ts index 0f210426..f9b48cff 100644 --- a/packages/react/src/analytics-utils.ts +++ b/packages/react/src/analytics-utils.ts @@ -56,7 +56,7 @@ export function parseGid(gid: string | undefined): { const id = matches[2] ?? null; const resource = matches[1] ?? null; - // if id is comprasied of only numbers, return as an integer + // if id is of only numbers, return as an integer if (id && /^\d+$/.test(id)) { return {id: parseInt(id, 10), resource}; } From 49ed5c686106f1db28363ee083f00423a28929c4 Mon Sep 17 00:00:00 2001 From: "Juan P. Prieto" Date: Thu, 12 Jan 2023 12:13:05 -0800 Subject: [PATCH 5/6] add cookie util test --- packages/react/src/cookie-utils.test.ts | 31 +++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 packages/react/src/cookie-utils.test.ts diff --git a/packages/react/src/cookie-utils.test.ts b/packages/react/src/cookie-utils.test.ts new file mode 100644 index 00000000..e3a8b345 --- /dev/null +++ b/packages/react/src/cookie-utils.test.ts @@ -0,0 +1,31 @@ +import { + buildUUID, + hexTime, + getShopifyCookies, + ShopifyCookies, +} from './cookies-utils.js'; + +describe('cookies-utils', () => { + describe('buildUUID', () => { + it('returns a string', () => { + expect(typeof buildUUID()).toBe('string'); + }); + }); + + describe('hexTime', () => { + it('returns a string', () => { + expect(typeof hexTime()).toBe('string'); + }); + }); + + describe('getShopifyCookies', () => { + it('returns object with SHOPIFY_Y and SHOPIFY_X', () => { + const cookie = + '_shopify_m=persistent; _y=44c60bb0-577c-4901-874c-92cb323fccf1; _shopify_y=44c60bb0-577c-4901-874c-92cb323fccf1; _shopify_y=44c60bb0-577c-4901-874c-92cb323fccf1; _tracking_consent={"lim":["GDPR"],"v":"2.0","con":{"GDPR":""},"reg":"CCPA"}; _shopify_s=a797b9ef-C0E7-4536-18BA-2828BA504882'; + expect(getShopifyCookies(cookie)).toMatchObject({ + _shopify_y: '44c60bb0-577c-4901-874c-92cb323fccf1', + _shopify_s: 'a797b9ef-C0E7-4536-18BA-2828BA504882', + }); + }); + }); +}); From 2a5c4fe21fcd6009cc5eab239266136fc729a5b9 Mon Sep 17 00:00:00 2001 From: "Juan P. Prieto" Date: Thu, 12 Jan 2023 12:21:05 -0800 Subject: [PATCH 6/6] add jsdoc to ShopifyCookies --- packages/react/src/ShopifyCookies.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/react/src/ShopifyCookies.tsx b/packages/react/src/ShopifyCookies.tsx index 3fd9c3f1..0a5764ab 100644 --- a/packages/react/src/ShopifyCookies.tsx +++ b/packages/react/src/ShopifyCookies.tsx @@ -16,6 +16,17 @@ interface ShopifyCookiesProps { hasUserConsent?: boolean; } +/** + * Set user and session cookies and refresh the expiry time + * @param domain - The domain scope of the cookie + * @param hasUserConsent - Defaults to false. If hasUserConsent is true, we can set Shopify unique user token cookie + * @example + * ```tsx + * import {ShopifyCookies} from '@shopify/hydrogen-react'; + * + * + * ``` + */ export function ShopifyCookies(props: ShopifyCookiesProps) { const {domain = '', hasUserConsent = false} = props;