From 34c3da34fcaf59f5a61827f3d454ccd1ad787142 Mon Sep 17 00:00:00 2001 From: Sebastian Sangervasi <2236777+ssangervasi@users.noreply.github.com> Date: Tue, 10 Jan 2023 11:28:46 -0800 Subject: [PATCH] pc/consent: Fides.shopify integration function (#2152) --- CHANGELOG.md | 3 + clients/privacy-center/.eslintrc.json | 1 + .../privacy-center/cypress/e2e/consent.cy.ts | 2 +- .../packages/fides-consent/README.md | 52 +++++++++++++- .../fides-consent/src/fides-consent.ts | 26 +++---- .../fides-consent/src/integrations/gtm.ts | 18 +++++ .../fides-consent/src/integrations/shopify.ts | 68 +++++++++++++++++++ 7 files changed, 150 insertions(+), 20 deletions(-) create mode 100644 clients/privacy-center/packages/fides-consent/src/integrations/gtm.ts create mode 100644 clients/privacy-center/packages/fides-consent/src/integrations/shopify.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bf14bb1b0c..25ff2dd762c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ The types of changes are: * Add link to Classify Systems page in nav side bar [#2128](https://github.com/ethyca/fides/pull/2128) * Dataset classification UI now polls for results [#2123](https://github.com/ethyca/fides/pull/2123) * Update Privacy Center Icons [#1800](https://github.com/ethyca/fides/pull/2139) +* Privacy Center `fides-consent.js`: + * `Fides.shopify` integration function. [#2152](https://github.com/ethyca/fides/pull/2152) + * Dedicated folder for integrations. ### Changed diff --git a/clients/privacy-center/.eslintrc.json b/clients/privacy-center/.eslintrc.json index 217dba53a39..b9af6aff4df 100644 --- a/clients/privacy-center/.eslintrc.json +++ b/clients/privacy-center/.eslintrc.json @@ -11,6 +11,7 @@ "rules": { "curly": ["error", "all"], "nonblock-statement-body-position": ["error", "below"], + "import/prefer-default-export": "off", "react/jsx-filename-extension": [1, { "extensions": [".tsx"] }], "react/jsx-props-no-spreading": [0], "react/function-component-definition": [ diff --git a/clients/privacy-center/cypress/e2e/consent.cy.ts b/clients/privacy-center/cypress/e2e/consent.cy.ts index 5d230f226ee..45b60927964 100644 --- a/clients/privacy-center/cypress/e2e/consent.cy.ts +++ b/clients/privacy-center/cypress/e2e/consent.cy.ts @@ -30,7 +30,7 @@ describe("Consent settings", () => { cy.getByTestId("card").contains("Manage your consent").click(); cy.getByTestId("consent-request-form").within(() => { - cy.get("input").type("test@example.com"); + cy.get("input#email").type("test@example.com"); cy.get("button").contains("Continue").click(); }); cy.wait("@postConsentRequest"); diff --git a/clients/privacy-center/packages/fides-consent/README.md b/clients/privacy-center/packages/fides-consent/README.md index e157f84fe18..436c11df0d4 100644 --- a/clients/privacy-center/packages/fides-consent/README.md +++ b/clients/privacy-center/packages/fides-consent/README.md @@ -29,10 +29,36 @@ In this example, `data_sales` is a cookie key that has been [configured in the P The build process for this package pulls in the consent configuration from the Privacy Center's `config.json`. This includes the `cookieKeys` for each consent item as the default options for a -user that has not modified their consent. +user that has not modified their consent. + +For example, the default configuration includes a consent option for advertising: + +```json +{ + "consent": { + "consentOptions": [ + { + "fidesDataUseKey": "advertising", + "name": "Data Sales or Sharing", + "default": true, + "cookieKeys": ["data_sales"] + } + ] + } +} +``` + +When a user visits a page that includes `fides-consent.js` with this configuration, the value of +`Fides.consent.data_sales` will be set to `true` by default. + +If the user visits the Privacy Center and removes their consent for advertising, this choice is +saved in their browser. Subsequent visits to pages that include `fides-consent.js` will have +`Fides.consent.data_sales` set to `false`. -## Google Tag Manager +## Integrations + +### Google Tag Manager Once Fides is loaded in a page, calling `Fides.gtm()` will push the user's consent choices into GTM's dataLayer under `Fides.consent`. @@ -59,7 +85,27 @@ if (Fides.consent.data_sales) { } ``` -## fides-consent.mjs & fides-consent.d.ts +### Shopify + +To integrate with Shopify's [Consent Tracking API](https://shopify.dev/api/consent-tracking?shpxid=7e81a186-C696-4E23-F327-E7F38E5FF5EE#consent-collection), +call `Fides.shopify(options)`, where options is an with the following properties: + +- `tracking`: The only consent option Shopify currently supports. Refer to their [visitor tracking](https://shopify.dev/api/consent-tracking#visitor-tracking) documentation. + +For example, with the default Privacy Center configuration: + +```html + + + + + +``` + +Note that `data_sales` is just an example cookie key. You may configure other data uses that should +be considered tracking, whose cookie key you would pass as the `tracking` option instead. + +## fides-consent.mjs & fides-consent.d.ts This package also exports its library (`src/lib`) as a module the Privacy Center can import. This ensures the Privacy Center uses the exact same logic for reading & writing cookie data. This module is only used locally for convenience and is not published. diff --git a/clients/privacy-center/packages/fides-consent/src/fides-consent.ts b/clients/privacy-center/packages/fides-consent/src/fides-consent.ts index 696346d52da..844570bd10c 100644 --- a/clients/privacy-center/packages/fides-consent/src/fides-consent.ts +++ b/clients/privacy-center/packages/fides-consent/src/fides-consent.ts @@ -6,6 +6,8 @@ // This file is created at build time by `generateConsentConfig` in `rollup.config.js`. import consentConfig from "./consent-config.json"; +import { gtm } from "./integrations/gtm"; +import { shopify } from "./integrations/shopify"; import { getConsentCookie } from "./lib/cookie"; const Fides = { @@ -14,22 +16,14 @@ const Fides = { */ consent: getConsentCookie(consentConfig.defaults), - /** - * Call this to configure Google Tag Manager. The user's consent choices will be - * pushed into GTM's `dataLayer` under `Fides.consent`. - */ - gtm() { - if (typeof window === "undefined") { - return; - } - - const dataLayer: any[] = (window as any)?.dataLayer ?? []; - dataLayer.push({ - Fides: { - consent: Fides.consent, - }, - }); - }, + gtm, + shopify, }; +declare global { + interface Window { + Fides: typeof Fides; + } +} + export default Fides; diff --git a/clients/privacy-center/packages/fides-consent/src/integrations/gtm.ts b/clients/privacy-center/packages/fides-consent/src/integrations/gtm.ts new file mode 100644 index 00000000000..57ff639e916 --- /dev/null +++ b/clients/privacy-center/packages/fides-consent/src/integrations/gtm.ts @@ -0,0 +1,18 @@ +declare global { + interface Window { + dataLayer?: any[]; + } +} + +/** + * Call Fides.gtm to configure Google Tag Manager. The user's consent choices will be + * pushed into GTM's `dataLayer` under `Fides.consent`. + */ +export const gtm = () => { + const dataLayer = window.dataLayer ?? []; + dataLayer.push({ + Fides: { + consent: window.Fides.consent, + }, + }); +}; diff --git a/clients/privacy-center/packages/fides-consent/src/integrations/shopify.ts b/clients/privacy-center/packages/fides-consent/src/integrations/shopify.ts new file mode 100644 index 00000000000..c1af7e36bd2 --- /dev/null +++ b/clients/privacy-center/packages/fides-consent/src/integrations/shopify.ts @@ -0,0 +1,68 @@ +declare global { + interface Window { + Shopify?: { + /** https://shopify.dev/api/consent-tracking#loading-pattern-for-visitor-tracking */ + loadFeatures( + features: Array<{ name: string; version: string }>, + callback: (error: Error) => void + ): void; + customerPrivacy?: { + /** https://shopify.dev/api/consent-tracking#settrackingconsent-consent-boolean-callback-function */ + setTrackingConsent(consent: boolean, callback: () => void): void; + }; + }; + } +} + +type ShopifyOptions = { + tracking: boolean | undefined; +}; + +const applyOptions = (options: ShopifyOptions) => { + if (!window.Shopify?.customerPrivacy) { + throw Error("Fides could not access Shopify's customerPrivacy API"); + } + + window.Shopify.customerPrivacy.setTrackingConsent( + Boolean(options.tracking), + () => {} + ); +}; + +/** + * Call Fides.shopify to configure Shopify customer privacy. Currently the only consent option + * Shopify allows to be configured is user tracking. + * + * @example + * Fides.shopify({ tracking: Fides.consent.data_sales }) + */ +export const shopify = (options: ShopifyOptions) => { + if (!window.Shopify) { + throw Error( + "Fides.shopify was called but Shopify is not present in the page." + ); + } + + // If the API is already present, simply call it. + if (window.Shopify.customerPrivacy) { + applyOptions(options); + return; + } + + // Otherwise we need to load the feature before applying the options. + window.Shopify.loadFeatures( + [ + { + name: "consent-tracking-api", + version: "0.1", + }, + ], + (error) => { + if (error) { + throw Error("Fides could not load Shopify's consent-tracking-api"); + } + + applyOptions(options); + } + ); +};