From 3a4c3456fa1795949e248358ded7442ae1e2fc82 Mon Sep 17 00:00:00 2001 From: Jason Gill Date: Fri, 16 Aug 2024 12:29:30 -0600 Subject: [PATCH 1/6] Add support for Vendor Count in descriptions --- .../src/components/ExperienceDescription.tsx | 34 ++++++++------ .../src/components/tcf/TcfOverlay.tsx | 9 ++++ .../src/components/tcf/VendorInfoBanner.tsx | 10 +++- clients/fides-js/src/lib/consent-types.ts | 1 + .../fides-js/src/lib/i18n/i18n-context.tsx | 4 +- .../fides-js/src/lib/tcf/renderOverlay.tsx | 5 +- .../src/lib/tcf/vendor-button-context.tsx | 46 +++++++++++++++++++ 7 files changed, 90 insertions(+), 19 deletions(-) create mode 100644 clients/fides-js/src/lib/tcf/vendor-button-context.tsx diff --git a/clients/fides-js/src/components/ExperienceDescription.tsx b/clients/fides-js/src/components/ExperienceDescription.tsx index 7277d2228c..b0f8bf8432 100644 --- a/clients/fides-js/src/components/ExperienceDescription.tsx +++ b/clients/fides-js/src/components/ExperienceDescription.tsx @@ -1,6 +1,9 @@ +/* eslint-disable no-template-curly-in-string */ import { h } from "preact"; -const TEXT_TO_LINK = "vendors page."; +import { useVendorButton } from "../lib/tcf/vendor-button-context"; + +const VENDOR_COUNT_LINK = "${VENDOR_COUNT_LINK}"; const ExperienceDescription = ({ description, @@ -11,6 +14,8 @@ const ExperienceDescription = ({ onVendorPageClick?: () => void; allowHTMLDescription?: boolean | null; }) => { + const { vendorCount } = useVendorButton(); + if (!description) { return null; } @@ -29,22 +34,21 @@ const ExperienceDescription = ({ } // Swap out reference to "vendors page" with a button that can go to the vendor page - if ( - onVendorPageClick && - (description.endsWith(TEXT_TO_LINK) || - description.endsWith(`${TEXT_TO_LINK}\n`)) - ) { - const firstPart = description.split(TEXT_TO_LINK)[0]; + if (description.includes(VENDOR_COUNT_LINK)) { + const parts = description.split(VENDOR_COUNT_LINK); return (
- {firstPart}{" "} - + {parts[0]} + {onVendorPageClick && vendorCount && ( + + )} + {parts[1]}
); } diff --git a/clients/fides-js/src/components/tcf/TcfOverlay.tsx b/clients/fides-js/src/components/tcf/TcfOverlay.tsx index 8dab5e09b0..243d58e692 100644 --- a/clients/fides-js/src/components/tcf/TcfOverlay.tsx +++ b/clients/fides-js/src/components/tcf/TcfOverlay.tsx @@ -41,6 +41,7 @@ import type { TCFVendorLegitimateInterestsRecord, TCFVendorSave, } from "../../lib/tcf/types"; +import { useVendorButton } from "../../lib/tcf/vendor-button-context"; import { fetchGvlTranslations } from "../../services/api"; import Button from "../Button"; import ConsentBanner from "../ConsentBanner"; @@ -205,6 +206,8 @@ const TcfOverlay: FunctionComponent = ({ cookie, savedConsent, }) => { + const { setVendorCount } = useVendorButton(); + const initialEnabledIds: EnabledIds = useMemo(() => { const { tcf_purpose_consents: consentPurposes = [], @@ -252,6 +255,12 @@ const TcfOverlay: FunctionComponent = ({ setCurrentLocale(locale); }; + useEffect(() => { + if (experience.vendor_count && setVendorCount) { + setVendorCount(experience.vendor_count); + } + }, [experience, setVendorCount]); + useEffect(() => { if (!currentLocale && locale && defaultLocale) { if (locale !== defaultLocale) { diff --git a/clients/fides-js/src/components/tcf/VendorInfoBanner.tsx b/clients/fides-js/src/components/tcf/VendorInfoBanner.tsx index 965c547324..4175d6c5a9 100644 --- a/clients/fides-js/src/components/tcf/VendorInfoBanner.tsx +++ b/clients/fides-js/src/components/tcf/VendorInfoBanner.tsx @@ -1,8 +1,9 @@ import { h } from "preact"; -import { useMemo } from "preact/hooks"; +import { useEffect, useMemo } from "preact/hooks"; import { PrivacyExperience } from "../../lib/consent-types"; import type { I18n } from "../../lib/i18n"; +import { useVendorButton } from "../../lib/tcf/vendor-button-context"; const VendorInfo = ({ label, @@ -38,6 +39,7 @@ const VendorInfoBanner = ({ i18n: I18n; goToVendorTab: () => void; }) => { + const { setVendorCount } = useVendorButton(); const counts = useMemo(() => { const { tcf_vendor_consents: consentVendors = [], @@ -57,6 +59,12 @@ const VendorInfoBanner = ({ return { total, consent, legint }; }, [experience]); + useEffect(() => { + if (counts.total && setVendorCount) { + setVendorCount(counts.total); + } + }, [counts.total, setVendorCount]); + return (
>; } -const I18nContext = createContext({} as I18nContextProps); +const I18nContext = createContext>({}); export const I18nProvider: FunctionComponent = ({ children }) => { const [currentLocale, setCurrentLocale] = useState(); @@ -41,7 +41,7 @@ export const I18nProvider: FunctionComponent = ({ children }) => { export const useI18n = () => { const context = useContext(I18nContext); - if (!context) { + if (!context || Object.keys(context).length === 0) { throw new Error("useI18n must be used within a I18nProvider"); } return context; diff --git a/clients/fides-js/src/lib/tcf/renderOverlay.tsx b/clients/fides-js/src/lib/tcf/renderOverlay.tsx index 1a8098d5ac..99922e6ab5 100644 --- a/clients/fides-js/src/lib/tcf/renderOverlay.tsx +++ b/clients/fides-js/src/lib/tcf/renderOverlay.tsx @@ -4,6 +4,7 @@ import TcfOverlay from "../../components/tcf/TcfOverlay"; import { OverlayProps } from "../../components/types"; import { I18nProvider } from "../i18n/i18n-context"; import { loadTcfMessagesFromFiles } from "./i18n/tcf-i18n-utils"; +import { VendorButtonProvider } from "./vendor-button-context"; export const renderOverlay = (props: OverlayProps, parent: ContainerNode) => { /** @@ -18,7 +19,9 @@ export const renderOverlay = (props: OverlayProps, parent: ContainerNode) => { render( - + + + , parent, ); diff --git a/clients/fides-js/src/lib/tcf/vendor-button-context.tsx b/clients/fides-js/src/lib/tcf/vendor-button-context.tsx new file mode 100644 index 0000000000..e56acb8209 --- /dev/null +++ b/clients/fides-js/src/lib/tcf/vendor-button-context.tsx @@ -0,0 +1,46 @@ +import { createContext, h } from "preact"; +import { FC } from "preact/compat"; +import { + Dispatch, + StateUpdater, + useContext, + useMemo, + useState, +} from "preact/hooks"; + +interface VendorButtonContextProps { + vendorCount?: number; + setVendorCount: Dispatch>; +} + +const VendorButtonContext = createContext< + VendorButtonContextProps | Record +>({}); + +export const VendorButtonProvider: FC = ({ children }) => { + const [vendorCount, setVendorCount] = useState(); + + const value: VendorButtonContextProps = useMemo( + () => ({ + vendorCount, + setVendorCount, + }), + [vendorCount, setVendorCount], + ); + + return ( + + {children} + + ); +}; + +export const useVendorButton = () => { + const context = useContext(VendorButtonContext); + if (!context || Object.keys(context).length === 0) { + throw new Error( + "useVendorButton must be used within a VendorButtonProvider", + ); + } + return context; +}; From 8c6418c199fc4bda1a439d0a48a384325756b7d5 Mon Sep 17 00:00:00 2001 From: Jason Gill Date: Fri, 16 Aug 2024 14:44:33 -0600 Subject: [PATCH 2/6] fix to include count, even if no button action set --- clients/fides-js/src/components/ExperienceDescription.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clients/fides-js/src/components/ExperienceDescription.tsx b/clients/fides-js/src/components/ExperienceDescription.tsx index b0f8bf8432..19a7dcec31 100644 --- a/clients/fides-js/src/components/ExperienceDescription.tsx +++ b/clients/fides-js/src/components/ExperienceDescription.tsx @@ -39,10 +39,13 @@ const ExperienceDescription = ({ return (
{parts[0]} + {!onVendorPageClick && vendorCount && ( + {vendorCount} + )} {onVendorPageClick && vendorCount && (