@dloizides/legal-ui 1.0.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/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/README.md +43 -0
- package/dist/index.d.mts +124 -0
- package/dist/index.d.ts +124 -0
- package/dist/index.js +550 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +540 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +113 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
import { useMemo, useState, useEffect, useCallback } from 'react';
|
|
2
|
+
import { StyleSheet, Platform, TouchableOpacity, Text, View, Modal, ScrollView, Switch } from 'react-native';
|
|
3
|
+
import { useUi } from '@dloizides/ui-feedback';
|
|
4
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
+
import { SvgIcon } from '@dloizides/ui-icons';
|
|
6
|
+
|
|
7
|
+
// src/CookieConsentBanner/CookieConsentBanner.tsx
|
|
8
|
+
var BORDER_RADIUS = 8;
|
|
9
|
+
var PADDING_VERTICAL = 10;
|
|
10
|
+
var PADDING_HORIZONTAL = 16;
|
|
11
|
+
var BORDER_WIDTH = 1;
|
|
12
|
+
var FONT_SIZE = 14;
|
|
13
|
+
var MIN_MARGIN_TOP = 8;
|
|
14
|
+
var styles = StyleSheet.create({
|
|
15
|
+
base: {
|
|
16
|
+
borderRadius: BORDER_RADIUS,
|
|
17
|
+
paddingVertical: PADDING_VERTICAL,
|
|
18
|
+
paddingHorizontal: PADDING_HORIZONTAL,
|
|
19
|
+
alignItems: "center",
|
|
20
|
+
justifyContent: "center",
|
|
21
|
+
borderWidth: BORDER_WIDTH,
|
|
22
|
+
minWidth: PADDING_HORIZONTAL * 2,
|
|
23
|
+
marginTop: MIN_MARGIN_TOP
|
|
24
|
+
},
|
|
25
|
+
label: {
|
|
26
|
+
fontSize: FONT_SIZE,
|
|
27
|
+
fontWeight: "600"
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
var ConsentButton = ({
|
|
31
|
+
label,
|
|
32
|
+
testID,
|
|
33
|
+
textColor,
|
|
34
|
+
onPress,
|
|
35
|
+
a11yHint,
|
|
36
|
+
primary = false,
|
|
37
|
+
primaryColor,
|
|
38
|
+
borderColor
|
|
39
|
+
}) => {
|
|
40
|
+
const buttonStyle = useMemo(
|
|
41
|
+
() => [
|
|
42
|
+
styles.base,
|
|
43
|
+
{
|
|
44
|
+
backgroundColor: primary ? primaryColor ?? "transparent" : "transparent",
|
|
45
|
+
borderColor: primary ? primaryColor ?? "transparent" : borderColor ?? "transparent"
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
[primary, primaryColor, borderColor]
|
|
49
|
+
);
|
|
50
|
+
return /* @__PURE__ */ jsx(
|
|
51
|
+
TouchableOpacity,
|
|
52
|
+
{
|
|
53
|
+
accessibilityHint: a11yHint,
|
|
54
|
+
accessibilityLabel: label,
|
|
55
|
+
accessibilityRole: "button",
|
|
56
|
+
style: buttonStyle,
|
|
57
|
+
testID,
|
|
58
|
+
onPress,
|
|
59
|
+
children: /* @__PURE__ */ jsx(Text, { style: [styles.label, { color: textColor }], children: label })
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
var SECTION_MARGIN_BOTTOM = 20;
|
|
64
|
+
var SECTION_TITLE_SIZE = 18;
|
|
65
|
+
var SECTION_TITLE_MARGIN_BOTTOM = 8;
|
|
66
|
+
var SECTION_BODY_SIZE = 14;
|
|
67
|
+
var SECTION_BODY_LINE_HEIGHT = 22;
|
|
68
|
+
var styles2 = StyleSheet.create({
|
|
69
|
+
section: { marginBottom: SECTION_MARGIN_BOTTOM },
|
|
70
|
+
sectionTitle: { fontSize: SECTION_TITLE_SIZE, fontWeight: "600", marginBottom: SECTION_TITLE_MARGIN_BOTTOM },
|
|
71
|
+
sectionBody: { fontSize: SECTION_BODY_SIZE, lineHeight: SECTION_BODY_LINE_HEIGHT }
|
|
72
|
+
});
|
|
73
|
+
var LegalSection = ({ title, body }) => {
|
|
74
|
+
const { theme } = useUi();
|
|
75
|
+
const colors = theme.colors;
|
|
76
|
+
return /* @__PURE__ */ jsxs(View, { style: styles2.section, children: [
|
|
77
|
+
/* @__PURE__ */ jsx(Text, { style: [styles2.sectionTitle, { color: colors.text }], children: title }),
|
|
78
|
+
/* @__PURE__ */ jsx(Text, { style: [styles2.sectionBody, { color: colors.textSecondary }], children: body })
|
|
79
|
+
] });
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// src/constants.ts
|
|
83
|
+
var COOKIE_CONSENT_STORAGE_KEY = "COOKIE_CONSENT";
|
|
84
|
+
var LEGAL_TEST_IDS = {
|
|
85
|
+
cookieBanner: "cookie-consent-banner",
|
|
86
|
+
cookieAcceptAll: "cookie-consent-accept-all",
|
|
87
|
+
cookieRejectAll: "cookie-consent-reject-all",
|
|
88
|
+
cookieCustomize: "cookie-consent-customize",
|
|
89
|
+
cookieSavePreferences: "cookie-consent-save-preferences",
|
|
90
|
+
cookieEssentialToggle: "cookie-consent-essential-toggle",
|
|
91
|
+
cookieAnalyticsToggle: "cookie-consent-analytics-toggle",
|
|
92
|
+
cookieMarketingToggle: "cookie-consent-marketing-toggle",
|
|
93
|
+
cookiePrivacyLink: "cookie-consent-privacy-link",
|
|
94
|
+
privacyPolicyScreen: "privacy-policy-screen",
|
|
95
|
+
privacyPolicyClose: "privacy-policy-close",
|
|
96
|
+
termsOfServiceScreen: "terms-of-service-screen",
|
|
97
|
+
termsOfServiceClose: "terms-of-service-close"
|
|
98
|
+
};
|
|
99
|
+
var CONTENT_PADDING = 16;
|
|
100
|
+
var BOTTOM_PADDING = 48;
|
|
101
|
+
var TITLE_FONT_SIZE = 24;
|
|
102
|
+
var TITLE_MARGIN_BOTTOM = 4;
|
|
103
|
+
var UPDATED_FONT_SIZE = 12;
|
|
104
|
+
var UPDATED_MARGIN_BOTTOM = 16;
|
|
105
|
+
var CLOSE_BUTTON_PADDING = 6;
|
|
106
|
+
var CLOSE_BUTTON_BORDER_RADIUS = 6;
|
|
107
|
+
var CLOSE_ICON_SIZE = 18;
|
|
108
|
+
var DEFAULT_LAST_UPDATED = "2026-03-12";
|
|
109
|
+
var styles3 = StyleSheet.create({
|
|
110
|
+
container: { flex: 1 },
|
|
111
|
+
scrollContent: { padding: CONTENT_PADDING, paddingBottom: BOTTOM_PADDING },
|
|
112
|
+
headerRow: {
|
|
113
|
+
flexDirection: "row",
|
|
114
|
+
alignItems: "center",
|
|
115
|
+
justifyContent: "space-between"
|
|
116
|
+
},
|
|
117
|
+
title: { fontSize: TITLE_FONT_SIZE, fontWeight: "700", marginBottom: TITLE_MARGIN_BOTTOM },
|
|
118
|
+
lastUpdated: { fontSize: UPDATED_FONT_SIZE, marginBottom: UPDATED_MARGIN_BOTTOM },
|
|
119
|
+
closeButton: {
|
|
120
|
+
padding: CLOSE_BUTTON_PADDING,
|
|
121
|
+
borderRadius: CLOSE_BUTTON_BORDER_RADIUS
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
var SECTIONS = [
|
|
125
|
+
"introduction",
|
|
126
|
+
"dataWeCollect",
|
|
127
|
+
"howWeUse",
|
|
128
|
+
"legalBasis",
|
|
129
|
+
"dataSharing",
|
|
130
|
+
"internationalTransfers",
|
|
131
|
+
"dataRetention",
|
|
132
|
+
"yourRights",
|
|
133
|
+
"cookies",
|
|
134
|
+
"childrenPrivacy",
|
|
135
|
+
"dataSecurity",
|
|
136
|
+
"policyChanges",
|
|
137
|
+
"contact"
|
|
138
|
+
];
|
|
139
|
+
var PrivacyPolicyModal = ({
|
|
140
|
+
visible,
|
|
141
|
+
onClose,
|
|
142
|
+
lastUpdated = DEFAULT_LAST_UPDATED
|
|
143
|
+
}) => {
|
|
144
|
+
const { theme, t } = useUi();
|
|
145
|
+
const colors = theme.colors;
|
|
146
|
+
return /* @__PURE__ */ jsx(
|
|
147
|
+
Modal,
|
|
148
|
+
{
|
|
149
|
+
animationType: "slide",
|
|
150
|
+
visible,
|
|
151
|
+
onRequestClose: onClose,
|
|
152
|
+
children: /* @__PURE__ */ jsx(View, { style: [styles3.container, { backgroundColor: colors.background }], testID: LEGAL_TEST_IDS.privacyPolicyScreen, children: /* @__PURE__ */ jsxs(
|
|
153
|
+
ScrollView,
|
|
154
|
+
{
|
|
155
|
+
accessibilityViewIsModal: true,
|
|
156
|
+
"aria-label": t("legal.privacyPolicy.title"),
|
|
157
|
+
contentContainerStyle: styles3.scrollContent,
|
|
158
|
+
role: "dialog",
|
|
159
|
+
children: [
|
|
160
|
+
/* @__PURE__ */ jsxs(View, { style: styles3.headerRow, children: [
|
|
161
|
+
/* @__PURE__ */ jsx(Text, { style: [styles3.title, { color: colors.text }], children: t("legal.privacyPolicy.title") }),
|
|
162
|
+
/* @__PURE__ */ jsx(
|
|
163
|
+
TouchableOpacity,
|
|
164
|
+
{
|
|
165
|
+
accessibilityHint: t("common.closeDialogHint"),
|
|
166
|
+
accessibilityLabel: t("common.close"),
|
|
167
|
+
accessibilityRole: "button",
|
|
168
|
+
style: styles3.closeButton,
|
|
169
|
+
testID: LEGAL_TEST_IDS.privacyPolicyClose,
|
|
170
|
+
onPress: onClose,
|
|
171
|
+
children: /* @__PURE__ */ jsx(SvgIcon, { color: colors.textSecondary, name: "close", size: CLOSE_ICON_SIZE })
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
] }),
|
|
175
|
+
/* @__PURE__ */ jsx(Text, { style: [styles3.lastUpdated, { color: colors.textSecondary }], children: t("legal.privacyPolicy.lastUpdated", lastUpdated) }),
|
|
176
|
+
SECTIONS.map((key) => /* @__PURE__ */ jsx(
|
|
177
|
+
LegalSection,
|
|
178
|
+
{
|
|
179
|
+
body: t(`legal.privacyPolicy.${key}.body`),
|
|
180
|
+
title: t(`legal.privacyPolicy.${key}.title`)
|
|
181
|
+
},
|
|
182
|
+
key
|
|
183
|
+
))
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
) })
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// src/types.ts
|
|
192
|
+
var CONSENT_VERSION = "1.0";
|
|
193
|
+
|
|
194
|
+
// src/hooks/useCookieConsent.ts
|
|
195
|
+
function isRecord(value) {
|
|
196
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
197
|
+
}
|
|
198
|
+
function isCookieConsent(value) {
|
|
199
|
+
if (!isRecord(value)) return false;
|
|
200
|
+
return value["necessary"] === true && typeof value["analytics"] === "boolean" && typeof value["marketing"] === "boolean" && typeof value["consentedAt"] === "string" && typeof value["version"] === "string";
|
|
201
|
+
}
|
|
202
|
+
function readConsent() {
|
|
203
|
+
if (typeof window === "undefined") return null;
|
|
204
|
+
try {
|
|
205
|
+
const raw = window.localStorage.getItem(COOKIE_CONSENT_STORAGE_KEY);
|
|
206
|
+
if (raw === null) return null;
|
|
207
|
+
const parsed = JSON.parse(raw);
|
|
208
|
+
if (!isCookieConsent(parsed)) return null;
|
|
209
|
+
return parsed;
|
|
210
|
+
} catch {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function writeConsent(consent) {
|
|
215
|
+
if (typeof window === "undefined") return;
|
|
216
|
+
try {
|
|
217
|
+
window.localStorage.setItem(COOKIE_CONSENT_STORAGE_KEY, JSON.stringify(consent));
|
|
218
|
+
} catch {
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function buildConsent(analytics, marketing) {
|
|
222
|
+
return {
|
|
223
|
+
necessary: true,
|
|
224
|
+
analytics,
|
|
225
|
+
marketing,
|
|
226
|
+
consentedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
227
|
+
version: CONSENT_VERSION
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function useCookieConsent() {
|
|
231
|
+
const [consent, setConsent] = useState(() => readConsent());
|
|
232
|
+
useEffect(() => {
|
|
233
|
+
setConsent(readConsent());
|
|
234
|
+
}, []);
|
|
235
|
+
const acceptAll = useCallback(() => {
|
|
236
|
+
const record = buildConsent(true, true);
|
|
237
|
+
writeConsent(record);
|
|
238
|
+
setConsent(record);
|
|
239
|
+
}, []);
|
|
240
|
+
const rejectAll = useCallback(() => {
|
|
241
|
+
const record = buildConsent(false, false);
|
|
242
|
+
writeConsent(record);
|
|
243
|
+
setConsent(record);
|
|
244
|
+
}, []);
|
|
245
|
+
const savePreferences = useCallback((analytics, marketing) => {
|
|
246
|
+
const record = buildConsent(analytics, marketing);
|
|
247
|
+
writeConsent(record);
|
|
248
|
+
setConsent(record);
|
|
249
|
+
}, []);
|
|
250
|
+
const showBanner = consent === null;
|
|
251
|
+
return { consent, showBanner, acceptAll, rejectAll, savePreferences };
|
|
252
|
+
}
|
|
253
|
+
var BANNER_PADDING = 16;
|
|
254
|
+
var BANNER_MAX_WIDTH = 640;
|
|
255
|
+
var BORDER_RADIUS2 = 12;
|
|
256
|
+
var SECTION_GAP = 12;
|
|
257
|
+
var TOGGLE_MARGIN_TOP = 8;
|
|
258
|
+
var SHADOW_OFFSET_Y = -2;
|
|
259
|
+
var SHADOW_RADIUS = 8;
|
|
260
|
+
var SHADOW_OPACITY = 0.15;
|
|
261
|
+
var OVERLAY_ELEVATION = 20;
|
|
262
|
+
var BORDER_WIDTH2 = 1;
|
|
263
|
+
var MESSAGE_FONT_SIZE = 14;
|
|
264
|
+
var MESSAGE_LINE_HEIGHT = 20;
|
|
265
|
+
var SMALL_FONT_SIZE = 12;
|
|
266
|
+
var TOGGLE_DESC_MARGIN_TOP = 2;
|
|
267
|
+
var styles4 = StyleSheet.create({
|
|
268
|
+
overlay: {
|
|
269
|
+
position: "absolute",
|
|
270
|
+
bottom: 0,
|
|
271
|
+
left: 0,
|
|
272
|
+
right: 0,
|
|
273
|
+
alignItems: "center",
|
|
274
|
+
padding: BANNER_PADDING,
|
|
275
|
+
elevation: OVERLAY_ELEVATION,
|
|
276
|
+
zIndex: OVERLAY_ELEVATION
|
|
277
|
+
},
|
|
278
|
+
banner: {
|
|
279
|
+
width: "100%",
|
|
280
|
+
maxWidth: BANNER_MAX_WIDTH,
|
|
281
|
+
borderRadius: BORDER_RADIUS2,
|
|
282
|
+
padding: BANNER_PADDING,
|
|
283
|
+
borderWidth: BORDER_WIDTH2,
|
|
284
|
+
...Platform.select({
|
|
285
|
+
web: {
|
|
286
|
+
boxShadow: `0px ${SHADOW_OFFSET_Y}px ${SHADOW_RADIUS}px rgba(0,0,0,${SHADOW_OPACITY})`
|
|
287
|
+
},
|
|
288
|
+
default: {
|
|
289
|
+
shadowOffset: { width: 0, height: SHADOW_OFFSET_Y },
|
|
290
|
+
shadowRadius: SHADOW_RADIUS,
|
|
291
|
+
shadowOpacity: SHADOW_OPACITY
|
|
292
|
+
}
|
|
293
|
+
})
|
|
294
|
+
},
|
|
295
|
+
message: { fontSize: MESSAGE_FONT_SIZE, lineHeight: MESSAGE_LINE_HEIGHT, marginBottom: SECTION_GAP },
|
|
296
|
+
buttonRow: { flexDirection: "row", gap: SECTION_GAP, flexWrap: "wrap" },
|
|
297
|
+
customiseSection: { marginTop: SECTION_GAP },
|
|
298
|
+
toggleRow: {
|
|
299
|
+
flexDirection: "row",
|
|
300
|
+
justifyContent: "space-between",
|
|
301
|
+
alignItems: "center",
|
|
302
|
+
marginTop: TOGGLE_MARGIN_TOP
|
|
303
|
+
},
|
|
304
|
+
toggleLabel: { fontSize: MESSAGE_FONT_SIZE, fontWeight: "600" },
|
|
305
|
+
toggleDescription: { fontSize: SMALL_FONT_SIZE, marginTop: TOGGLE_DESC_MARGIN_TOP },
|
|
306
|
+
privacyLink: { fontSize: SMALL_FONT_SIZE, marginTop: SECTION_GAP, textDecorationLine: "underline" }
|
|
307
|
+
});
|
|
308
|
+
var CookieConsentBanner = () => {
|
|
309
|
+
const { theme, t } = useUi();
|
|
310
|
+
const { showBanner, acceptAll, rejectAll, savePreferences } = useCookieConsent();
|
|
311
|
+
const [showCustomise, setShowCustomise] = useState(false);
|
|
312
|
+
const [analytics, setAnalytics] = useState(false);
|
|
313
|
+
const [marketing, setMarketing] = useState(false);
|
|
314
|
+
const [showPrivacy, setShowPrivacy] = useState(false);
|
|
315
|
+
const handleCustomise = useCallback(() => {
|
|
316
|
+
setShowCustomise((prev) => !prev);
|
|
317
|
+
}, []);
|
|
318
|
+
const handleSavePreferences = useCallback(() => {
|
|
319
|
+
savePreferences(analytics, marketing);
|
|
320
|
+
}, [analytics, marketing, savePreferences]);
|
|
321
|
+
const handlePrivacyLink = useCallback(() => setShowPrivacy(true), []);
|
|
322
|
+
const handleClosePrivacy = useCallback(() => setShowPrivacy(false), []);
|
|
323
|
+
if (!showBanner) return null;
|
|
324
|
+
const colors = theme.colors;
|
|
325
|
+
const primary = theme.palette.primary["500"];
|
|
326
|
+
return /* @__PURE__ */ jsxs(View, { style: styles4.overlay, testID: LEGAL_TEST_IDS.cookieBanner, children: [
|
|
327
|
+
/* @__PURE__ */ jsxs(View, { style: [styles4.banner, { backgroundColor: colors.surface, borderColor: colors.border }], children: [
|
|
328
|
+
/* @__PURE__ */ jsx(Text, { style: [styles4.message, { color: colors.text }], children: t("cookieConsent.message") }),
|
|
329
|
+
/* @__PURE__ */ jsxs(View, { style: styles4.buttonRow, children: [
|
|
330
|
+
/* @__PURE__ */ jsx(
|
|
331
|
+
ConsentButton,
|
|
332
|
+
{
|
|
333
|
+
primary: true,
|
|
334
|
+
a11yHint: t("cookieConsent.acceptAllHint"),
|
|
335
|
+
label: t("cookieConsent.acceptAll"),
|
|
336
|
+
primaryColor: primary,
|
|
337
|
+
testID: LEGAL_TEST_IDS.cookieAcceptAll,
|
|
338
|
+
textColor: colors.surface,
|
|
339
|
+
onPress: acceptAll
|
|
340
|
+
}
|
|
341
|
+
),
|
|
342
|
+
/* @__PURE__ */ jsx(
|
|
343
|
+
ConsentButton,
|
|
344
|
+
{
|
|
345
|
+
a11yHint: t("cookieConsent.rejectAllHint"),
|
|
346
|
+
borderColor: colors.border,
|
|
347
|
+
label: t("cookieConsent.rejectAll"),
|
|
348
|
+
testID: LEGAL_TEST_IDS.cookieRejectAll,
|
|
349
|
+
textColor: colors.text,
|
|
350
|
+
onPress: rejectAll
|
|
351
|
+
}
|
|
352
|
+
),
|
|
353
|
+
/* @__PURE__ */ jsx(
|
|
354
|
+
ConsentButton,
|
|
355
|
+
{
|
|
356
|
+
a11yHint: t("cookieConsent.customizeHint"),
|
|
357
|
+
borderColor: colors.border,
|
|
358
|
+
label: t("cookieConsent.customize"),
|
|
359
|
+
testID: LEGAL_TEST_IDS.cookieCustomize,
|
|
360
|
+
textColor: colors.text,
|
|
361
|
+
onPress: handleCustomise
|
|
362
|
+
}
|
|
363
|
+
)
|
|
364
|
+
] }),
|
|
365
|
+
showCustomise ? /* @__PURE__ */ jsxs(View, { style: styles4.customiseSection, children: [
|
|
366
|
+
/* @__PURE__ */ jsxs(View, { style: styles4.toggleRow, children: [
|
|
367
|
+
/* @__PURE__ */ jsxs(View, { children: [
|
|
368
|
+
/* @__PURE__ */ jsx(Text, { style: [styles4.toggleLabel, { color: colors.text }], children: t("cookieConsent.necessaryLabel") }),
|
|
369
|
+
/* @__PURE__ */ jsx(Text, { style: [styles4.toggleDescription, { color: colors.textSecondary }], children: t("cookieConsent.necessaryDescription") })
|
|
370
|
+
] }),
|
|
371
|
+
/* @__PURE__ */ jsx(
|
|
372
|
+
Switch,
|
|
373
|
+
{
|
|
374
|
+
disabled: true,
|
|
375
|
+
value: true,
|
|
376
|
+
accessibilityHint: t("cookieConsent.essentialToggleHint"),
|
|
377
|
+
accessibilityLabel: t("cookieConsent.necessaryLabel"),
|
|
378
|
+
testID: LEGAL_TEST_IDS.cookieEssentialToggle,
|
|
379
|
+
trackColor: { true: primary, false: colors.border }
|
|
380
|
+
}
|
|
381
|
+
)
|
|
382
|
+
] }),
|
|
383
|
+
/* @__PURE__ */ jsxs(View, { style: styles4.toggleRow, children: [
|
|
384
|
+
/* @__PURE__ */ jsxs(View, { children: [
|
|
385
|
+
/* @__PURE__ */ jsx(Text, { style: [styles4.toggleLabel, { color: colors.text }], children: t("cookieConsent.analyticsLabel") }),
|
|
386
|
+
/* @__PURE__ */ jsx(Text, { style: [styles4.toggleDescription, { color: colors.textSecondary }], children: t("cookieConsent.analyticsDescription") })
|
|
387
|
+
] }),
|
|
388
|
+
/* @__PURE__ */ jsx(
|
|
389
|
+
Switch,
|
|
390
|
+
{
|
|
391
|
+
accessibilityHint: t("cookieConsent.analyticsToggleHint"),
|
|
392
|
+
accessibilityLabel: t("cookieConsent.analyticsLabel"),
|
|
393
|
+
testID: LEGAL_TEST_IDS.cookieAnalyticsToggle,
|
|
394
|
+
trackColor: { true: primary, false: colors.border },
|
|
395
|
+
value: analytics,
|
|
396
|
+
onValueChange: setAnalytics
|
|
397
|
+
}
|
|
398
|
+
)
|
|
399
|
+
] }),
|
|
400
|
+
/* @__PURE__ */ jsxs(View, { style: styles4.toggleRow, children: [
|
|
401
|
+
/* @__PURE__ */ jsxs(View, { children: [
|
|
402
|
+
/* @__PURE__ */ jsx(Text, { style: [styles4.toggleLabel, { color: colors.text }], children: t("cookieConsent.marketingLabel") }),
|
|
403
|
+
/* @__PURE__ */ jsx(Text, { style: [styles4.toggleDescription, { color: colors.textSecondary }], children: t("cookieConsent.marketingDescription") })
|
|
404
|
+
] }),
|
|
405
|
+
/* @__PURE__ */ jsx(
|
|
406
|
+
Switch,
|
|
407
|
+
{
|
|
408
|
+
accessibilityHint: t("cookieConsent.marketingToggleHint"),
|
|
409
|
+
accessibilityLabel: t("cookieConsent.marketingLabel"),
|
|
410
|
+
testID: LEGAL_TEST_IDS.cookieMarketingToggle,
|
|
411
|
+
trackColor: { true: primary, false: colors.border },
|
|
412
|
+
value: marketing,
|
|
413
|
+
onValueChange: setMarketing
|
|
414
|
+
}
|
|
415
|
+
)
|
|
416
|
+
] }),
|
|
417
|
+
/* @__PURE__ */ jsx(
|
|
418
|
+
ConsentButton,
|
|
419
|
+
{
|
|
420
|
+
primary: true,
|
|
421
|
+
a11yHint: t("cookieConsent.savePreferencesHint"),
|
|
422
|
+
label: t("cookieConsent.savePreferences"),
|
|
423
|
+
primaryColor: primary,
|
|
424
|
+
testID: LEGAL_TEST_IDS.cookieSavePreferences,
|
|
425
|
+
textColor: colors.surface,
|
|
426
|
+
onPress: handleSavePreferences
|
|
427
|
+
}
|
|
428
|
+
)
|
|
429
|
+
] }) : null,
|
|
430
|
+
/* @__PURE__ */ jsx(
|
|
431
|
+
Text,
|
|
432
|
+
{
|
|
433
|
+
accessibilityHint: t("cookieConsent.privacyLinkHint"),
|
|
434
|
+
accessibilityLabel: t("cookieConsent.privacyPolicyLink"),
|
|
435
|
+
accessibilityRole: "link",
|
|
436
|
+
style: [styles4.privacyLink, { color: primary }],
|
|
437
|
+
testID: LEGAL_TEST_IDS.cookiePrivacyLink,
|
|
438
|
+
onPress: handlePrivacyLink,
|
|
439
|
+
children: t("cookieConsent.privacyPolicyLink")
|
|
440
|
+
}
|
|
441
|
+
)
|
|
442
|
+
] }),
|
|
443
|
+
/* @__PURE__ */ jsx(PrivacyPolicyModal, { visible: showPrivacy, onClose: handleClosePrivacy })
|
|
444
|
+
] });
|
|
445
|
+
};
|
|
446
|
+
var CONTENT_PADDING2 = 16;
|
|
447
|
+
var BOTTOM_PADDING2 = 48;
|
|
448
|
+
var TITLE_FONT_SIZE2 = 24;
|
|
449
|
+
var TITLE_MARGIN_BOTTOM2 = 4;
|
|
450
|
+
var UPDATED_FONT_SIZE2 = 12;
|
|
451
|
+
var UPDATED_MARGIN_BOTTOM2 = 16;
|
|
452
|
+
var CLOSE_BUTTON_PADDING2 = 6;
|
|
453
|
+
var CLOSE_BUTTON_BORDER_RADIUS2 = 6;
|
|
454
|
+
var CLOSE_ICON_SIZE2 = 18;
|
|
455
|
+
var DEFAULT_LAST_UPDATED2 = "2026-03-12";
|
|
456
|
+
var styles5 = StyleSheet.create({
|
|
457
|
+
container: { flex: 1 },
|
|
458
|
+
scrollContent: { padding: CONTENT_PADDING2, paddingBottom: BOTTOM_PADDING2 },
|
|
459
|
+
headerRow: {
|
|
460
|
+
flexDirection: "row",
|
|
461
|
+
alignItems: "center",
|
|
462
|
+
justifyContent: "space-between"
|
|
463
|
+
},
|
|
464
|
+
title: { fontSize: TITLE_FONT_SIZE2, fontWeight: "700", marginBottom: TITLE_MARGIN_BOTTOM2 },
|
|
465
|
+
lastUpdated: { fontSize: UPDATED_FONT_SIZE2, marginBottom: UPDATED_MARGIN_BOTTOM2 },
|
|
466
|
+
closeButton: {
|
|
467
|
+
padding: CLOSE_BUTTON_PADDING2,
|
|
468
|
+
borderRadius: CLOSE_BUTTON_BORDER_RADIUS2
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
var SECTIONS2 = [
|
|
472
|
+
"acceptance",
|
|
473
|
+
"services",
|
|
474
|
+
"userAccounts",
|
|
475
|
+
"acceptableUse",
|
|
476
|
+
"intellectualProperty",
|
|
477
|
+
"dataPrivacy",
|
|
478
|
+
"paymentTerms",
|
|
479
|
+
"limitationOfLiability",
|
|
480
|
+
"indemnification",
|
|
481
|
+
"termination",
|
|
482
|
+
"disputeResolution",
|
|
483
|
+
"generalProvisions",
|
|
484
|
+
"contact"
|
|
485
|
+
];
|
|
486
|
+
var TermsOfServiceModal = ({
|
|
487
|
+
visible,
|
|
488
|
+
onClose,
|
|
489
|
+
lastUpdated = DEFAULT_LAST_UPDATED2
|
|
490
|
+
}) => {
|
|
491
|
+
const { theme, t } = useUi();
|
|
492
|
+
const colors = theme.colors;
|
|
493
|
+
return /* @__PURE__ */ jsx(
|
|
494
|
+
Modal,
|
|
495
|
+
{
|
|
496
|
+
animationType: "slide",
|
|
497
|
+
visible,
|
|
498
|
+
onRequestClose: onClose,
|
|
499
|
+
children: /* @__PURE__ */ jsx(View, { style: [styles5.container, { backgroundColor: colors.background }], testID: LEGAL_TEST_IDS.termsOfServiceScreen, children: /* @__PURE__ */ jsxs(
|
|
500
|
+
ScrollView,
|
|
501
|
+
{
|
|
502
|
+
accessibilityViewIsModal: true,
|
|
503
|
+
"aria-label": t("legal.termsOfService.title"),
|
|
504
|
+
contentContainerStyle: styles5.scrollContent,
|
|
505
|
+
role: "dialog",
|
|
506
|
+
children: [
|
|
507
|
+
/* @__PURE__ */ jsxs(View, { style: styles5.headerRow, children: [
|
|
508
|
+
/* @__PURE__ */ jsx(Text, { style: [styles5.title, { color: colors.text }], children: t("legal.termsOfService.title") }),
|
|
509
|
+
/* @__PURE__ */ jsx(
|
|
510
|
+
TouchableOpacity,
|
|
511
|
+
{
|
|
512
|
+
accessibilityHint: t("common.closeDialogHint"),
|
|
513
|
+
accessibilityLabel: t("common.close"),
|
|
514
|
+
accessibilityRole: "button",
|
|
515
|
+
style: styles5.closeButton,
|
|
516
|
+
testID: LEGAL_TEST_IDS.termsOfServiceClose,
|
|
517
|
+
onPress: onClose,
|
|
518
|
+
children: /* @__PURE__ */ jsx(SvgIcon, { color: colors.textSecondary, name: "close", size: CLOSE_ICON_SIZE2 })
|
|
519
|
+
}
|
|
520
|
+
)
|
|
521
|
+
] }),
|
|
522
|
+
/* @__PURE__ */ jsx(Text, { style: [styles5.lastUpdated, { color: colors.textSecondary }], children: t("legal.termsOfService.lastUpdated", lastUpdated) }),
|
|
523
|
+
SECTIONS2.map((key) => /* @__PURE__ */ jsx(
|
|
524
|
+
LegalSection,
|
|
525
|
+
{
|
|
526
|
+
body: t(`legal.termsOfService.${key}.body`),
|
|
527
|
+
title: t(`legal.termsOfService.${key}.title`)
|
|
528
|
+
},
|
|
529
|
+
key
|
|
530
|
+
))
|
|
531
|
+
]
|
|
532
|
+
}
|
|
533
|
+
) })
|
|
534
|
+
}
|
|
535
|
+
);
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
export { CONSENT_VERSION, COOKIE_CONSENT_STORAGE_KEY, ConsentButton, CookieConsentBanner, LEGAL_TEST_IDS, LegalSection, PrivacyPolicyModal, TermsOfServiceModal, useCookieConsent };
|
|
539
|
+
//# sourceMappingURL=index.mjs.map
|
|
540
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ConsentButton/ConsentButton.tsx","../src/LegalSection/LegalSection.tsx","../src/constants.ts","../src/PrivacyPolicyModal/PrivacyPolicyModal.tsx","../src/types.ts","../src/hooks/useCookieConsent.ts","../src/CookieConsentBanner/CookieConsentBanner.tsx","../src/TermsOfServiceModal/TermsOfServiceModal.tsx"],"names":["styles","StyleSheet","jsx","Text","useUi","View","jsxs","TouchableOpacity","BORDER_RADIUS","BORDER_WIDTH","useState","useCallback","CONTENT_PADDING","BOTTOM_PADDING","TITLE_FONT_SIZE","TITLE_MARGIN_BOTTOM","UPDATED_FONT_SIZE","UPDATED_MARGIN_BOTTOM","CLOSE_BUTTON_PADDING","CLOSE_BUTTON_BORDER_RADIUS","CLOSE_ICON_SIZE","DEFAULT_LAST_UPDATED","SECTIONS","Modal","ScrollView","SvgIcon"],"mappings":";;;;;;;AAQA,IAAM,aAAA,GAAgB,CAAA;AACtB,IAAM,gBAAA,GAAmB,EAAA;AACzB,IAAM,kBAAA,GAAqB,EAAA;AAC3B,IAAM,YAAA,GAAe,CAAA;AACrB,IAAM,SAAA,GAAY,EAAA;AAClB,IAAM,cAAA,GAAiB,CAAA;AAEvB,IAAM,MAAA,GAAS,WAAW,MAAA,CAAO;AAAA,EAC/B,IAAA,EAAM;AAAA,IACJ,YAAA,EAAc,aAAA;AAAA,IACd,eAAA,EAAiB,gBAAA;AAAA,IACjB,iBAAA,EAAmB,kBAAA;AAAA,IACnB,UAAA,EAAY,QAAA;AAAA,IACZ,cAAA,EAAgB,QAAA;AAAA,IAChB,WAAA,EAAa,YAAA;AAAA,IACb,UAAU,kBAAA,GAAqB,CAAA;AAAA,IAC/B,SAAA,EAAW;AAAA,GACb;AAAA,EACA,KAAA,EAAO;AAAA,IACL,QAAA,EAAU,SAAA;AAAA,IACV,UAAA,EAAY;AAAA;AAEhB,CAAC,CAAA;AAaM,IAAM,gBAAgB,CAAC;AAAA,EAC5B,KAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA,GAAU,KAAA;AAAA,EACV,YAAA;AAAA,EACA;AACF,CAAA,KAA8C;AAC5C,EAAA,MAAM,WAAA,GAAc,OAAA;AAAA,IAClB,MAAM;AAAA,MACJ,MAAA,CAAO,IAAA;AAAA,MACP;AAAA,QACE,eAAA,EAAiB,OAAA,GAAW,YAAA,IAAgB,aAAA,GAAiB,aAAA;AAAA,QAC7D,WAAA,EAAa,OAAA,GAAW,YAAA,IAAgB,aAAA,GAAkB,WAAA,IAAe;AAAA;AAC3E,KACF;AAAA,IACA,CAAC,OAAA,EAAS,YAAA,EAAc,WAAW;AAAA,GACrC;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,gBAAA;AAAA,IAAA;AAAA,MACC,iBAAA,EAAmB,QAAA;AAAA,MACnB,kBAAA,EAAoB,KAAA;AAAA,MACpB,iBAAA,EAAkB,QAAA;AAAA,MAClB,KAAA,EAAO,WAAA;AAAA,MACP,MAAA;AAAA,MACA,OAAA;AAAA,MAEA,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAO,CAAC,MAAA,CAAO,KAAA,EAAO,EAAE,KAAA,EAAO,SAAA,EAAW,CAAA,EAAI,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA,GAC5D;AAEJ;ACnEA,IAAM,qBAAA,GAAwB,EAAA;AAC9B,IAAM,kBAAA,GAAqB,EAAA;AAC3B,IAAM,2BAAA,GAA8B,CAAA;AACpC,IAAM,iBAAA,GAAoB,EAAA;AAC1B,IAAM,wBAAA,GAA2B,EAAA;AAEjC,IAAMA,OAAAA,GAASC,WAAW,MAAA,CAAO;AAAA,EAC/B,OAAA,EAAS,EAAE,YAAA,EAAc,qBAAA,EAAsB;AAAA,EAC/C,cAAc,EAAE,QAAA,EAAU,oBAAoB,UAAA,EAAY,KAAA,EAAO,cAAc,2BAAA,EAA4B;AAAA,EAC3G,WAAA,EAAa,EAAE,QAAA,EAAU,iBAAA,EAAmB,YAAY,wBAAA;AAC1D,CAAC,CAAA;AAOM,IAAM,YAAA,GAAe,CAAC,EAAE,KAAA,EAAO,MAAK,KAA6C;AACtF,EAAA,MAAM,EAAE,KAAA,EAAM,GAAI,KAAA,EAAM;AACxB,EAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AAErB,EAAA,uBACE,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAOD,OAAAA,CAAO,OAAA,EAClB,QAAA,EAAA;AAAA,oBAAAE,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACH,OAAAA,CAAO,YAAA,EAAc,EAAE,KAAA,EAAO,MAAA,CAAO,IAAA,EAAM,GAAI,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,oBACnEE,GAAAA,CAACC,IAAAA,EAAA,EAAK,OAAO,CAACH,OAAAA,CAAO,WAAA,EAAa,EAAE,KAAA,EAAO,MAAA,CAAO,aAAA,EAAe,GAAI,QAAA,EAAA,IAAA,EAAK;AAAA,GAAA,EAC5E,CAAA;AAEJ;;;AChCO,IAAM,0BAAA,GAA6B;AAMnC,IAAM,cAAA,GAAiB;AAAA,EAC5B,YAAA,EAAc,uBAAA;AAAA,EACd,eAAA,EAAiB,2BAAA;AAAA,EACjB,eAAA,EAAiB,2BAAA;AAAA,EACjB,eAAA,EAAiB,0BAAA;AAAA,EACjB,qBAAA,EAAuB,iCAAA;AAAA,EACvB,qBAAA,EAAuB,iCAAA;AAAA,EACvB,qBAAA,EAAuB,iCAAA;AAAA,EACvB,qBAAA,EAAuB,iCAAA;AAAA,EACvB,iBAAA,EAAmB,6BAAA;AAAA,EACnB,mBAAA,EAAqB,uBAAA;AAAA,EACrB,kBAAA,EAAoB,sBAAA;AAAA,EACpB,oBAAA,EAAsB,yBAAA;AAAA,EACtB,mBAAA,EAAqB;AACvB;ACVA,IAAM,eAAA,GAAkB,EAAA;AACxB,IAAM,cAAA,GAAiB,EAAA;AACvB,IAAM,eAAA,GAAkB,EAAA;AACxB,IAAM,mBAAA,GAAsB,CAAA;AAC5B,IAAM,iBAAA,GAAoB,EAAA;AAC1B,IAAM,qBAAA,GAAwB,EAAA;AAC9B,IAAM,oBAAA,GAAuB,CAAA;AAC7B,IAAM,0BAAA,GAA6B,CAAA;AACnC,IAAM,eAAA,GAAkB,EAAA;AAExB,IAAM,oBAAA,GAAuB,YAAA;AAE7B,IAAMA,OAAAA,GAASC,WAAW,MAAA,CAAO;AAAA,EAC/B,SAAA,EAAW,EAAE,IAAA,EAAM,CAAA,EAAE;AAAA,EACrB,aAAA,EAAe,EAAE,OAAA,EAAS,eAAA,EAAiB,eAAe,cAAA,EAAe;AAAA,EACzE,SAAA,EAAW;AAAA,IACT,aAAA,EAAe,KAAA;AAAA,IACf,UAAA,EAAY,QAAA;AAAA,IACZ,cAAA,EAAgB;AAAA,GAClB;AAAA,EACA,OAAO,EAAE,QAAA,EAAU,iBAAiB,UAAA,EAAY,KAAA,EAAO,cAAc,mBAAA,EAAoB;AAAA,EACzF,WAAA,EAAa,EAAE,QAAA,EAAU,iBAAA,EAAmB,cAAc,qBAAA,EAAsB;AAAA,EAChF,WAAA,EAAa;AAAA,IACX,OAAA,EAAS,oBAAA;AAAA,IACT,YAAA,EAAc;AAAA;AAElB,CAAC,CAAA;AAED,IAAM,QAAA,GAAW;AAAA,EACf,cAAA;AAAA,EACA,eAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,wBAAA;AAAA,EACA,eAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA,iBAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA;AACF,CAAA;AASO,IAAM,qBAAqB,CAAC;AAAA,EACjC,OAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA,GAAc;AAChB,CAAA,KAAmD;AACjD,EAAA,MAAM,EAAE,KAAA,EAAO,CAAA,EAAE,GAAIG,KAAAA,EAAM;AAC3B,EAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AAErB,EAAA,uBACEF,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,aAAA,EAAc,OAAA;AAAA,MACd,OAAA;AAAA,MACA,cAAA,EAAgB,OAAA;AAAA,MAEhB,0BAAAA,GAAAA,CAACG,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACL,OAAAA,CAAO,SAAA,EAAW,EAAE,eAAA,EAAiB,OAAO,UAAA,EAAY,GAAG,MAAA,EAAQ,cAAA,CAAe,qBAC9F,QAAA,kBAAAM,IAAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,wBAAA,EAAwB,IAAA;AAAA,UACxB,YAAA,EAAY,EAAE,2BAA2B,CAAA;AAAA,UACzC,uBAAuBN,OAAAA,CAAO,aAAA;AAAA,UAC9B,IAAA,EAAK,QAAA;AAAA,UAEL,QAAA,EAAA;AAAA,4BAAAM,IAAAA,CAACD,IAAAA,EAAA,EAAK,KAAA,EAAOL,QAAO,SAAA,EAClB,QAAA,EAAA;AAAA,8BAAAE,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACH,OAAAA,CAAO,KAAA,EAAO,EAAE,KAAA,EAAO,OAAO,IAAA,EAAM,CAAA,EAC/C,QAAA,EAAA,CAAA,CAAE,2BAA2B,CAAA,EAChC,CAAA;AAAA,8BACAE,GAAAA;AAAA,gBAACK,gBAAAA;AAAA,gBAAA;AAAA,kBACC,iBAAA,EAAmB,EAAE,wBAAwB,CAAA;AAAA,kBAC7C,kBAAA,EAAoB,EAAE,cAAc,CAAA;AAAA,kBACpC,iBAAA,EAAkB,QAAA;AAAA,kBAClB,OAAOP,OAAAA,CAAO,WAAA;AAAA,kBACd,QAAQ,cAAA,CAAe,kBAAA;AAAA,kBACvB,OAAA,EAAS,OAAA;AAAA,kBAET,QAAA,kBAAAE,IAAC,OAAA,EAAA,EAAQ,KAAA,EAAO,OAAO,aAAA,EAAe,IAAA,EAAK,OAAA,EAAQ,IAAA,EAAM,eAAA,EAAiB;AAAA;AAAA;AAC5E,aAAA,EACF,CAAA;AAAA,4BACAA,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACH,OAAAA,CAAO,WAAA,EAAa,EAAE,KAAA,EAAO,OAAO,aAAA,EAAe,GAC9D,QAAA,EAAA,CAAA,CAAE,iCAAA,EAAmC,WAAW,CAAA,EACnD,CAAA;AAAA,YAEC,QAAA,CAAS,GAAA,CAAI,CAAC,GAAA,qBACbE,GAAAA;AAAA,cAAC,YAAA;AAAA,cAAA;AAAA,gBAEC,IAAA,EAAM,CAAA,CAAE,CAAA,oBAAA,EAAuB,GAAG,CAAA,KAAA,CAAO,CAAA;AAAA,gBACzC,KAAA,EAAO,CAAA,CAAE,CAAA,oBAAA,EAAuB,GAAG,CAAA,MAAA,CAAQ;AAAA,eAAA;AAAA,cAFtC;AAAA,aAIR;AAAA;AAAA;AAAA,OACH,EACF;AAAA;AAAA,GACF;AAEJ;;;AC/GO,IAAM,eAAA,GAAkB;;;ACM/B,SAAS,SAAS,KAAA,EAAkD;AAClE,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC5E;AAGA,SAAS,gBAAgB,KAAA,EAAwC;AAC/D,EAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,KAAA;AAC7B,EAAA,OACE,KAAA,CAAM,WAAW,CAAA,KAAM,IAAA,IACvB,OAAO,KAAA,CAAM,WAAW,CAAA,KAAM,SAAA,IAC9B,OAAO,KAAA,CAAM,WAAW,CAAA,KAAM,SAAA,IAC9B,OAAO,KAAA,CAAM,aAAa,MAAM,QAAA,IAChC,OAAO,KAAA,CAAM,SAAS,CAAA,KAAM,QAAA;AAEhC;AAeA,SAAS,WAAA,GAAoC;AAC3C,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,IAAA;AAC1C,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,YAAA,CAAa,OAAA,CAAQ,0BAA0B,CAAA;AAClE,IAAA,IAAI,GAAA,KAAQ,MAAM,OAAO,IAAA;AACzB,IAAA,MAAM,MAAA,GAAkB,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AACtC,IAAA,IAAI,CAAC,eAAA,CAAgB,MAAM,CAAA,EAAG,OAAO,IAAA;AACrC,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,aAAa,OAAA,EAA8B;AAClD,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACnC,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,aAAa,OAAA,CAAQ,0BAAA,EAA4B,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,EACjF,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAEA,SAAS,YAAA,CAAa,WAAoB,SAAA,EAAmC;AAC3E,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,IAAA;AAAA,IACX,SAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,IACpC,OAAA,EAAS;AAAA,GACX;AACF;AAEO,SAAS,gBAAA,GAA2C;AACzD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,IAAI,QAAA,CAA+B,MAAM,aAAa,CAAA;AAGhF,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,UAAA,CAAW,aAAa,CAAA;AAAA,EAC1B,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,SAAA,GAAY,YAAY,MAAM;AAClC,IAAA,MAAM,MAAA,GAAS,YAAA,CAAa,IAAA,EAAM,IAAI,CAAA;AACtC,IAAA,YAAA,CAAa,MAAM,CAAA;AACnB,IAAA,UAAA,CAAW,MAAM,CAAA;AAAA,EACnB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,SAAA,GAAY,YAAY,MAAM;AAClC,IAAA,MAAM,MAAA,GAAS,YAAA,CAAa,KAAA,EAAO,KAAK,CAAA;AACxC,IAAA,YAAA,CAAa,MAAM,CAAA;AACnB,IAAA,UAAA,CAAW,MAAM,CAAA;AAAA,EACnB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,eAAA,GAAkB,WAAA,CAAY,CAAC,SAAA,EAAoB,SAAA,KAAuB;AAC9E,IAAA,MAAM,MAAA,GAAS,YAAA,CAAa,SAAA,EAAW,SAAS,CAAA;AAChD,IAAA,YAAA,CAAa,MAAM,CAAA;AACnB,IAAA,UAAA,CAAW,MAAM,CAAA;AAAA,EACnB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,aAAa,OAAA,KAAY,IAAA;AAE/B,EAAA,OAAO,EAAE,OAAA,EAAS,UAAA,EAAY,SAAA,EAAW,WAAW,eAAA,EAAgB;AACtE;ACnFA,IAAM,cAAA,GAAiB,EAAA;AACvB,IAAM,gBAAA,GAAmB,GAAA;AACzB,IAAMM,cAAAA,GAAgB,EAAA;AACtB,IAAM,WAAA,GAAc,EAAA;AACpB,IAAM,iBAAA,GAAoB,CAAA;AAC1B,IAAM,eAAA,GAAkB,EAAA;AACxB,IAAM,aAAA,GAAgB,CAAA;AACtB,IAAM,cAAA,GAAiB,IAAA;AACvB,IAAM,iBAAA,GAAoB,EAAA;AAC1B,IAAMC,aAAAA,GAAe,CAAA;AACrB,IAAM,iBAAA,GAAoB,EAAA;AAC1B,IAAM,mBAAA,GAAsB,EAAA;AAC5B,IAAM,eAAA,GAAkB,EAAA;AACxB,IAAM,sBAAA,GAAyB,CAAA;AAE/B,IAAMT,OAAAA,GAASC,WAAW,MAAA,CAAO;AAAA,EAC/B,OAAA,EAAS;AAAA,IACP,QAAA,EAAU,UAAA;AAAA,IACV,MAAA,EAAQ,CAAA;AAAA,IACR,IAAA,EAAM,CAAA;AAAA,IACN,KAAA,EAAO,CAAA;AAAA,IACP,UAAA,EAAY,QAAA;AAAA,IACZ,OAAA,EAAS,cAAA;AAAA,IACT,SAAA,EAAW,iBAAA;AAAA,IACX,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,KAAA,EAAO,MAAA;AAAA,IACP,QAAA,EAAU,gBAAA;AAAA,IACV,YAAA,EAAcO,cAAAA;AAAA,IACd,OAAA,EAAS,cAAA;AAAA,IACT,WAAA,EAAaC,aAAAA;AAAA,IACb,GAAG,SAAS,MAAA,CAAO;AAAA,MACjB,GAAA,EAAK;AAAA,QACH,WAAW,CAAA,IAAA,EAAO,eAAe,CAAA,GAAA,EAAM,aAAa,iBAAiB,cAAc,CAAA,CAAA;AAAA,OACrF;AAAA,MACA,OAAA,EAAS;AAAA,QACP,YAAA,EAAc,EAAE,KAAA,EAAO,CAAA,EAAG,QAAQ,eAAA,EAAgB;AAAA,QAClD,YAAA,EAAc,aAAA;AAAA,QACd,aAAA,EAAe;AAAA;AACjB,KACD;AAAA,GACH;AAAA,EACA,SAAS,EAAE,QAAA,EAAU,mBAAmB,UAAA,EAAY,mBAAA,EAAqB,cAAc,WAAA,EAAY;AAAA,EACnG,WAAW,EAAE,aAAA,EAAe,OAAO,GAAA,EAAK,WAAA,EAAa,UAAU,MAAA,EAAO;AAAA,EACtE,gBAAA,EAAkB,EAAE,SAAA,EAAW,WAAA,EAAY;AAAA,EAC3C,SAAA,EAAW;AAAA,IACT,aAAA,EAAe,KAAA;AAAA,IACf,cAAA,EAAgB,eAAA;AAAA,IAChB,UAAA,EAAY,QAAA;AAAA,IACZ,SAAA,EAAW;AAAA,GACb;AAAA,EACA,WAAA,EAAa,EAAE,QAAA,EAAU,iBAAA,EAAmB,YAAY,KAAA,EAAM;AAAA,EAC9D,iBAAA,EAAmB,EAAE,QAAA,EAAU,eAAA,EAAiB,WAAW,sBAAA,EAAuB;AAAA,EAClF,aAAa,EAAE,QAAA,EAAU,iBAAiB,SAAA,EAAW,WAAA,EAAa,oBAAoB,WAAA;AACxF,CAAC,CAAA;AAEM,IAAM,sBAAsB,MAAiC;AAClE,EAAA,MAAM,EAAE,KAAA,EAAO,CAAA,EAAE,GAAIL,KAAAA,EAAM;AAC3B,EAAA,MAAM,EAAE,UAAA,EAAY,SAAA,EAAW,SAAA,EAAW,eAAA,KAAoB,gBAAA,EAAiB;AAE/E,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAIM,SAAS,KAAK,CAAA;AACxD,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAIA,SAAS,KAAK,CAAA;AAEpD,EAAA,MAAM,eAAA,GAAkBC,YAAY,MAAM;AACxC,IAAA,gBAAA,CAAiB,CAAC,IAAA,KAAS,CAAC,IAAI,CAAA;AAAA,EAClC,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,qBAAA,GAAwBA,YAAY,MAAM;AAC9C,IAAA,eAAA,CAAgB,WAAW,SAAS,CAAA;AAAA,EACtC,CAAA,EAAG,CAAC,SAAA,EAAW,SAAA,EAAW,eAAe,CAAC,CAAA;AAE1C,EAAA,MAAM,oBAAoBA,WAAAA,CAAY,MAAM,eAAe,IAAI,CAAA,EAAG,EAAE,CAAA;AACpE,EAAA,MAAM,qBAAqBA,WAAAA,CAAY,MAAM,eAAe,KAAK,CAAA,EAAG,EAAE,CAAA;AAEtE,EAAA,IAAI,CAAC,YAAY,OAAO,IAAA;AAExB,EAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,EAAA,MAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAA;AAE3C,EAAA,uBACEL,KAACD,IAAAA,EAAA,EAAK,OAAOL,OAAAA,CAAO,OAAA,EAAS,MAAA,EAAQ,cAAA,CAAe,YAAA,EAClD,QAAA,EAAA;AAAA,oBAAAM,IAAAA,CAACD,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACL,OAAAA,CAAO,MAAA,EAAQ,EAAE,eAAA,EAAiB,OAAO,OAAA,EAAS,WAAA,EAAa,MAAA,CAAO,MAAA,EAAQ,CAAA,EAC1F,QAAA,EAAA;AAAA,sBAAAE,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACH,OAAAA,CAAO,OAAA,EAAS,EAAE,KAAA,EAAO,OAAO,IAAA,EAAM,CAAA,EAAI,QAAA,EAAA,CAAA,CAAE,uBAAuB,CAAA,EAAE,CAAA;AAAA,sBAEnFM,IAAAA,CAACD,IAAAA,EAAA,EAAK,KAAA,EAAOL,QAAO,SAAA,EAClB,QAAA,EAAA;AAAA,wBAAAE,GAAAA;AAAA,UAAC,aAAA;AAAA,UAAA;AAAA,YACC,OAAA,EAAO,IAAA;AAAA,YACP,QAAA,EAAU,EAAE,6BAA6B,CAAA;AAAA,YACzC,KAAA,EAAO,EAAE,yBAAyB,CAAA;AAAA,YAClC,YAAA,EAAc,OAAA;AAAA,YACd,QAAQ,cAAA,CAAe,eAAA;AAAA,YACvB,WAAW,MAAA,CAAO,OAAA;AAAA,YAClB,OAAA,EAAS;AAAA;AAAA,SACX;AAAA,wBACAA,GAAAA;AAAA,UAAC,aAAA;AAAA,UAAA;AAAA,YACC,QAAA,EAAU,EAAE,6BAA6B,CAAA;AAAA,YACzC,aAAa,MAAA,CAAO,MAAA;AAAA,YACpB,KAAA,EAAO,EAAE,yBAAyB,CAAA;AAAA,YAClC,QAAQ,cAAA,CAAe,eAAA;AAAA,YACvB,WAAW,MAAA,CAAO,IAAA;AAAA,YAClB,OAAA,EAAS;AAAA;AAAA,SACX;AAAA,wBACAA,GAAAA;AAAA,UAAC,aAAA;AAAA,UAAA;AAAA,YACC,QAAA,EAAU,EAAE,6BAA6B,CAAA;AAAA,YACzC,aAAa,MAAA,CAAO,MAAA;AAAA,YACpB,KAAA,EAAO,EAAE,yBAAyB,CAAA;AAAA,YAClC,QAAQ,cAAA,CAAe,eAAA;AAAA,YACvB,WAAW,MAAA,CAAO,IAAA;AAAA,YAClB,OAAA,EAAS;AAAA;AAAA;AACX,OAAA,EACF,CAAA;AAAA,MAEC,gCACCI,IAAAA,CAACD,MAAA,EAAK,KAAA,EAAOL,QAAO,gBAAA,EAClB,QAAA,EAAA;AAAA,wBAAAM,IAAAA,CAACD,IAAAA,EAAA,EAAK,KAAA,EAAOL,QAAO,SAAA,EAClB,QAAA,EAAA;AAAA,0BAAAM,IAAAA,CAACD,MAAA,EACC,QAAA,EAAA;AAAA,4BAAAH,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACH,OAAAA,CAAO,WAAA,EAAa,EAAE,KAAA,EAAO,OAAO,IAAA,EAAM,CAAA,EAAI,QAAA,EAAA,CAAA,CAAE,8BAA8B,CAAA,EAAE,CAAA;AAAA,4BAC9FE,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACH,OAAAA,CAAO,iBAAA,EAAmB,EAAE,KAAA,EAAO,OAAO,aAAA,EAAe,CAAA,EACpE,QAAA,EAAA,CAAA,CAAE,oCAAoC,CAAA,EACzC;AAAA,WAAA,EACF,CAAA;AAAA,0BACAE,GAAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cACC,QAAA,EAAQ,IAAA;AAAA,cACR,KAAA,EAAK,IAAA;AAAA,cACL,iBAAA,EAAmB,EAAE,mCAAmC,CAAA;AAAA,cACxD,kBAAA,EAAoB,EAAE,8BAA8B,CAAA;AAAA,cACpD,QAAQ,cAAA,CAAe,qBAAA;AAAA,cACvB,YAAY,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO,OAAO,MAAA;AAAO;AAAA;AACpD,SAAA,EACF,CAAA;AAAA,wBAEAI,IAAAA,CAACD,IAAAA,EAAA,EAAK,KAAA,EAAOL,QAAO,SAAA,EAClB,QAAA,EAAA;AAAA,0BAAAM,IAAAA,CAACD,MAAA,EACC,QAAA,EAAA;AAAA,4BAAAH,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACH,OAAAA,CAAO,WAAA,EAAa,EAAE,KAAA,EAAO,OAAO,IAAA,EAAM,CAAA,EAAI,QAAA,EAAA,CAAA,CAAE,8BAA8B,CAAA,EAAE,CAAA;AAAA,4BAC9FE,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACH,OAAAA,CAAO,iBAAA,EAAmB,EAAE,KAAA,EAAO,OAAO,aAAA,EAAe,CAAA,EACpE,QAAA,EAAA,CAAA,CAAE,oCAAoC,CAAA,EACzC;AAAA,WAAA,EACF,CAAA;AAAA,0BACAE,GAAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cACC,iBAAA,EAAmB,EAAE,mCAAmC,CAAA;AAAA,cACxD,kBAAA,EAAoB,EAAE,8BAA8B,CAAA;AAAA,cACpD,QAAQ,cAAA,CAAe,qBAAA;AAAA,cACvB,YAAY,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO,OAAO,MAAA,EAAO;AAAA,cAClD,KAAA,EAAO,SAAA;AAAA,cACP,aAAA,EAAe;AAAA;AAAA;AACjB,SAAA,EACF,CAAA;AAAA,wBAEAI,IAAAA,CAACD,IAAAA,EAAA,EAAK,KAAA,EAAOL,QAAO,SAAA,EAClB,QAAA,EAAA;AAAA,0BAAAM,IAAAA,CAACD,MAAA,EACC,QAAA,EAAA;AAAA,4BAAAH,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACH,OAAAA,CAAO,WAAA,EAAa,EAAE,KAAA,EAAO,OAAO,IAAA,EAAM,CAAA,EAAI,QAAA,EAAA,CAAA,CAAE,8BAA8B,CAAA,EAAE,CAAA;AAAA,4BAC9FE,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACH,OAAAA,CAAO,iBAAA,EAAmB,EAAE,KAAA,EAAO,OAAO,aAAA,EAAe,CAAA,EACpE,QAAA,EAAA,CAAA,CAAE,oCAAoC,CAAA,EACzC;AAAA,WAAA,EACF,CAAA;AAAA,0BACAE,GAAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cACC,iBAAA,EAAmB,EAAE,mCAAmC,CAAA;AAAA,cACxD,kBAAA,EAAoB,EAAE,8BAA8B,CAAA;AAAA,cACpD,QAAQ,cAAA,CAAe,qBAAA;AAAA,cACvB,YAAY,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO,OAAO,MAAA,EAAO;AAAA,cAClD,KAAA,EAAO,SAAA;AAAA,cACP,aAAA,EAAe;AAAA;AAAA;AACjB,SAAA,EACF,CAAA;AAAA,wBAEAA,GAAAA;AAAA,UAAC,aAAA;AAAA,UAAA;AAAA,YACC,OAAA,EAAO,IAAA;AAAA,YACP,QAAA,EAAU,EAAE,mCAAmC,CAAA;AAAA,YAC/C,KAAA,EAAO,EAAE,+BAA+B,CAAA;AAAA,YACxC,YAAA,EAAc,OAAA;AAAA,YACd,QAAQ,cAAA,CAAe,qBAAA;AAAA,YACvB,WAAW,MAAA,CAAO,OAAA;AAAA,YAClB,OAAA,EAAS;AAAA;AAAA;AACX,OAAA,EACF,CAAA,GACE,IAAA;AAAA,sBAEJA,GAAAA;AAAA,QAACC,IAAAA;AAAA,QAAA;AAAA,UACC,iBAAA,EAAmB,EAAE,+BAA+B,CAAA;AAAA,UACpD,kBAAA,EAAoB,EAAE,iCAAiC,CAAA;AAAA,UACvD,iBAAA,EAAkB,MAAA;AAAA,UAClB,OAAO,CAACH,OAAAA,CAAO,aAAa,EAAE,KAAA,EAAO,SAAS,CAAA;AAAA,UAC9C,QAAQ,cAAA,CAAe,iBAAA;AAAA,UACvB,OAAA,EAAS,iBAAA;AAAA,UAER,YAAE,iCAAiC;AAAA;AAAA;AACtC,KAAA,EACF,CAAA;AAAA,oBACAE,GAAAA,CAAC,kBAAA,EAAA,EAAmB,OAAA,EAAS,WAAA,EAAa,SAAS,kBAAA,EAAoB;AAAA,GAAA,EACzE,CAAA;AAEJ;ACtMA,IAAMU,gBAAAA,GAAkB,EAAA;AACxB,IAAMC,eAAAA,GAAiB,EAAA;AACvB,IAAMC,gBAAAA,GAAkB,EAAA;AACxB,IAAMC,oBAAAA,GAAsB,CAAA;AAC5B,IAAMC,kBAAAA,GAAoB,EAAA;AAC1B,IAAMC,sBAAAA,GAAwB,EAAA;AAC9B,IAAMC,qBAAAA,GAAuB,CAAA;AAC7B,IAAMC,2BAAAA,GAA6B,CAAA;AACnC,IAAMC,gBAAAA,GAAkB,EAAA;AAExB,IAAMC,qBAAAA,GAAuB,YAAA;AAE7B,IAAMrB,OAAAA,GAASC,WAAW,MAAA,CAAO;AAAA,EAC/B,SAAA,EAAW,EAAE,IAAA,EAAM,CAAA,EAAE;AAAA,EACrB,aAAA,EAAe,EAAE,OAAA,EAASW,gBAAAA,EAAiB,eAAeC,eAAAA,EAAe;AAAA,EACzE,SAAA,EAAW;AAAA,IACT,aAAA,EAAe,KAAA;AAAA,IACf,UAAA,EAAY,QAAA;AAAA,IACZ,cAAA,EAAgB;AAAA,GAClB;AAAA,EACA,OAAO,EAAE,QAAA,EAAUC,kBAAiB,UAAA,EAAY,KAAA,EAAO,cAAcC,oBAAAA,EAAoB;AAAA,EACzF,WAAA,EAAa,EAAE,QAAA,EAAUC,kBAAAA,EAAmB,cAAcC,sBAAAA,EAAsB;AAAA,EAChF,WAAA,EAAa;AAAA,IACX,OAAA,EAASC,qBAAAA;AAAA,IACT,YAAA,EAAcC;AAAA;AAElB,CAAC,CAAA;AAED,IAAMG,SAAAA,GAAW;AAAA,EACf,YAAA;AAAA,EACA,UAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,sBAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,uBAAA;AAAA,EACA,iBAAA;AAAA,EACA,aAAA;AAAA,EACA,mBAAA;AAAA,EACA,mBAAA;AAAA,EACA;AACF,CAAA;AASO,IAAM,sBAAsB,CAAC;AAAA,EAClC,OAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA,GAAcD;AAChB,CAAA,KAAoD;AAClD,EAAA,MAAM,EAAE,KAAA,EAAO,CAAA,EAAE,GAAIjB,KAAAA,EAAM;AAC3B,EAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AAErB,EAAA,uBACEF,GAAAA;AAAA,IAACqB,KAAAA;AAAA,IAAA;AAAA,MACC,aAAA,EAAc,OAAA;AAAA,MACd,OAAA;AAAA,MACA,cAAA,EAAgB,OAAA;AAAA,MAEhB,0BAAArB,GAAAA,CAACG,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACL,OAAAA,CAAO,SAAA,EAAW,EAAE,eAAA,EAAiB,OAAO,UAAA,EAAY,GAAG,MAAA,EAAQ,cAAA,CAAe,sBAC9F,QAAA,kBAAAM,IAAAA;AAAA,QAACkB,UAAAA;AAAA,QAAA;AAAA,UACC,wBAAA,EAAwB,IAAA;AAAA,UACxB,YAAA,EAAY,EAAE,4BAA4B,CAAA;AAAA,UAC1C,uBAAuBxB,OAAAA,CAAO,aAAA;AAAA,UAC9B,IAAA,EAAK,QAAA;AAAA,UAEL,QAAA,EAAA;AAAA,4BAAAM,IAAAA,CAACD,IAAAA,EAAA,EAAK,KAAA,EAAOL,QAAO,SAAA,EAClB,QAAA,EAAA;AAAA,8BAAAE,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACH,OAAAA,CAAO,KAAA,EAAO,EAAE,KAAA,EAAO,OAAO,IAAA,EAAM,CAAA,EAC/C,QAAA,EAAA,CAAA,CAAE,4BAA4B,CAAA,EACjC,CAAA;AAAA,8BACAE,GAAAA;AAAA,gBAACK,gBAAAA;AAAA,gBAAA;AAAA,kBACC,iBAAA,EAAmB,EAAE,wBAAwB,CAAA;AAAA,kBAC7C,kBAAA,EAAoB,EAAE,cAAc,CAAA;AAAA,kBACpC,iBAAA,EAAkB,QAAA;AAAA,kBAClB,OAAOP,OAAAA,CAAO,WAAA;AAAA,kBACd,QAAQ,cAAA,CAAe,mBAAA;AAAA,kBACvB,OAAA,EAAS,OAAA;AAAA,kBAET,QAAA,kBAAAE,GAAAA,CAACuB,OAAAA,EAAA,EAAQ,KAAA,EAAO,OAAO,aAAA,EAAe,IAAA,EAAK,OAAA,EAAQ,IAAA,EAAML,gBAAAA,EAAiB;AAAA;AAAA;AAC5E,aAAA,EACF,CAAA;AAAA,4BACAlB,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACH,OAAAA,CAAO,WAAA,EAAa,EAAE,KAAA,EAAO,OAAO,aAAA,EAAe,GAC9D,QAAA,EAAA,CAAA,CAAE,kCAAA,EAAoC,WAAW,CAAA,EACpD,CAAA;AAAA,YAECsB,SAAAA,CAAS,GAAA,CAAI,CAAC,GAAA,qBACbpB,GAAAA;AAAA,cAAC,YAAA;AAAA,cAAA;AAAA,gBAEC,IAAA,EAAM,CAAA,CAAE,CAAA,qBAAA,EAAwB,GAAG,CAAA,KAAA,CAAO,CAAA;AAAA,gBAC1C,KAAA,EAAO,CAAA,CAAE,CAAA,qBAAA,EAAwB,GAAG,CAAA,MAAA,CAAQ;AAAA,eAAA;AAAA,cAFvC;AAAA,aAIR;AAAA;AAAA;AAAA,OACH,EACF;AAAA;AAAA,GACF;AAEJ","file":"index.mjs","sourcesContent":["/**\n * Reusable button for the cookie consent banner.\n * Supports primary (filled) and secondary (outlined) variants. Colours are passed in.\n */\nimport React, { useMemo } from 'react';\n\nimport { StyleSheet, TouchableOpacity, Text } from 'react-native';\n\nconst BORDER_RADIUS = 8;\nconst PADDING_VERTICAL = 10;\nconst PADDING_HORIZONTAL = 16;\nconst BORDER_WIDTH = 1;\nconst FONT_SIZE = 14;\nconst MIN_MARGIN_TOP = 8;\n\nconst styles = StyleSheet.create({\n base: {\n borderRadius: BORDER_RADIUS,\n paddingVertical: PADDING_VERTICAL,\n paddingHorizontal: PADDING_HORIZONTAL,\n alignItems: 'center',\n justifyContent: 'center',\n borderWidth: BORDER_WIDTH,\n minWidth: PADDING_HORIZONTAL * 2,\n marginTop: MIN_MARGIN_TOP,\n },\n label: {\n fontSize: FONT_SIZE,\n fontWeight: '600',\n },\n});\n\nexport interface ConsentButtonProps {\n label: string;\n testID: string;\n textColor: string;\n onPress: () => void;\n a11yHint: string;\n primary?: boolean;\n primaryColor?: string;\n borderColor?: string;\n}\n\nexport const ConsentButton = ({\n label,\n testID,\n textColor,\n onPress,\n a11yHint,\n primary = false,\n primaryColor,\n borderColor,\n}: ConsentButtonProps): React.ReactElement => {\n const buttonStyle = useMemo(\n () => [\n styles.base,\n {\n backgroundColor: primary ? (primaryColor ?? 'transparent') : 'transparent',\n borderColor: primary ? (primaryColor ?? 'transparent') : (borderColor ?? 'transparent'),\n },\n ],\n [primary, primaryColor, borderColor],\n );\n\n return (\n <TouchableOpacity\n accessibilityHint={a11yHint}\n accessibilityLabel={label}\n accessibilityRole=\"button\"\n style={buttonStyle}\n testID={testID}\n onPress={onPress}\n >\n <Text style={[styles.label, { color: textColor }]}>{label}</Text>\n </TouchableOpacity>\n );\n};\n\nexport default ConsentButton;\n","/**\n * A single section within a legal page (title + body text).\n */\nimport React from 'react';\n\nimport { StyleSheet, View, Text } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nconst SECTION_MARGIN_BOTTOM = 20;\nconst SECTION_TITLE_SIZE = 18;\nconst SECTION_TITLE_MARGIN_BOTTOM = 8;\nconst SECTION_BODY_SIZE = 14;\nconst SECTION_BODY_LINE_HEIGHT = 22;\n\nconst styles = StyleSheet.create({\n section: { marginBottom: SECTION_MARGIN_BOTTOM },\n sectionTitle: { fontSize: SECTION_TITLE_SIZE, fontWeight: '600', marginBottom: SECTION_TITLE_MARGIN_BOTTOM },\n sectionBody: { fontSize: SECTION_BODY_SIZE, lineHeight: SECTION_BODY_LINE_HEIGHT },\n});\n\nexport interface LegalSectionProps {\n title: string;\n body: string;\n}\n\nexport const LegalSection = ({ title, body }: LegalSectionProps): React.ReactElement => {\n const { theme } = useUi();\n const colors = theme.colors;\n\n return (\n <View style={styles.section}>\n <Text style={[styles.sectionTitle, { color: colors.text }]}>{title}</Text>\n <Text style={[styles.sectionBody, { color: colors.textSecondary }]}>{body}</Text>\n </View>\n );\n};\n\nexport default LegalSection;\n","/**\n * localStorage key for the persisted consent record. Kept as the exact string the\n * apps already used so existing visitors' stored consent is preserved after migration.\n */\nexport const COOKIE_CONSENT_STORAGE_KEY = 'COOKIE_CONSENT';\n\n/**\n * Default testID strings — match the values the consuming apps already used so existing\n * Playwright selectors keep working.\n */\nexport const LEGAL_TEST_IDS = {\n cookieBanner: 'cookie-consent-banner',\n cookieAcceptAll: 'cookie-consent-accept-all',\n cookieRejectAll: 'cookie-consent-reject-all',\n cookieCustomize: 'cookie-consent-customize',\n cookieSavePreferences: 'cookie-consent-save-preferences',\n cookieEssentialToggle: 'cookie-consent-essential-toggle',\n cookieAnalyticsToggle: 'cookie-consent-analytics-toggle',\n cookieMarketingToggle: 'cookie-consent-marketing-toggle',\n cookiePrivacyLink: 'cookie-consent-privacy-link',\n privacyPolicyScreen: 'privacy-policy-screen',\n privacyPolicyClose: 'privacy-policy-close',\n termsOfServiceScreen: 'terms-of-service-screen',\n termsOfServiceClose: 'terms-of-service-close',\n} as const;\n","/**\n * Privacy Policy modal — full-screen scrollable legal text built from translated sections.\n * Content keys live in the consuming app's locale files (legal.privacyPolicy.*).\n */\nimport React from 'react';\n\nimport { Modal, StyleSheet, View, Text, ScrollView, TouchableOpacity } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\nimport { SvgIcon } from '@dloizides/ui-icons';\n\nimport { LegalSection } from '../LegalSection/LegalSection';\nimport { LEGAL_TEST_IDS } from '../constants';\n\nconst CONTENT_PADDING = 16;\nconst BOTTOM_PADDING = 48;\nconst TITLE_FONT_SIZE = 24;\nconst TITLE_MARGIN_BOTTOM = 4;\nconst UPDATED_FONT_SIZE = 12;\nconst UPDATED_MARGIN_BOTTOM = 16;\nconst CLOSE_BUTTON_PADDING = 6;\nconst CLOSE_BUTTON_BORDER_RADIUS = 6;\nconst CLOSE_ICON_SIZE = 18;\n\nconst DEFAULT_LAST_UPDATED = '2026-03-12';\n\nconst styles = StyleSheet.create({\n container: { flex: 1 },\n scrollContent: { padding: CONTENT_PADDING, paddingBottom: BOTTOM_PADDING },\n headerRow: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n },\n title: { fontSize: TITLE_FONT_SIZE, fontWeight: '700', marginBottom: TITLE_MARGIN_BOTTOM },\n lastUpdated: { fontSize: UPDATED_FONT_SIZE, marginBottom: UPDATED_MARGIN_BOTTOM },\n closeButton: {\n padding: CLOSE_BUTTON_PADDING,\n borderRadius: CLOSE_BUTTON_BORDER_RADIUS,\n },\n});\n\nconst SECTIONS = [\n 'introduction',\n 'dataWeCollect',\n 'howWeUse',\n 'legalBasis',\n 'dataSharing',\n 'internationalTransfers',\n 'dataRetention',\n 'yourRights',\n 'cookies',\n 'childrenPrivacy',\n 'dataSecurity',\n 'policyChanges',\n 'contact',\n] as const;\n\nexport interface PrivacyPolicyModalProps {\n visible: boolean;\n onClose: () => void;\n /** ISO date shown in the \"last updated\" line. Defaults to the bundled placeholder. */\n lastUpdated?: string;\n}\n\nexport const PrivacyPolicyModal = ({\n visible,\n onClose,\n lastUpdated = DEFAULT_LAST_UPDATED,\n}: PrivacyPolicyModalProps): React.ReactElement => {\n const { theme, t } = useUi();\n const colors = theme.colors;\n\n return (\n <Modal\n animationType=\"slide\"\n visible={visible}\n onRequestClose={onClose}\n >\n <View style={[styles.container, { backgroundColor: colors.background }]} testID={LEGAL_TEST_IDS.privacyPolicyScreen}>\n <ScrollView\n accessibilityViewIsModal\n aria-label={t('legal.privacyPolicy.title')}\n contentContainerStyle={styles.scrollContent}\n role=\"dialog\"\n >\n <View style={styles.headerRow}>\n <Text style={[styles.title, { color: colors.text }]}>\n {t('legal.privacyPolicy.title')}\n </Text>\n <TouchableOpacity\n accessibilityHint={t('common.closeDialogHint')}\n accessibilityLabel={t('common.close')}\n accessibilityRole=\"button\"\n style={styles.closeButton}\n testID={LEGAL_TEST_IDS.privacyPolicyClose}\n onPress={onClose}\n >\n <SvgIcon color={colors.textSecondary} name=\"close\" size={CLOSE_ICON_SIZE} />\n </TouchableOpacity>\n </View>\n <Text style={[styles.lastUpdated, { color: colors.textSecondary }]}>\n {t('legal.privacyPolicy.lastUpdated', lastUpdated)}\n </Text>\n\n {SECTIONS.map((key) => (\n <LegalSection\n key={key}\n body={t(`legal.privacyPolicy.${key}.body`)}\n title={t(`legal.privacyPolicy.${key}.title`)}\n />\n ))}\n </ScrollView>\n </View>\n </Modal>\n );\n};\n\nexport default PrivacyPolicyModal;\n","/**\n * Types for the GDPR cookie consent system.\n */\n\n/** Current version of the consent schema. Bump when consent categories change. */\nexport const CONSENT_VERSION = '1.0';\n\n/** Shape of the consent record persisted in localStorage. */\nexport interface CookieConsent {\n /** Always true — essential cookies cannot be disabled. */\n necessary: true;\n /** Whether the user opted in to analytics cookies. */\n analytics: boolean;\n /** Whether the user opted in to marketing cookies. */\n marketing: boolean;\n /** ISO-8601 timestamp of when consent was given. */\n consentedAt: string;\n /** Schema version that was active when consent was captured. */\n version: string;\n}\n","/**\n * Hook for reading and writing GDPR cookie consent from localStorage.\n *\n * Returns the current consent state plus helpers to accept all,\n * reject all, or save custom preferences.\n */\nimport { useState, useCallback, useEffect } from 'react';\n\nimport { COOKIE_CONSENT_STORAGE_KEY } from '../constants';\nimport { CONSENT_VERSION, type CookieConsent } from '../types';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Runtime type guard for stored consent records. */\nfunction isCookieConsent(value: unknown): value is CookieConsent {\n if (!isRecord(value)) return false;\n return (\n value['necessary'] === true &&\n typeof value['analytics'] === 'boolean' &&\n typeof value['marketing'] === 'boolean' &&\n typeof value['consentedAt'] === 'string' &&\n typeof value['version'] === 'string'\n );\n}\n\nexport interface UseCookieConsentReturn {\n /** Current consent record, or null if user has not yet responded. */\n consent: CookieConsent | null;\n /** Whether the banner should be shown (no consent recorded yet). */\n showBanner: boolean;\n /** Accept all cookie categories. */\n acceptAll: () => void;\n /** Reject all optional cookie categories. */\n rejectAll: () => void;\n /** Save custom category preferences. */\n savePreferences: (analytics: boolean, marketing: boolean) => void;\n}\n\nfunction readConsent(): CookieConsent | null {\n if (typeof window === 'undefined') return null;\n try {\n const raw = window.localStorage.getItem(COOKIE_CONSENT_STORAGE_KEY);\n if (raw === null) return null;\n const parsed: unknown = JSON.parse(raw);\n if (!isCookieConsent(parsed)) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n\nfunction writeConsent(consent: CookieConsent): void {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(COOKIE_CONSENT_STORAGE_KEY, JSON.stringify(consent));\n } catch {\n // localStorage may be unavailable (private browsing, quota exceeded)\n }\n}\n\nfunction buildConsent(analytics: boolean, marketing: boolean): CookieConsent {\n return {\n necessary: true,\n analytics,\n marketing,\n consentedAt: new Date().toISOString(),\n version: CONSENT_VERSION,\n };\n}\n\nexport function useCookieConsent(): UseCookieConsentReturn {\n const [consent, setConsent] = useState<CookieConsent | null>(() => readConsent());\n\n // Re-read on mount to handle SSR hydration mismatch\n useEffect(() => {\n setConsent(readConsent());\n }, []);\n\n const acceptAll = useCallback(() => {\n const record = buildConsent(true, true);\n writeConsent(record);\n setConsent(record);\n }, []);\n\n const rejectAll = useCallback(() => {\n const record = buildConsent(false, false);\n writeConsent(record);\n setConsent(record);\n }, []);\n\n const savePreferences = useCallback((analytics: boolean, marketing: boolean) => {\n const record = buildConsent(analytics, marketing);\n writeConsent(record);\n setConsent(record);\n }, []);\n\n const showBanner = consent === null;\n\n return { consent, showBanner, acceptAll, rejectAll, savePreferences };\n}\n","/**\n * GDPR Cookie Consent Banner.\n *\n * Appears at the bottom of the screen on first visit. Allows the user to accept all,\n * reject all, or customise analytics/marketing cookies. Consent is persisted in\n * localStorage (via useCookieConsent) so the banner only shows once.\n */\nimport React, { useState, useCallback } from 'react';\n\nimport { StyleSheet, View, Text, Switch, Platform } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { ConsentButton } from '../ConsentButton/ConsentButton';\nimport { PrivacyPolicyModal } from '../PrivacyPolicyModal/PrivacyPolicyModal';\nimport { useCookieConsent } from '../hooks/useCookieConsent';\nimport { LEGAL_TEST_IDS } from '../constants';\n\nconst BANNER_PADDING = 16;\nconst BANNER_MAX_WIDTH = 640;\nconst BORDER_RADIUS = 12;\nconst SECTION_GAP = 12;\nconst TOGGLE_MARGIN_TOP = 8;\nconst SHADOW_OFFSET_Y = -2;\nconst SHADOW_RADIUS = 8;\nconst SHADOW_OPACITY = 0.15;\nconst OVERLAY_ELEVATION = 20;\nconst BORDER_WIDTH = 1;\nconst MESSAGE_FONT_SIZE = 14;\nconst MESSAGE_LINE_HEIGHT = 20;\nconst SMALL_FONT_SIZE = 12;\nconst TOGGLE_DESC_MARGIN_TOP = 2;\n\nconst styles = StyleSheet.create({\n overlay: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n alignItems: 'center',\n padding: BANNER_PADDING,\n elevation: OVERLAY_ELEVATION,\n zIndex: OVERLAY_ELEVATION,\n },\n banner: {\n width: '100%',\n maxWidth: BANNER_MAX_WIDTH,\n borderRadius: BORDER_RADIUS,\n padding: BANNER_PADDING,\n borderWidth: BORDER_WIDTH,\n ...Platform.select({\n web: {\n boxShadow: `0px ${SHADOW_OFFSET_Y}px ${SHADOW_RADIUS}px rgba(0,0,0,${SHADOW_OPACITY})`,\n },\n default: {\n shadowOffset: { width: 0, height: SHADOW_OFFSET_Y },\n shadowRadius: SHADOW_RADIUS,\n shadowOpacity: SHADOW_OPACITY,\n },\n }),\n },\n message: { fontSize: MESSAGE_FONT_SIZE, lineHeight: MESSAGE_LINE_HEIGHT, marginBottom: SECTION_GAP },\n buttonRow: { flexDirection: 'row', gap: SECTION_GAP, flexWrap: 'wrap' },\n customiseSection: { marginTop: SECTION_GAP },\n toggleRow: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginTop: TOGGLE_MARGIN_TOP,\n },\n toggleLabel: { fontSize: MESSAGE_FONT_SIZE, fontWeight: '600' },\n toggleDescription: { fontSize: SMALL_FONT_SIZE, marginTop: TOGGLE_DESC_MARGIN_TOP },\n privacyLink: { fontSize: SMALL_FONT_SIZE, marginTop: SECTION_GAP, textDecorationLine: 'underline' },\n});\n\nexport const CookieConsentBanner = (): React.ReactElement | null => {\n const { theme, t } = useUi();\n const { showBanner, acceptAll, rejectAll, savePreferences } = useCookieConsent();\n\n const [showCustomise, setShowCustomise] = useState(false);\n const [analytics, setAnalytics] = useState(false);\n const [marketing, setMarketing] = useState(false);\n const [showPrivacy, setShowPrivacy] = useState(false);\n\n const handleCustomise = useCallback(() => {\n setShowCustomise((prev) => !prev);\n }, []);\n\n const handleSavePreferences = useCallback(() => {\n savePreferences(analytics, marketing);\n }, [analytics, marketing, savePreferences]);\n\n const handlePrivacyLink = useCallback(() => setShowPrivacy(true), []);\n const handleClosePrivacy = useCallback(() => setShowPrivacy(false), []);\n\n if (!showBanner) return null;\n\n const colors = theme.colors;\n const primary = theme.palette.primary['500'];\n\n return (\n <View style={styles.overlay} testID={LEGAL_TEST_IDS.cookieBanner}>\n <View style={[styles.banner, { backgroundColor: colors.surface, borderColor: colors.border }]}>\n <Text style={[styles.message, { color: colors.text }]}>{t('cookieConsent.message')}</Text>\n\n <View style={styles.buttonRow}>\n <ConsentButton\n primary\n a11yHint={t('cookieConsent.acceptAllHint')}\n label={t('cookieConsent.acceptAll')}\n primaryColor={primary}\n testID={LEGAL_TEST_IDS.cookieAcceptAll}\n textColor={colors.surface}\n onPress={acceptAll}\n />\n <ConsentButton\n a11yHint={t('cookieConsent.rejectAllHint')}\n borderColor={colors.border}\n label={t('cookieConsent.rejectAll')}\n testID={LEGAL_TEST_IDS.cookieRejectAll}\n textColor={colors.text}\n onPress={rejectAll}\n />\n <ConsentButton\n a11yHint={t('cookieConsent.customizeHint')}\n borderColor={colors.border}\n label={t('cookieConsent.customize')}\n testID={LEGAL_TEST_IDS.cookieCustomize}\n textColor={colors.text}\n onPress={handleCustomise}\n />\n </View>\n\n {showCustomise ? (\n <View style={styles.customiseSection}>\n <View style={styles.toggleRow}>\n <View>\n <Text style={[styles.toggleLabel, { color: colors.text }]}>{t('cookieConsent.necessaryLabel')}</Text>\n <Text style={[styles.toggleDescription, { color: colors.textSecondary }]}>\n {t('cookieConsent.necessaryDescription')}\n </Text>\n </View>\n <Switch\n disabled\n value\n accessibilityHint={t('cookieConsent.essentialToggleHint')}\n accessibilityLabel={t('cookieConsent.necessaryLabel')}\n testID={LEGAL_TEST_IDS.cookieEssentialToggle}\n trackColor={{ true: primary, false: colors.border }}\n />\n </View>\n\n <View style={styles.toggleRow}>\n <View>\n <Text style={[styles.toggleLabel, { color: colors.text }]}>{t('cookieConsent.analyticsLabel')}</Text>\n <Text style={[styles.toggleDescription, { color: colors.textSecondary }]}>\n {t('cookieConsent.analyticsDescription')}\n </Text>\n </View>\n <Switch\n accessibilityHint={t('cookieConsent.analyticsToggleHint')}\n accessibilityLabel={t('cookieConsent.analyticsLabel')}\n testID={LEGAL_TEST_IDS.cookieAnalyticsToggle}\n trackColor={{ true: primary, false: colors.border }}\n value={analytics}\n onValueChange={setAnalytics}\n />\n </View>\n\n <View style={styles.toggleRow}>\n <View>\n <Text style={[styles.toggleLabel, { color: colors.text }]}>{t('cookieConsent.marketingLabel')}</Text>\n <Text style={[styles.toggleDescription, { color: colors.textSecondary }]}>\n {t('cookieConsent.marketingDescription')}\n </Text>\n </View>\n <Switch\n accessibilityHint={t('cookieConsent.marketingToggleHint')}\n accessibilityLabel={t('cookieConsent.marketingLabel')}\n testID={LEGAL_TEST_IDS.cookieMarketingToggle}\n trackColor={{ true: primary, false: colors.border }}\n value={marketing}\n onValueChange={setMarketing}\n />\n </View>\n\n <ConsentButton\n primary\n a11yHint={t('cookieConsent.savePreferencesHint')}\n label={t('cookieConsent.savePreferences')}\n primaryColor={primary}\n testID={LEGAL_TEST_IDS.cookieSavePreferences}\n textColor={colors.surface}\n onPress={handleSavePreferences}\n />\n </View>\n ) : null}\n\n <Text\n accessibilityHint={t('cookieConsent.privacyLinkHint')}\n accessibilityLabel={t('cookieConsent.privacyPolicyLink')}\n accessibilityRole=\"link\"\n style={[styles.privacyLink, { color: primary }]}\n testID={LEGAL_TEST_IDS.cookiePrivacyLink}\n onPress={handlePrivacyLink}\n >\n {t('cookieConsent.privacyPolicyLink')}\n </Text>\n </View>\n <PrivacyPolicyModal visible={showPrivacy} onClose={handleClosePrivacy} />\n </View>\n );\n};\n\nexport default CookieConsentBanner;\n","/**\n * Terms of Service modal — full-screen scrollable legal text built from translated sections.\n * Content keys live in the consuming app's locale files (legal.termsOfService.*).\n */\nimport React from 'react';\n\nimport { Modal, StyleSheet, View, Text, ScrollView, TouchableOpacity } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\nimport { SvgIcon } from '@dloizides/ui-icons';\n\nimport { LegalSection } from '../LegalSection/LegalSection';\nimport { LEGAL_TEST_IDS } from '../constants';\n\nconst CONTENT_PADDING = 16;\nconst BOTTOM_PADDING = 48;\nconst TITLE_FONT_SIZE = 24;\nconst TITLE_MARGIN_BOTTOM = 4;\nconst UPDATED_FONT_SIZE = 12;\nconst UPDATED_MARGIN_BOTTOM = 16;\nconst CLOSE_BUTTON_PADDING = 6;\nconst CLOSE_BUTTON_BORDER_RADIUS = 6;\nconst CLOSE_ICON_SIZE = 18;\n\nconst DEFAULT_LAST_UPDATED = '2026-03-12';\n\nconst styles = StyleSheet.create({\n container: { flex: 1 },\n scrollContent: { padding: CONTENT_PADDING, paddingBottom: BOTTOM_PADDING },\n headerRow: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n },\n title: { fontSize: TITLE_FONT_SIZE, fontWeight: '700', marginBottom: TITLE_MARGIN_BOTTOM },\n lastUpdated: { fontSize: UPDATED_FONT_SIZE, marginBottom: UPDATED_MARGIN_BOTTOM },\n closeButton: {\n padding: CLOSE_BUTTON_PADDING,\n borderRadius: CLOSE_BUTTON_BORDER_RADIUS,\n },\n});\n\nconst SECTIONS = [\n 'acceptance',\n 'services',\n 'userAccounts',\n 'acceptableUse',\n 'intellectualProperty',\n 'dataPrivacy',\n 'paymentTerms',\n 'limitationOfLiability',\n 'indemnification',\n 'termination',\n 'disputeResolution',\n 'generalProvisions',\n 'contact',\n] as const;\n\nexport interface TermsOfServiceModalProps {\n visible: boolean;\n onClose: () => void;\n /** ISO date shown in the \"last updated\" line. Defaults to the bundled placeholder. */\n lastUpdated?: string;\n}\n\nexport const TermsOfServiceModal = ({\n visible,\n onClose,\n lastUpdated = DEFAULT_LAST_UPDATED,\n}: TermsOfServiceModalProps): React.ReactElement => {\n const { theme, t } = useUi();\n const colors = theme.colors;\n\n return (\n <Modal\n animationType=\"slide\"\n visible={visible}\n onRequestClose={onClose}\n >\n <View style={[styles.container, { backgroundColor: colors.background }]} testID={LEGAL_TEST_IDS.termsOfServiceScreen}>\n <ScrollView\n accessibilityViewIsModal\n aria-label={t('legal.termsOfService.title')}\n contentContainerStyle={styles.scrollContent}\n role=\"dialog\"\n >\n <View style={styles.headerRow}>\n <Text style={[styles.title, { color: colors.text }]}>\n {t('legal.termsOfService.title')}\n </Text>\n <TouchableOpacity\n accessibilityHint={t('common.closeDialogHint')}\n accessibilityLabel={t('common.close')}\n accessibilityRole=\"button\"\n style={styles.closeButton}\n testID={LEGAL_TEST_IDS.termsOfServiceClose}\n onPress={onClose}\n >\n <SvgIcon color={colors.textSecondary} name=\"close\" size={CLOSE_ICON_SIZE} />\n </TouchableOpacity>\n </View>\n <Text style={[styles.lastUpdated, { color: colors.textSecondary }]}>\n {t('legal.termsOfService.lastUpdated', lastUpdated)}\n </Text>\n\n {SECTIONS.map((key) => (\n <LegalSection\n key={key}\n body={t(`legal.termsOfService.${key}.body`)}\n title={t(`legal.termsOfService.${key}.title`)}\n />\n ))}\n </ScrollView>\n </View>\n </Modal>\n );\n};\n\nexport default TermsOfServiceModal;\n"]}
|