Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mobile Native POC support work #5541

Merged
merged 16 commits into from
Dec 3, 2024
Merged
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ The types of changes are:

### Added
- Added new column for Action Type in privacy request event logs [#5546](https://github.com/ethyca/fides/pull/5546)
- Added `fides_consent_override` option in FidesJS SDK [#5541](https://github.com/ethyca/fides/pull/5541)
- Added new `script` ConsentMethod in FidesJS SDK for tracking automated consent [#5541](https://github.com/ethyca/fides/pull/5541)

### Changed
- Adding hashes to system tab URLs [#5535](https://github.com/ethyca/fides/pull/5535)
- Updated Cookie House to be responsive [#5541](https://github.com/ethyca/fides/pull/5541)

### Developer Experience
- Migrated remaining instances of Chakra's Select component to use Ant's Select component [#5502](https://github.com/ethyca/fides/pull/5502)
Expand Down
2 changes: 0 additions & 2 deletions clients/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# Clients

The clients directory houses all front-end packages and shared code amongst clients, and also includes e2e tests.

See the [UI Contribution Guide](http://localhost:8000/fides/development/ui/overview/) for more information
1 change: 1 addition & 0 deletions clients/admin-ui/src/types/api/models/ConsentMethod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export enum ConsentMethod {
BUTTON = "button",
REJECT = "reject",
ACCEPT = "accept",
SCRIPT = "script",
SAVE = "save",
DISMISS = "dismiss",
GPC = "gpc",
Expand Down
16 changes: 15 additions & 1 deletion clients/fides-js/docs/interfaces/FidesOptions.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Interface: FidesOptions

FidesJS supports a variety of custom options to modify it's behavior or
enabled more advanced usage. For example, the `fides_locale` option can be
enable more advanced usage. For example, the `fides_locale` option can be
provided to override the browser locale. See the properties list below for
the supported options and example usage for each.

Expand Down Expand Up @@ -160,3 +160,17 @@ overriden at the page-level as needed. Only applicable to a TCF experience.
For more details, see the [TCF CMP API technical specification](https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20CMP%20API%20v2.md#what-does-the-gdprapplies-value-mean) *

Defaults to `true`.

***

### fides\_consent\_override

> **fides\_consent\_override**: `"accept"` \| `"reject"`

FidesJS will automatically opt in or out of all notices with this option and
only show the consent modal upon user request. This is useful for any
scenario where the user has previously provided consent in a different
context (e.g. a native app, another website, etc.) and you want to ensure
that those preferences are respected.

Defaults to `undefined`.
2 changes: 1 addition & 1 deletion clients/fides-js/rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const GZIP_SIZE_ERROR_KB = 45; // fail build if bundle size exceeds this
const GZIP_SIZE_WARN_KB = 35; // log a warning if bundle size exceeds this

// TCF
const GZIP_SIZE_TCF_ERROR_KB = 85;
const GZIP_SIZE_TCF_ERROR_KB = 85.5;
const GZIP_SIZE_TCF_WARN_KB = 75;

const preactAliases = {
Expand Down
25 changes: 6 additions & 19 deletions clients/fides-js/src/components/ConsentButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useEffect, useState } from "preact/hooks";

import {
ButtonType,
ConsentMechanism,
ConsentMethod,
FidesInitOptions,
PrivacyExperience,
Expand Down Expand Up @@ -139,6 +138,8 @@ type NoticeKeys = Array<PrivacyNotice["notice_key"]>;

interface NoticeConsentButtonProps {
experience: PrivacyExperience;
onAcceptAll: () => void;
onRejectAll: () => void;
onSave: (consentMethod: ConsentMethod, noticeKeys: NoticeKeys) => void;
onManagePreferencesClick?: () => void;
enabledKeys: NoticeKeys;
Expand All @@ -150,6 +151,8 @@ interface NoticeConsentButtonProps {

export const NoticeConsentButtons = ({
experience,
onAcceptAll,
onRejectAll,
onSave,
onManagePreferencesClick,
enabledKeys,
Expand All @@ -164,29 +167,13 @@ export const NoticeConsentButtons = ({
}
const { privacy_notices: notices } = experience;

const handleAcceptAll = () => {
onSave(
ConsentMethod.ACCEPT,
notices.map((n) => n.notice_key),
);
};

const handleAcknowledgeNotices = () => {
onSave(
ConsentMethod.ACKNOWLEDGE,
notices.map((n) => n.notice_key),
);
};

const handleRejectAll = () => {
onSave(
ConsentMethod.REJECT,
notices
.filter((n) => n.consent_mechanism === ConsentMechanism.NOTICE_ONLY)
.map((n) => n.notice_key),
);
};

const handleSave = () => {
onSave(ConsentMethod.SAVE, enabledKeys);
};
Expand Down Expand Up @@ -219,8 +206,8 @@ export const NoticeConsentButtons = ({
<ConsentButtons
availableLocales={experience.available_locales}
onManagePreferencesClick={onManagePreferencesClick}
onAcceptAll={handleAcceptAll}
onRejectAll={handleRejectAll}
onAcceptAll={onAcceptAll}
onRejectAll={onRejectAll}
isInModal={isInModal}
renderFirstButton={renderFirstButton}
hideOptInOut={hideOptInOut}
Expand Down
9 changes: 4 additions & 5 deletions clients/fides-js/src/components/Overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from "preact/hooks";

import { useA11yDialog } from "../lib/a11y-dialog";
import { isConsentOverride } from "../lib/common-utils";
import { FIDES_OVERLAY_WRAPPER } from "../lib/consent-constants";
import {
ComponentType,
Expand All @@ -32,7 +33,6 @@ interface RenderBannerProps {
isOpen: boolean;
isEmbedded: boolean;
onClose: () => void;
onSave: () => void;
onManagePreferencesClick: () => void;
}

Expand Down Expand Up @@ -72,13 +72,15 @@ const Overlay: FunctionComponent<Props> = ({
const delayBannerMilliseconds = 100;
const delayModalLinkMilliseconds = 200;
const hasMounted = useHasMounted();
const isAutomatedConsent = isConsentOverride(options);

const showBanner = useMemo(
() =>
!isAutomatedConsent &&
!options.fidesDisableBanner &&
experience.experience_config?.component !== ComponentType.MODAL &&
shouldResurfaceConsent(experience, cookie, savedConsent),
[cookie, savedConsent, experience, options],
[cookie, savedConsent, experience, options, isAutomatedConsent],
);

const [bannerIsOpen, setBannerIsOpen] = useState(
Expand Down Expand Up @@ -237,9 +239,6 @@ const Overlay: FunctionComponent<Props> = ({
onClose: () => {
setBannerIsOpen(false);
},
onSave: () => {
setBannerIsOpen(false);
},
Comment on lines -240 to -242
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onSave was just superfluous and confusing so I removed it in favor of onClose everywhere.

onManagePreferencesClick: handleManagePreferencesClick,
})
: null}
Expand Down
61 changes: 59 additions & 2 deletions clients/fides-js/src/components/notices/NoticeOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import "../fides.css";
import { FunctionComponent, h } from "preact";
import { useCallback, useEffect, useMemo, useState } from "preact/hooks";

import { isConsentOverride } from "../../lib/common-utils";
import { getConsentContext } from "../../lib/consent-context";
import {
ConsentMechanism,
Expand Down Expand Up @@ -229,6 +230,47 @@ const NoticeOverlay: FunctionComponent<OverlayProps> = ({
],
);

const handleAcceptAll = useCallback(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bumped these up to parent to take advantage of them at this level for the automated preference

(wasAutomated?: boolean) => {
handleUpdatePreferences(
wasAutomated ? ConsentMethod.SCRIPT : ConsentMethod.ACCEPT,
privacyNoticeItems.map((n) => n.notice.notice_key),
);
},
[handleUpdatePreferences, privacyNoticeItems],
);

const handleRejectAll = useCallback(
(wasAutomated?: boolean) => {
handleUpdatePreferences(
wasAutomated ? ConsentMethod.SCRIPT : ConsentMethod.REJECT,
privacyNoticeItems
.filter(
(n) => n.notice.consent_mechanism === ConsentMechanism.NOTICE_ONLY,
)
.map((n) => n.notice.notice_key),
);
},
[handleUpdatePreferences, privacyNoticeItems],
);

useEffect(() => {
if (isConsentOverride(options) && experience.privacy_notices) {
if (options.fidesConsentOverride === ConsentMethod.ACCEPT) {
fidesDebugger(
"Consent automatically accepted by fides_accept_all override!",
);
handleAcceptAll(true);
} else if (options.fidesConsentOverride === ConsentMethod.REJECT) {
fidesDebugger(
"Consent automatically rejected by fides_reject_all override!",
);
handleRejectAll(true);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [experience.privacy_notices, options.fidesConsentOverride]);

const dispatchOpenBannerEvent = useCallback(() => {
dispatchFidesEvent("FidesUIShown", cookie, options.debug, {
servingComponent: ServingComponent.BANNER,
Expand Down Expand Up @@ -268,7 +310,6 @@ const NoticeOverlay: FunctionComponent<OverlayProps> = ({
isEmbedded,
isOpen,
onClose,
onSave,
onManagePreferencesClick,
}) => {
const isAcknowledge =
Expand All @@ -290,12 +331,20 @@ const NoticeOverlay: FunctionComponent<OverlayProps> = ({
experience={experience}
onManagePreferencesClick={onManagePreferencesClick}
enabledKeys={draftEnabledNoticeKeys}
onAcceptAll={() => {
handleAcceptAll();
onClose();
}}
onRejectAll={() => {
handleRejectAll();
onClose();
}}
onSave={(
consentMethod: ConsentMethod,
keys: Array<PrivacyNotice["notice_key"]>,
) => {
handleUpdatePreferences(consentMethod, keys);
onSave();
onClose();
}}
isAcknowledge={isAcknowledge}
hideOptInOut={isAcknowledge}
Expand Down Expand Up @@ -323,6 +372,14 @@ const NoticeOverlay: FunctionComponent<OverlayProps> = ({
<NoticeConsentButtons
experience={experience}
enabledKeys={draftEnabledNoticeKeys}
onAcceptAll={() => {
handleAcceptAll();
onClose();
}}
onRejectAll={() => {
handleRejectAll();
onClose();
}}
onSave={(
consentMethod: ConsentMethod,
keys: Array<PrivacyNotice["notice_key"]>,
Expand Down
79 changes: 6 additions & 73 deletions clients/fides-js/src/components/tcf/TcfConsentButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,27 @@
import { h, VNode } from "preact";

import {
ConsentMethod,
FidesInitOptions,
PrivacyExperience,
PrivacyExperienceMinimal,
} from "../../lib/consent-types";
import type { EnabledIds, TcfModels } from "../../lib/tcf/types";
import { ConsentButtons } from "../ConsentButtons";

interface TcfConsentButtonProps {
experience: PrivacyExperience | PrivacyExperienceMinimal;
options: FidesInitOptions;
onManagePreferencesClick?: () => void;
onSave: (consentMethod: ConsentMethod, keys: EnabledIds) => void;
onRejectAll: () => void;
onAcceptAll: () => void;
renderFirstButton?: () => VNode;
isInModal?: boolean;
}

const getAllIds = (modelList: TcfModels) => {
if (!modelList) {
return [];
}
return modelList.map((m) => `${m.id}`);
};

export const TcfConsentButtons = ({
experience,
onManagePreferencesClick,
onSave,
onRejectAll,
onAcceptAll,
renderFirstButton,
isInModal,
options,
Expand All @@ -39,72 +32,12 @@ export const TcfConsentButtons = ({

const isGVLLoading = Object.keys(experience.gvl || {}).length === 0;

const handleAcceptAll = () => {
let allIds: EnabledIds;
if (!experience.minimal_tcf) {
// eslint-disable-next-line no-param-reassign
experience = experience as PrivacyExperience;
allIds = {
purposesConsent: getAllIds(experience.tcf_purpose_consents),
purposesLegint: getAllIds(experience.tcf_purpose_legitimate_interests),
specialPurposes: getAllIds(experience.tcf_special_purposes),
features: getAllIds(experience.tcf_features),
specialFeatures: getAllIds(experience.tcf_special_features),
vendorsConsent: getAllIds([
...(experience.tcf_vendor_consents || []),
...(experience.tcf_system_consents || []),
]),
vendorsLegint: getAllIds([
...(experience.tcf_vendor_legitimate_interests || []),
...(experience.tcf_system_legitimate_interests || []),
]),
};
} else {
// eslint-disable-next-line no-param-reassign
experience = experience as PrivacyExperienceMinimal;
allIds = {
purposesConsent:
experience.tcf_purpose_consent_ids?.map((id) => `${id}`) || [],
purposesLegint:
experience.tcf_purpose_legitimate_interest_ids?.map(
(id) => `${id}`,
) || [],
specialPurposes:
experience.tcf_special_purpose_ids?.map((id) => `${id}`) || [],
features: experience.tcf_feature_ids?.map((id) => `${id}`) || [],
specialFeatures:
experience.tcf_special_feature_ids?.map((id) => `${id}`) || [],
vendorsConsent: [
...(experience.tcf_vendor_consent_ids || []),
...(experience.tcf_system_consent_ids || []),
],
vendorsLegint: [
...(experience.tcf_vendor_legitimate_interest_ids || []),
...(experience.tcf_system_legitimate_interest_ids || []),
],
};
}
onSave(ConsentMethod.ACCEPT, allIds);
};
const handleRejectAll = () => {
const emptyIds: EnabledIds = {
purposesConsent: [],
purposesLegint: [],
specialPurposes: [],
features: [],
specialFeatures: [],
vendorsConsent: [],
vendorsLegint: [],
};
onSave(ConsentMethod.REJECT, emptyIds);
};

return (
<ConsentButtons
availableLocales={experience.available_locales}
onManagePreferencesClick={onManagePreferencesClick}
onAcceptAll={handleAcceptAll}
onRejectAll={handleRejectAll}
onAcceptAll={onAcceptAll}
onRejectAll={onRejectAll}
renderFirstButton={renderFirstButton}
isInModal={isInModal}
options={options}
Expand Down
Loading
Loading