@terreno/ui 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ConsentFormScreen.d.ts +1 -0
- package/dist/ConsentFormScreen.js +5 -2
- package/dist/ConsentFormScreen.js.map +1 -1
- package/dist/ConsentNavigator.d.ts +2 -0
- package/dist/ConsentNavigator.js +15 -3
- package/dist/ConsentNavigator.js.map +1 -1
- package/package.json +1 -1
- package/src/ConsentFormScreen.tsx +6 -1
- package/src/ConsentNavigator.test.tsx +56 -0
- package/src/ConsentNavigator.tsx +19 -0
|
@@ -9,7 +9,7 @@ import { Modal } from "./Modal";
|
|
|
9
9
|
import { Page } from "./Page";
|
|
10
10
|
import { SignatureField } from "./SignatureField";
|
|
11
11
|
import { Text } from "./Text";
|
|
12
|
-
export const ConsentFormScreen = ({ form, isSubmitting = false, locale, onAgree, onDecline, }) => {
|
|
12
|
+
export const ConsentFormScreen = ({ form, isSubmitting = false, locale, onAgree, onDecline, variables, }) => {
|
|
13
13
|
var _a, _b;
|
|
14
14
|
const [checkboxValues, setCheckboxValues] = useState({});
|
|
15
15
|
const [hasScrolledToBottom, setHasScrolledToBottom] = useState(!form.requireScrollToBottom);
|
|
@@ -19,7 +19,10 @@ export const ConsentFormScreen = ({ form, isSubmitting = false, locale, onAgree,
|
|
|
19
19
|
const [scrollEnabled, setScrollEnabled] = useState(true);
|
|
20
20
|
const [contentHeight, setContentHeight] = useState(0);
|
|
21
21
|
const [layoutHeight, setLayoutHeight] = useState(0);
|
|
22
|
-
const
|
|
22
|
+
const rawContent = (_b = (_a = form.content[locale]) !== null && _a !== void 0 ? _a : form.content[form.defaultLocale]) !== null && _b !== void 0 ? _b : "";
|
|
23
|
+
const content = variables
|
|
24
|
+
? rawContent.replace(/\{\{(\w+)\}\}/g, (match, key) => { var _a; return (_a = variables[key]) !== null && _a !== void 0 ? _a : match; })
|
|
25
|
+
: rawContent;
|
|
23
26
|
const allRequiredCheckboxesChecked = form.checkboxes.every((checkbox, index) => {
|
|
24
27
|
if (!checkbox.required) {
|
|
25
28
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConsentFormScreen.js","sourceRoot":"","sources":["../src/ConsentFormScreen.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAC,QAAQ,EAAC,MAAM,OAAO,CAAC;AACtC,OAAO,EAAC,SAAS,EAAE,UAAU,EAAC,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAC,GAAG,EAAC,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAC,MAAM,EAAC,MAAM,UAAU,CAAC;AAChC,OAAO,EAAC,QAAQ,EAAC,MAAM,YAAY,CAAC;AACpC,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAC,KAAK,EAAC,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAC,IAAI,EAAC,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAC,IAAI,EAAC,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"ConsentFormScreen.js","sourceRoot":"","sources":["../src/ConsentFormScreen.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAC,QAAQ,EAAC,MAAM,OAAO,CAAC;AACtC,OAAO,EAAC,SAAS,EAAE,UAAU,EAAC,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAC,GAAG,EAAC,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAC,MAAM,EAAC,MAAM,UAAU,CAAC;AAChC,OAAO,EAAC,QAAQ,EAAC,MAAM,YAAY,CAAC;AACpC,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAC,KAAK,EAAC,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAC,IAAI,EAAC,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAC,IAAI,EAAC,MAAM,QAAQ,CAAC;AAY5B,MAAM,CAAC,MAAM,iBAAiB,GAAqC,CAAC,EAClE,IAAI,EACJ,YAAY,GAAG,KAAK,EACpB,MAAM,EACN,OAAO,EACP,SAAS,EACT,SAAS,GACV,EAAE,EAAE;;IACH,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAA0B,EAAE,CAAC,CAAC;IAClF,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAC5F,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAqB,SAAS,CAAC,CAAC;IACpF,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtE,MAAM,CAAC,yBAAyB,EAAE,4BAA4B,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAChG,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IACzD,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEpD,MAAM,UAAU,GAAG,MAAA,MAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,mCAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,mCAAI,EAAE,CAAC;IAClF,MAAM,OAAO,GAAG,SAAS;QACvB,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,WAAC,OAAA,MAAA,SAAS,CAAC,GAAG,CAAC,mCAAI,KAAK,CAAA,EAAA,CAAC;QAC/E,CAAC,CAAC,UAAU,CAAC;IAEf,MAAM,4BAA4B,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE;QAC7E,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,cAAc,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,MAAM,iBAAiB,GAAG,CAAC,IAAI,CAAC,gBAAgB,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;IAE5E,MAAM,QAAQ,GAAG,mBAAmB,IAAI,4BAA4B,IAAI,iBAAiB,CAAC;IAE1F,wEAAwE;IACxE,MAAM,uBAAuB,GAAG,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE;QACxD,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,CAAC,mBAAmB,IAAI,CAAC,GAAG,CAAC,IAAI,YAAY,GAAG,CAAC,IAAI,CAAC,IAAI,YAAY,EAAE,CAAC;YAC3E,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,CAAC,KAAU,EAAE,EAAE;QAClC,MAAM,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC;QAC1C,eAAe,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,CAAC,mBAAmB,IAAI,aAAa,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,aAAa,IAAI,CAAC,EAAE,CAAC;YAC7E,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,CAAC,KAAU,EAAE,EAAE;QAClC,IAAI,mBAAmB,EAAE,CAAC;YACxB,OAAO;QACT,CAAC;QACD,MAAM,EAAC,aAAa,EAAE,WAAW,EAAE,iBAAiB,EAAC,GAAG,KAAK,CAAC,WAAW,CAAC;QAC1E,MAAM,kBAAkB,GAAG,WAAW,CAAC,MAAM,GAAG,iBAAiB,CAAC,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC;QAC3F,IAAI,kBAAkB,IAAI,EAAE,EAAE,CAAC;YAC7B,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,mBAAmB,GAAG,CAAC,KAAa,EAAE,EAAE;;QAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC7B,MAAM,YAAY,GAAG,MAAA,cAAc,CAAC,GAAG,CAAC,mCAAI,KAAK,CAAC;QAElD,IAAI,QAAQ,CAAC,kBAAkB,IAAI,CAAC,YAAY,EAAE,CAAC;YACjD,6CAA6C;YAC7C,4BAA4B,CAAC,KAAK,CAAC,CAAC;YACpC,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,iBAAiB,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,iCAAK,IAAI,KAAE,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,IAAE,CAAC,CAAC;QACjE,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,yBAAyB,GAAG,GAAG,EAAE;QACrC,IAAI,yBAAyB,KAAK,IAAI,EAAE,CAAC;YACvC,MAAM,GAAG,GAAG,yBAAyB,CAAC,QAAQ,EAAE,CAAC;YACjD,iBAAiB,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,iCAAK,IAAI,KAAE,CAAC,GAAG,CAAC,EAAE,IAAI,IAAE,CAAC,CAAC;QACxD,CAAC;QACD,sBAAsB,CAAC,KAAK,CAAC,CAAC;QAC9B,4BAA4B,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC,CAAC;IAEF,MAAM,yBAAyB,GAAG,GAAG,EAAE;QACrC,sBAAsB,CAAC,KAAK,CAAC,CAAC;QAC9B,4BAA4B,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,OAAO,CAAC,EAAC,cAAc,EAAE,SAAS,EAAE,cAAc,EAAC,CAAC,CAAC;IACvD,CAAC,CAAC;IAEF,MAAM,kBAAkB,GACtB,yBAAyB,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEzF,MAAM,MAAM,GAAG,CACb,MAAC,GAAG,IAAC,SAAS,EAAC,QAAQ,EAAC,GAAG,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAC,qBAAqB,EAAC,KAAK,EAAC,MAAM,aACnF,OAAO,CAAC,IAAI,CAAC,YAAY,IAAI,SAAS,CAAC,IAAI,CAC1C,KAAC,GAAG,IAAC,KAAK,EAAC,MAAM,YACf,KAAC,MAAM,IACL,SAAS,QACT,OAAO,EAAE,SAAU,EACnB,MAAM,EAAC,6BAA6B,EACpC,IAAI,EAAE,IAAI,CAAC,iBAAiB,EAC5B,OAAO,EAAC,OAAO,GACf,GACE,CACP,EACD,KAAC,GAAG,IAAC,KAAK,EAAC,MAAM,YACf,KAAC,MAAM,IACL,QAAQ,EAAE,CAAC,QAAQ,EACnB,SAAS,QACT,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAC,2BAA2B,EAClC,IAAI,EAAE,IAAI,CAAC,eAAe,GAC1B,GACE,IACF,CACP,CAAC;IAEF,OAAO,CACL,MAAC,IAAI,IAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,aACpD,KAAC,UAAU,IACT,mBAAmB,EAAE,uBAAuB,EAC5C,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,YAAY,EACtB,aAAa,EAAE,aAAa,EAC5B,mBAAmB,EAAE,EAAE,EACvB,KAAK,EAAE,EAAC,IAAI,EAAE,CAAC,EAAC,EAChB,MAAM,EAAC,0BAA0B,YAEjC,MAAC,GAAG,IAAC,SAAS,EAAC,QAAQ,EAAC,GAAG,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,aACzC,KAAC,YAAY,cAAE,OAAO,GAAgB,EAErC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,CAC7B,KAAC,GAAG,IAAC,SAAS,EAAC,QAAQ,EAAC,GAAG,EAAE,CAAC,EAAE,MAAM,EAAC,yBAAyB,YAC7D,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE;;gCACvC,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;gCAC7B,MAAM,SAAS,GAAG,MAAA,cAAc,CAAC,GAAG,CAAC,mCAAI,KAAK,CAAC;gCAE/C,OAAO,CACL,KAAC,SAAS,IAER,OAAO,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,KAAK,CAAC,EACzC,MAAM,EAAE,yBAAyB,KAAK,EAAE,YAExC,MAAC,GAAG,IAAC,UAAU,EAAC,QAAQ,EAAC,SAAS,EAAC,KAAK,EAAC,GAAG,EAAE,CAAC,aAC7C,KAAC,QAAQ,IAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAC,IAAI,GAAG,EAC3C,KAAC,GAAG,IAAC,IAAI,EAAC,MAAM,YACd,MAAC,IAAI,IAAC,IAAI,EAAC,IAAI,aACZ,QAAQ,CAAC,KAAK,EACd,QAAQ,CAAC,QAAQ,IAAI,IAAI,IACrB,GACH,IACF,IAZD,GAAG,CAaE,CACb,CAAC;4BACJ,CAAC,CAAC,GACE,CACP,EAEA,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CACjC,KAAC,GAAG,IAAC,SAAS,EAAC,QAAQ,EAAC,GAAG,EAAE,CAAC,EAAE,MAAM,EAAC,wBAAwB,YAC7D,KAAC,cAAc,IACb,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAC7C,KAAK,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,EACnC,OAAO,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,EACtC,KAAK,EAAC,WAAW,EACjB,KAAK,EAAE,cAAc,GACrB,GACE,CACP,EAEA,OAAO,CAAC,IAAI,CAAC,qBAAqB,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAC9D,KAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAC,0BAA0B,YACjD,KAAC,IAAI,IAAC,KAAK,EAAC,eAAe,EAAC,IAAI,EAAC,IAAI,yDAE9B,GACH,CACP,IACG,GACK,EAEZ,kBAAkB,IAAI,CACrB,KAAC,KAAK,IACJ,SAAS,EAAE,yBAAyB,EACpC,oBAAoB,EAAE,yBAAyB,EAC/C,iBAAiB,EAAC,SAAS,EAC3B,sBAAsB,EAAE,yBAAyB,EACjD,mBAAmB,EAAC,QAAQ,EAC5B,IAAI,EAAE,kBAAkB,CAAC,kBAAkB,EAC3C,KAAK,EAAC,gBAAgB,EACtB,OAAO,EAAE,mBAAmB,GAC5B,CACH,IACI,CACR,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -3,7 +3,9 @@ interface ConsentNavigatorProps {
|
|
|
3
3
|
api: any;
|
|
4
4
|
baseUrl?: string;
|
|
5
5
|
children: React.ReactNode;
|
|
6
|
+
extraScreens?: React.ReactNode[];
|
|
6
7
|
onError?: (error: any) => void;
|
|
8
|
+
variables?: Record<string, string>;
|
|
7
9
|
}
|
|
8
10
|
export declare const ConsentNavigator: React.FC<ConsentNavigatorProps>;
|
|
9
11
|
export {};
|
package/dist/ConsentNavigator.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from "react";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
3
|
import { Box } from "./Box";
|
|
4
4
|
import { Button } from "./Button";
|
|
5
5
|
import { ConsentFormScreen } from "./ConsentFormScreen";
|
|
@@ -7,12 +7,14 @@ import { Spinner } from "./Spinner";
|
|
|
7
7
|
import { Text } from "./Text";
|
|
8
8
|
import { detectLocale, useConsentForms } from "./useConsentForms";
|
|
9
9
|
import { useSubmitConsent } from "./useSubmitConsent";
|
|
10
|
-
export const ConsentNavigator = ({ api, baseUrl, children, onError, }) => {
|
|
10
|
+
export const ConsentNavigator = ({ api, baseUrl, children, extraScreens, onError, variables, }) => {
|
|
11
11
|
var _a, _b;
|
|
12
12
|
const [currentIndex, setCurrentIndex] = useState(0);
|
|
13
|
+
const [extraScreenIndex, setExtraScreenIndex] = useState(0);
|
|
13
14
|
const { forms, isLoading, error, refetch } = useConsentForms(api, baseUrl);
|
|
14
15
|
const { submit, isSubmitting } = useSubmitConsent(api, baseUrl);
|
|
15
16
|
const locale = detectLocale();
|
|
17
|
+
const validExtraScreens = extraScreens !== null && extraScreens !== void 0 ? extraScreens : [];
|
|
16
18
|
if (isLoading) {
|
|
17
19
|
console.debug("[ConsentNavigator] Loading pending consents...");
|
|
18
20
|
return (_jsx(Box, { alignItems: "center", flex: "grow", justifyContent: "center", testID: "consent-navigator-loading", children: _jsx(Spinner, {}) }));
|
|
@@ -28,6 +30,16 @@ export const ConsentNavigator = ({ api, baseUrl, children, onError, }) => {
|
|
|
28
30
|
return (_jsxs(Box, { alignItems: "center", direction: "column", flex: "grow", gap: 3, justifyContent: "center", padding: 6, testID: "consent-navigator-error", children: [_jsx(Text, { align: "center", color: "error", size: "lg", children: "Failed to load consent forms" }), _jsx(Button, { onClick: refetch, text: "Retry" })] }));
|
|
29
31
|
}
|
|
30
32
|
if (forms.length === 0 || currentIndex >= forms.length) {
|
|
33
|
+
if (extraScreenIndex < validExtraScreens.length) {
|
|
34
|
+
const currentScreen = validExtraScreens[extraScreenIndex];
|
|
35
|
+
console.debug(`[ConsentNavigator] Showing extra screen ${extraScreenIndex + 1}/${validExtraScreens.length}`);
|
|
36
|
+
if (React.isValidElement(currentScreen)) {
|
|
37
|
+
return React.cloneElement(currentScreen, {
|
|
38
|
+
onNext: () => setExtraScreenIndex((i) => i + 1),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return _jsx(_Fragment, { children: currentScreen });
|
|
42
|
+
}
|
|
31
43
|
console.debug("[ConsentNavigator] No pending consents, showing app");
|
|
32
44
|
return _jsx(_Fragment, { children: children });
|
|
33
45
|
}
|
|
@@ -67,6 +79,6 @@ export const ConsentNavigator = ({ api, baseUrl, children, onError, }) => {
|
|
|
67
79
|
onError === null || onError === void 0 ? void 0 : onError(err);
|
|
68
80
|
}
|
|
69
81
|
};
|
|
70
|
-
return (_jsx(ConsentFormScreen, { form: currentForm, isSubmitting: isSubmitting, locale: locale, onAgree: handleAgree, onDecline: currentForm.required ? undefined : handleDecline }));
|
|
82
|
+
return (_jsx(ConsentFormScreen, { form: currentForm, isSubmitting: isSubmitting, locale: locale, onAgree: handleAgree, onDecline: currentForm.required ? undefined : handleDecline, variables: variables }));
|
|
71
83
|
};
|
|
72
84
|
//# sourceMappingURL=ConsentNavigator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConsentNavigator.js","sourceRoot":"","sources":["../src/ConsentNavigator.tsx"],"names":[],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"ConsentNavigator.js","sourceRoot":"","sources":["../src/ConsentNavigator.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -17,6 +17,7 @@ interface ConsentFormScreenProps {
|
|
|
17
17
|
locale: string;
|
|
18
18
|
onAgree: (data: {checkboxValues: Record<string, boolean>; signature?: string}) => void;
|
|
19
19
|
onDecline?: () => void;
|
|
20
|
+
variables?: Record<string, string>;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
export const ConsentFormScreen: React.FC<ConsentFormScreenProps> = ({
|
|
@@ -25,6 +26,7 @@ export const ConsentFormScreen: React.FC<ConsentFormScreenProps> = ({
|
|
|
25
26
|
locale,
|
|
26
27
|
onAgree,
|
|
27
28
|
onDecline,
|
|
29
|
+
variables,
|
|
28
30
|
}) => {
|
|
29
31
|
const [checkboxValues, setCheckboxValues] = useState<Record<string, boolean>>({});
|
|
30
32
|
const [hasScrolledToBottom, setHasScrolledToBottom] = useState(!form.requireScrollToBottom);
|
|
@@ -35,7 +37,10 @@ export const ConsentFormScreen: React.FC<ConsentFormScreenProps> = ({
|
|
|
35
37
|
const [contentHeight, setContentHeight] = useState(0);
|
|
36
38
|
const [layoutHeight, setLayoutHeight] = useState(0);
|
|
37
39
|
|
|
38
|
-
const
|
|
40
|
+
const rawContent = form.content[locale] ?? form.content[form.defaultLocale] ?? "";
|
|
41
|
+
const content = variables
|
|
42
|
+
? rawContent.replace(/\{\{(\w+)\}\}/g, (match, key) => variables[key] ?? match)
|
|
43
|
+
: rawContent;
|
|
39
44
|
|
|
40
45
|
const allRequiredCheckboxesChecked = form.checkboxes.every((checkbox, index) => {
|
|
41
46
|
if (!checkbox.required) {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {describe, expect, it, mock} from "bun:test";
|
|
2
2
|
import React from "react";
|
|
3
|
+
import {Pressable} from "react-native";
|
|
4
|
+
import {Box} from "./Box";
|
|
3
5
|
import {ConsentNavigator} from "./ConsentNavigator";
|
|
4
6
|
import {Text} from "./Text";
|
|
5
7
|
import {renderWithTheme} from "./test-utils";
|
|
@@ -71,6 +73,15 @@ const createLoadingMockApi = () => {
|
|
|
71
73
|
};
|
|
72
74
|
};
|
|
73
75
|
|
|
76
|
+
const ExtraScreen: React.FC<{onNext?: () => void}> = ({onNext}) => (
|
|
77
|
+
<Box testID="extra-screen">
|
|
78
|
+
<Text>Extra Screen Content</Text>
|
|
79
|
+
<Pressable onPress={onNext} testID="extra-screen-next">
|
|
80
|
+
<Text>Next</Text>
|
|
81
|
+
</Pressable>
|
|
82
|
+
</Box>
|
|
83
|
+
);
|
|
84
|
+
|
|
74
85
|
describe("ConsentNavigator", () => {
|
|
75
86
|
it("renders children when there are no pending consent forms", async () => {
|
|
76
87
|
const api = createMockApi([]);
|
|
@@ -108,4 +119,49 @@ describe("ConsentNavigator", () => {
|
|
|
108
119
|
|
|
109
120
|
expect(getByTestId("consent-navigator-loading")).toBeTruthy();
|
|
110
121
|
});
|
|
122
|
+
|
|
123
|
+
it("shows extra screens after consent forms are completed", async () => {
|
|
124
|
+
const api = createMockApi([]);
|
|
125
|
+
|
|
126
|
+
const {getByTestId, queryByText} = renderWithTheme(
|
|
127
|
+
<ConsentNavigator api={api} extraScreens={[<ExtraScreen key="extra" />]}>
|
|
128
|
+
<Text>App Content</Text>
|
|
129
|
+
</ConsentNavigator>
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
expect(getByTestId("extra-screen")).toBeTruthy();
|
|
133
|
+
expect(queryByText("App Content")).toBeNull();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("shows children after all extra screens are dismissed", async () => {
|
|
137
|
+
const api = createMockApi([]);
|
|
138
|
+
const {act, fireEvent, waitFor} = await import("@testing-library/react-native");
|
|
139
|
+
|
|
140
|
+
const {getByTestId, getByText} = renderWithTheme(
|
|
141
|
+
<ConsentNavigator api={api} extraScreens={[<ExtraScreen key="extra" />]}>
|
|
142
|
+
<Text>App Content</Text>
|
|
143
|
+
</ConsentNavigator>
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
expect(getByTestId("extra-screen")).toBeTruthy();
|
|
147
|
+
await act(async () => {
|
|
148
|
+
fireEvent.press(getByTestId("extra-screen-next"));
|
|
149
|
+
});
|
|
150
|
+
await waitFor(() => {
|
|
151
|
+
expect(getByText("App Content")).toBeTruthy();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("injects onNext prop into extra screen elements", async () => {
|
|
156
|
+
const api = createMockApi([]);
|
|
157
|
+
|
|
158
|
+
const {getByTestId} = renderWithTheme(
|
|
159
|
+
<ConsentNavigator api={api} extraScreens={[<ExtraScreen key="extra" />]}>
|
|
160
|
+
<Text>App Content</Text>
|
|
161
|
+
</ConsentNavigator>
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// The extra screen should have a working next button (onNext was injected)
|
|
165
|
+
expect(getByTestId("extra-screen-next")).toBeTruthy();
|
|
166
|
+
});
|
|
111
167
|
});
|
package/src/ConsentNavigator.tsx
CHANGED
|
@@ -13,19 +13,25 @@ interface ConsentNavigatorProps {
|
|
|
13
13
|
api: any;
|
|
14
14
|
baseUrl?: string;
|
|
15
15
|
children: React.ReactNode;
|
|
16
|
+
extraScreens?: React.ReactNode[];
|
|
16
17
|
onError?: (error: any) => void;
|
|
18
|
+
variables?: Record<string, string>;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export const ConsentNavigator: React.FC<ConsentNavigatorProps> = ({
|
|
20
22
|
api,
|
|
21
23
|
baseUrl,
|
|
22
24
|
children,
|
|
25
|
+
extraScreens,
|
|
23
26
|
onError,
|
|
27
|
+
variables,
|
|
24
28
|
}) => {
|
|
25
29
|
const [currentIndex, setCurrentIndex] = useState(0);
|
|
30
|
+
const [extraScreenIndex, setExtraScreenIndex] = useState(0);
|
|
26
31
|
const {forms, isLoading, error, refetch} = useConsentForms(api, baseUrl);
|
|
27
32
|
const {submit, isSubmitting} = useSubmitConsent(api, baseUrl);
|
|
28
33
|
const locale = detectLocale();
|
|
34
|
+
const validExtraScreens = extraScreens ?? [];
|
|
29
35
|
|
|
30
36
|
if (isLoading) {
|
|
31
37
|
console.debug("[ConsentNavigator] Loading pending consents...");
|
|
@@ -68,6 +74,18 @@ export const ConsentNavigator: React.FC<ConsentNavigatorProps> = ({
|
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
if (forms.length === 0 || currentIndex >= forms.length) {
|
|
77
|
+
if (extraScreenIndex < validExtraScreens.length) {
|
|
78
|
+
const currentScreen = validExtraScreens[extraScreenIndex];
|
|
79
|
+
console.debug(
|
|
80
|
+
`[ConsentNavigator] Showing extra screen ${extraScreenIndex + 1}/${validExtraScreens.length}`
|
|
81
|
+
);
|
|
82
|
+
if (React.isValidElement(currentScreen)) {
|
|
83
|
+
return React.cloneElement(currentScreen as React.ReactElement<any>, {
|
|
84
|
+
onNext: () => setExtraScreenIndex((i) => i + 1),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return <>{currentScreen}</>;
|
|
88
|
+
}
|
|
71
89
|
console.debug("[ConsentNavigator] No pending consents, showing app");
|
|
72
90
|
return <>{children}</>;
|
|
73
91
|
}
|
|
@@ -123,6 +141,7 @@ export const ConsentNavigator: React.FC<ConsentNavigatorProps> = ({
|
|
|
123
141
|
locale={locale}
|
|
124
142
|
onAgree={handleAgree}
|
|
125
143
|
onDecline={currentForm.required ? undefined : handleDecline}
|
|
144
|
+
variables={variables}
|
|
126
145
|
/>
|
|
127
146
|
);
|
|
128
147
|
};
|