Skip to content

Commit

Permalink
Make transcend API object an EventTarget and dispatch `view-state-c…
Browse files Browse the repository at this point in the history
…hange` events (#129)
  • Loading branch information
bencmbrook authored Jul 11, 2023
1 parent 794b962 commit 2c77f9c
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 45 deletions.
22 changes: 11 additions & 11 deletions .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/transcend-io/consent-manager-ui.git"
},
"homepage": "https://github.com/transcend-io/consent-manager-ui",
"version": "3.0.0",
"version": "4.0.0",
"license": "MIT",
"main": "build/ui",
"files": [
Expand Down Expand Up @@ -44,7 +44,7 @@
},
"devDependencies": {
"@monaco-editor/react": "^4.4.5",
"@transcend-io/airgap.js-types": "^9.6.0",
"@transcend-io/airgap.js-types": "^10.0.0",
"@transcend-io/type-utils": "^1.0.7",
"@types/node": "^17.0.21",
"@typescript-eslint/eslint-plugin": "^5.12.1",
Expand Down
12 changes: 10 additions & 2 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { LOG_LEVELS } from './settings';
import { HandleSetLanguage, HandleSetViewState } from './types';

interface MakeConsentManagerAPIInput {
/** The event target, where events as dispatched */
eventTarget: EventTarget;
/** Property for the current view state of the consent manager UI */
viewState: ViewState;
/** Method to change language */
Expand All @@ -29,12 +31,13 @@ let promptSuppressionNoticeShown = false;
* @returns the Consent Manager API
*/
export function makeConsentManagerAPI({
eventTarget,
viewState,
handleChangeLanguage,
handleSetViewState,
airgap,
}: MakeConsentManagerAPIInput): ConsentManagerAPI {
const api: ConsentManagerAPI = {
const consentManagerMethods: Omit<ConsentManagerAPI, keyof EventTarget> = {
setActiveLocale: (locale) => Promise.resolve(handleChangeLanguage(locale)),
getViewState: () => viewState,
viewStates: new Set(Object.values(ViewState)),
Expand Down Expand Up @@ -93,5 +96,10 @@ export function makeConsentManagerAPI({
},
};

return api;
const consentManagerAPI: ConsentManagerAPI = Object.assign(
eventTarget,
consentManagerMethods,
);

return consentManagerAPI;
}
14 changes: 11 additions & 3 deletions src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,16 @@ import { ConsentManagerLanguageKey } from '@transcend-io/internationalization';

import { CONSENT_MANAGER_SUPPORTED_LANGUAGES } from '../i18n';
import { makeConsentManagerAPI } from '../api';
import { TranscendEventTarget } from '../event-target';

// TODO: https://transcend.height.app/T-13483
// Fix IntlProvider JSX types
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const IntlProvider = _IntlProvider as any;

// Create `transcend` eventTarget on the global scope so this isn't derefenced on the next render of App
const eventTarget = new TranscendEventTarget();

/**
* Top layer concerned with data, not presentation
*/
Expand All @@ -43,16 +47,19 @@ export function App({
// Get the active privacy regime
const privacyRegime = getPrimaryRegime(airgap.getRegimes());

// View state controller. Defaults based on regime and config.
// Get default view states
const { initialViewStateByPrivacyRegime, dismissedViewState } = config;
const initialViewState =
initialViewStateByPrivacyRegime[
privacyRegime as keyof typeof initialViewStateByPrivacyRegime
] || 'Hidden';

// View state controller. Defaults based on regime and config.
const { viewState, firstSelectedViewState, handleSetViewState, auth } =
useViewState({
initialViewState,
dismissedViewState,
eventTarget,
});

// Language setup
Expand All @@ -66,15 +73,16 @@ export function App({
settings.messages || config.messages || './translations',
});

// API setup. To pass this API out of Preact, we overwrite the prop.
// Create the `transcend` API
const consentManagerAPI = makeConsentManagerAPI({
eventTarget,
viewState,
handleChangeLanguage,
handleSetViewState,
airgap,
});

// Send the API up and out of Preact via this callback
// Send this API up and out of Preact via this callback
callback(consentManagerAPI);

return (
Expand Down
29 changes: 29 additions & 0 deletions src/event-target.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Extend EventTarget to include the Transcend toStringTag
*/
export class TranscendEventTarget extends EventTarget {
#stringTag = 'Transcend';

/**
* Add Transcend to the string tag
*
* @returns string
*/
get [Symbol.toStringTag](): string {
return this.#stringTag;
}

/**
* Allow airgap.js code to overwrite [Symbol.toStringTag]
*/
set [Symbol.toStringTag](updatedStringTag: string) {
this.#stringTag = updatedStringTag;
}

/**
* @param args - EventTarget constructor parameters
*/
constructor(...args: ConstructorParameters<typeof EventTarget>) {
super(...args);
}
}
17 changes: 17 additions & 0 deletions src/hooks/useViewState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import type {
ResponseViewState,
InitialViewState,
ViewState,
ViewStateEventDetails,
TranscendEventType,
} from '@transcend-io/airgap.js-types';
import { logger } from '../logger';
import type { HandleSetViewState } from '../types';
Expand Down Expand Up @@ -44,11 +46,14 @@ export function isResponseViewState(
export function useViewState({
initialViewState,
dismissedViewState,
eventTarget,
}: {
/** Which state this consent manager should go to when opened */
initialViewState: InitialViewState;
/** Which state this consent manager should go to when closed */
dismissedViewState: DismissedViewState;
/** The event target on the `transcend` API, where we will dispatch view state change events */
eventTarget: EventTarget;
}): {
/** The current view state */
viewState: ViewState;
Expand Down Expand Up @@ -133,6 +138,18 @@ export function useViewState({
[state, setState, initialViewState, dismissedViewState],
);

// Now that the viewState has updated, dispatch an event on the `transcend` API / event target
const eventDetails: ViewStateEventDetails = {
viewState: state.current,
previousViewState: state.previous,
};
const eventType: TranscendEventType = 'view-state-change';
eventTarget.dispatchEvent(
new CustomEvent(eventType, {
detail: eventDetails,
}),
);

return {
viewState: state.current,
handleSetViewState,
Expand Down
30 changes: 13 additions & 17 deletions src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,23 +80,19 @@ export const init = async (): Promise<void> => {
injectCss(settings.css || 'cm.css');

// Create the Transcend API
const transcend: TranscendAPI = Object.create(
null,
Object.getOwnPropertyDescriptors({
readyQueue: [],
...transcendInit,
/**
* Transcend Consent Manager ready listener registrar
*
* @param callback - Callback with Transcend Consent Manager
* API passed as its first argument
*/
ready(callback: (api: TranscendAPI) => void) {
callback(transcend);
},
...consentManagerAPI,
}),
);
const transcend: TranscendAPI = Object.assign(consentManagerAPI, {
readyQueue: [],
...transcendInit,
/**
* Transcend Consent Manager ready listener registrar
*
* @param callback - Callback with Transcend Consent Manager
* API passed as its first argument
*/
ready(callback: (api: TranscendAPI) => void) {
callback(transcend);
},
});

// Export the initialized API for use by customer
view.transcend = transcend;
Expand Down
20 changes: 10 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1155,26 +1155,26 @@ __metadata:
languageName: node
linkType: hard

"@transcend-io/airgap.js-types@npm:^7.0.0":
version: 7.0.0
resolution: "@transcend-io/airgap.js-types@npm:7.0.0"
"@transcend-io/airgap.js-types@npm:^10.0.0":
version: 10.0.0
resolution: "@transcend-io/airgap.js-types@npm:10.0.0"
dependencies:
"@transcend-io/type-utils": ^1.0.5
fp-ts: ^2.11.8
io-ts: ^2.2.16
tslib: ^2.3.1
checksum: 6df9dd1dfdfbdf02f2d02d569400533b2b1cd3b75e036f20e99315ae3b526841f92b20be4341efaa93434a1e85afcdf23cced2a9ffb754ad96ef0214cede3ca2
checksum: 477c080bcce57d6db6dc3ba38adb03f60ab30bd44d62c0114f2cb8b5fcd677c63f260fdcc5117b27ceff1f226462fbd95e74d2e3a910f041d088bd7523590a66
languageName: node
linkType: hard

"@transcend-io/airgap.js-types@npm:^9.6.0":
version: 9.6.0
resolution: "@transcend-io/airgap.js-types@npm:9.6.0"
"@transcend-io/airgap.js-types@npm:^7.0.0":
version: 7.0.0
resolution: "@transcend-io/airgap.js-types@npm:7.0.0"
dependencies:
"@transcend-io/type-utils": ^1.0.5
fp-ts: ^2.11.8
io-ts: ^2.2.16
checksum: 3e337e33fa34b0f9bd1b1abdd31e1bac0042b4a3c054e2fcbd21c5f67c4df1c0f4ce27757cfcb7e10fd263aa55773279bfed064620cd8f2cebf82fca80683ab7
tslib: ^2.3.1
checksum: 6df9dd1dfdfbdf02f2d02d569400533b2b1cd3b75e036f20e99315ae3b526841f92b20be4341efaa93434a1e85afcdf23cced2a9ffb754ad96ef0214cede3ca2
languageName: node
linkType: hard

Expand All @@ -1183,7 +1183,7 @@ __metadata:
resolution: "@transcend-io/consent-manager-ui@workspace:."
dependencies:
"@monaco-editor/react": ^4.4.5
"@transcend-io/airgap.js-types": ^9.6.0
"@transcend-io/airgap.js-types": ^10.0.0
"@transcend-io/internationalization": ^1.5.1
"@transcend-io/logger": ^1.0.14
"@transcend-io/type-utils": ^1.0.7
Expand Down

1 comment on commit 2c77f9c

@vercel
Copy link

@vercel vercel bot commented on 2c77f9c Jul 11, 2023

Choose a reason for hiding this comment

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

Please sign in to comment.