Skip to content

Commit

Permalink
GPC indication on fides-js overlay (#3673)
Browse files Browse the repository at this point in the history
  • Loading branch information
allisonking authored Jun 28, 2023
1 parent 0337c66 commit dd7ebfa
Show file tree
Hide file tree
Showing 21 changed files with 372 additions and 78 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The types of changes are:

### Added
- Empty state for when there are no relevant privacy notices in the privacy center [#3640](https://github.com/ethyca/fides/pull/3640)
- GPC indicators in fides-js banner and modal [#3673](https://github.com/ethyca/fides/pull/3673)
- Set `sslmode` to `prefer` if connecting to Redshift via ssh [#3685](https://github.com/ethyca/fides/pull/3685)

### Fixed
Expand Down
10 changes: 2 additions & 8 deletions clients/fides-js/src/components/CloseButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,10 @@ const CloseButton = ({
className="fides-close-button"
onClick={onClick}
>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none">
<path
d="M7.99999 7.05732L11.3 3.75732L12.2427 4.69999L8.94266 7.99999L12.2427 11.3L11.3 12.2427L7.99999 8.94266L4.69999 12.2427L3.75732 11.3L7.05732 7.99999L3.75732 4.69999L4.69999 3.75732L7.99999 7.05732Z"
fill="#2D3748"
d="m8 7.057 3.3-3.3.943.943-3.3 3.3 3.3 3.3-.943.943-3.3-3.3-3.3 3.3-.943-.943 3.3-3.3-3.3-3.3.943-.943 3.3 3.3Z"
/>
</svg>
</button>
Expand Down
52 changes: 34 additions & 18 deletions clients/fides-js/src/components/ConsentBanner.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { h, FunctionComponent, VNode } from "preact";
import { getConsentContext } from "../lib/consent-context";
import { ExperienceConfig } from "../lib/consent-types";
import CloseButton from "./CloseButton";
import { GpcBadge } from "./GpcBadge";

interface BannerProps {
experience: ExperienceConfig;
Expand All @@ -14,26 +16,40 @@ const ConsentBanner: FunctionComponent<BannerProps> = ({
buttonGroup,
onClose,
bannerIsOpen,
}) => (
<div
id="fides-banner-container"
className={`fides-banner fides-banner-bottom ${
bannerIsOpen ? "" : "fides-banner-hidden"
} `}
>
<div id="fides-banner">
<div id="fides-banner-inner">
<CloseButton ariaLabel="Close banner" onClick={onClose} />
<div id="fides-banner-title" className="fides-banner-title">
{experience.title}
}) => {
const showGpcBadge = getConsentContext().globalPrivacyControl;
return (
<div
id="fides-banner-container"
className={`fides-banner fides-banner-bottom ${
bannerIsOpen ? "" : "fides-banner-hidden"
} `}
>
<div id="fides-banner">
<div id="fides-banner-inner">
<CloseButton ariaLabel="Close banner" onClick={onClose} />
<div id="fides-banner-heading">
<div id="fides-banner-title" className="fides-banner-title">
{experience.title}
</div>
{showGpcBadge ? (
<GpcBadge
label="Global Privacy Control Signal"
status="detected"
/>
) : null}
</div>
<div
id="fides-banner-description"
className="fides-banner-description"
>
{experience.description}
</div>
{buttonGroup}
</div>
<div id="fides-banner-description" className="fides-banner-description">
{experience.description}
</div>
{buttonGroup}
</div>
</div>
</div>
);
);
};

export default ConsentBanner;
2 changes: 2 additions & 0 deletions clients/fides-js/src/components/ConsentModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Attributes } from "../lib/a11y-dialog";
import { PrivacyNotice, ExperienceConfig } from "../lib/consent-types";
import NoticeToggles from "./NoticeToggles";
import CloseButton from "./CloseButton";
import GpcInfo from "./GpcInfo";

type NoticeKeys = Array<PrivacyNotice["notice_key"]>;

Expand Down Expand Up @@ -51,6 +52,7 @@ const ConsentModal = ({
>
{experience.description}
</p>
<GpcInfo />
<div className="fides-modal-notices">
<NoticeToggles
notices={notices}
Expand Down
36 changes: 36 additions & 0 deletions clients/fides-js/src/components/GpcBadge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { h } from "preact";
import { GpcStatus, PrivacyNotice } from "../lib/consent-types";
import { getConsentContext } from "../lib/consent-context";
import { getGpcStatusFromNotice } from "../lib/consent-utils";

export const GpcBadge = ({
label,
status,
}: {
label: string;
status: string;
}) => (
<span className="fides-gpc-label">
{label}{" "}
<span className={`fides-gpc-badge fides-gpc-badge-${status}`}>
{status}
</span>
</span>
);

export const GpcBadgeForNotice = ({
value,
notice,
}: {
value: boolean;
notice: PrivacyNotice;
}) => {
const consentContext = getConsentContext();
const status = getGpcStatusFromNotice({ value, notice, consentContext });

if (status === GpcStatus.NONE) {
return null;
}

return <GpcBadge label="Global Privacy Control" status={status.valueOf()} />;
};
29 changes: 29 additions & 0 deletions clients/fides-js/src/components/GpcInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { h } from "preact";
import WarningIcon from "./WarningIcon";
import { getConsentContext } from "../lib/consent-context";

const GpcInfo = () => {
const context = getConsentContext();

if (!context.globalPrivacyControl) {
return null;
}

return (
<div className="fides-gpc-banner">
<div className="fides-gpc-warning">
<WarningIcon />
</div>
<div>
<p className="fides-gpc-header">Global Privacy Control detected</p>
<p>
Your global privacy control preference has been honored. You have been
automatically opted out of data uses cases which adhere to global
privacy control.
</p>
</div>
</div>
);
};

export default GpcInfo;
3 changes: 3 additions & 0 deletions clients/fides-js/src/components/NoticeToggles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ConsentMechanism, PrivacyNotice } from "../lib/consent-types";
import Toggle from "./Toggle";
import Divider from "./Divider";
import { useDisclosure } from "../lib/hooks";
import { GpcBadgeForNotice } from "./GpcBadge";

const NoticeToggle = ({
notice,
Expand Down Expand Up @@ -46,7 +47,9 @@ const NoticeToggle = ({
className="fides-notice-toggle-trigger"
>
{notice.name}
<GpcBadgeForNotice notice={notice} value={checked} />
</span>

<Toggle
name={notice.name || ""}
id={notice.notice_key}
Expand Down
14 changes: 14 additions & 0 deletions clients/fides-js/src/components/WarningIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { h } from "preact";

const WarningIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
fill="currentColor"
>
<path d="M9 12.05a.68.68 0 0 0-.68.7c0 .39.32.7.68.7.39 0 .68-.31.68-.7a.66.66 0 0 0-.68-.7Zm0-1.18c.26 0 .44-.2.44-.46V6.19c0-.26-.2-.47-.44-.47a.49.49 0 0 0-.47.47v4.22c0 .25.21.46.47.46Zm7.27 2.27-5.85-9.9c-.3-.5-.83-.8-1.42-.8-.6 0-1.12.3-1.42.8l-5.86 9.9c-.3.5-.3 1.1-.01 1.6.3.51.83.82 1.43.82h11.72c.6 0 1.13-.3 1.43-.82.29-.5.28-1.1-.02-1.6Zm-.82 1.1c-.1.25-.33.38-.62.38H3.14a.7.7 0 0 1-.61-.35.64.64 0 0 1 0-.65l5.86-9.9A.7.7 0 0 1 9 3.37a.7.7 0 0 1 .61.35l5.86 9.9c.1.2.12.44-.02.63Z" />
</svg>
);

export default WarningIcon;
64 changes: 62 additions & 2 deletions clients/fides-js/src/components/fides.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
--fides-overlay-font-color: #4a5568;
--fides-overlay-font-color-dark: #2d3748;
--fides-overlay-hover-color: #edf2f7;
--fides-overlay-gpc-applied-background-color: #38a169;
--fides-overlay-gpc-applied-text-color: white;
--fides-overlay-gpc-overridden-background-color: #e53e3e;
--fides-overlay-gpc-overridden-text-color: white;
/* Buttons */
--fides-overlay-primary-button-background-color: var(
--fides-overlay-primary-color
Expand Down Expand Up @@ -143,6 +147,12 @@ div#fides-banner-container.fides-banner-top.fides-banner-hidden {
}
}

div#fides-banner-heading {
display: flex;
margin-right: 0.8em;
align-items: center;
}

div#fides-banner-title {
font-size: var(--fides-overlay-font-size-title);
font-weight: 600;
Expand Down Expand Up @@ -286,8 +296,8 @@ div#fides-modal .fides-modal-button-group {

.fides-close-button {
position: absolute;
top: 1em;
right: 1em;
top: 0.5em;
right: 0.2em;
cursor: pointer;
background: none;
border: none;
Expand Down Expand Up @@ -423,10 +433,15 @@ div#fides-modal .fides-modal-button-group {
padding: 0.5em;
display: flex;
justify-content: space-between;
min-height: 40px;
align-items: center;
}

.fides-notice-toggle .fides-notice-toggle-trigger {
width: 100%;
display: flex;
justify-content: space-between;
margin-right: 0.5em;
}

.fides-notice-toggle .fides-notice-toggle-title:hover {
Expand All @@ -441,3 +456,48 @@ div#fides-modal .fides-modal-button-group {
.fides-notice-toggle-expanded {
background-color: var(--fides-overlay-row-hover-color);
}

/* GPC */
.fides-gpc-banner {
border: 1px solid var(--fides-overlay-primary-color);
border-radius: var(--fides-overlay-component-border-radius);
display: flex;
padding: 1.1em;
margin-bottom: 1em;
}

.fides-gpc-banner p {
margin: 0;
}

.fides-gpc-warning {
color: var(--fides-overlay-primary-color);
margin-right: 0.5em;
}

.fides-gpc-header {
font-weight: 700;
}

.fides-gpc-label {
font-weight: 600;
font-size: 0.9em;
}

.fides-gpc-badge {
text-transform: uppercase;
padding: 0 4px;
font-weight: 700;
border-radius: var(--fides-overlay-button-border-radius);
}

.fides-gpc-badge-applied,
.fides-gpc-badge-detected {
background: var(--fides-overlay-gpc-applied-background-color);
color: var(--fides-overlay-gpc-applied-text-color);
}

.fides-gpc-badge-overridden {
background: var(--fides-overlay-gpc-overridden-background-color);
color: var(--fides-overlay-gpc-overridden-text-color);
}
34 changes: 25 additions & 9 deletions clients/fides-js/src/fides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import {
UserGeolocation,
ConsentMethod,
SaveConsentPreference,
ConsentMechanism,
} from "./lib/consent-types";
import {
constructFidesRegionString,
Expand All @@ -79,6 +80,7 @@ import { fetchExperience } from "./services/fides/api";
import { getGeolocation } from "./services/external/geolocation";
import { OverlayProps } from "./components/Overlay";
import { updateConsentPreferences } from "./lib/preferences";
import { resolveConsentValue } from "./lib/consent-value";

export type Fides = {
consent: CookieKeyConsent;
Expand Down Expand Up @@ -131,26 +133,40 @@ const automaticallyApplyGPCPreferences = (
fidesApiUrl: string,
effectiveExperience?: PrivacyExperience | null
) => {
if (!effectiveExperience) {
if (!effectiveExperience || !effectiveExperience.privacy_notices) {
return;
}

if (!getConsentContext().globalPrivacyControl) {
const context = getConsentContext();
if (!context.globalPrivacyControl) {
return;
}

const consentPreferencesToSave: Array<SaveConsentPreference> = [];
effectiveExperience.privacy_notices?.forEach((notice) => {
if (notice.has_gpc_flag && !notice.current_preference) {
consentPreferencesToSave.push(
new SaveConsentPreference(
let gpcApplied = false;
const consentPreferencesToSave = effectiveExperience.privacy_notices.map(
(notice) => {
if (
notice.has_gpc_flag &&
!notice.current_preference &&
notice.consent_mechanism !== ConsentMechanism.NOTICE_ONLY
) {
gpcApplied = true;
return new SaveConsentPreference(
notice,
transformConsentToFidesUserPreference(false, notice.consent_mechanism)
);
}
return new SaveConsentPreference(
notice,
transformConsentToFidesUserPreference(
resolveConsentValue(notice, context),
notice.consent_mechanism
)
);
}
});
if (consentPreferencesToSave.length > 0) {
);

if (gpcApplied) {
updateConsentPreferences({
consentPreferencesToSave,
experienceId: effectiveExperience.id,
Expand Down
9 changes: 9 additions & 0 deletions clients/fides-js/src/lib/consent-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,15 @@ export enum RequestOrigin {
api = "api",
}

export enum GpcStatus {
/** GPC is not relevant for the consent option. */
NONE = "none",
/** GPC is enabled and consent matches the configured default. */
APPLIED = "applied",
/** GPC is enabled but consent has been set to override the configured default. */
OVERRIDDEN = "overridden",
}

// ------------------LEGACY TYPES BELOW -------------------

export type ConditionalValue = {
Expand Down
Loading

0 comments on commit dd7ebfa

Please sign in to comment.