@incodetech/prizma-core-screens 0.2.7 → 0.2.14
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/BiometricConsentScreen.d.ts +95 -0
- package/dist/BiometricConsentScreen.js +91 -0
- package/dist/BiometricConsentStrings.d.ts +84 -0
- package/dist/BiometricConsentStrings.js +31 -0
- package/dist/CaptureScreen.d.ts +13 -0
- package/dist/CaptureScreen.js +2 -2
- package/dist/DemoScreensLayout.css +16 -0
- package/dist/DemoScreensRedirectScreen.d.ts +6 -1
- package/dist/DemoScreensRedirectScreen.js +3 -2
- package/dist/DemoScreensStrings.d.ts +5 -0
- package/dist/DigitalIdDeviceWalletsDocumentSelectionScreen.d.ts +34 -0
- package/dist/DigitalIdDeviceWalletsDocumentSelectionScreen.js +47 -0
- package/dist/DigitalIdDeviceWalletsResultScreen.d.ts +28 -0
- package/dist/DigitalIdDeviceWalletsResultScreen.js +23 -0
- package/dist/DigitalIdDeviceWalletsStrings.d.ts +55 -0
- package/dist/DigitalIdDeviceWalletsStrings.js +19 -0
- package/dist/DigitalIdProvidersDocumentSelectionScreen.d.ts +31 -0
- package/dist/DigitalIdProvidersDocumentSelectionScreen.js +37 -0
- package/dist/DigitalIdProvidersErrorScreen.d.ts +33 -0
- package/dist/DigitalIdProvidersErrorScreen.js +33 -0
- package/dist/DigitalIdProvidersLayout.css +59 -0
- package/dist/DigitalIdProvidersRedirectScreen.d.ts +24 -0
- package/dist/DigitalIdProvidersRedirectScreen.js +18 -0
- package/dist/DigitalIdProvidersStrings.d.ts +72 -0
- package/dist/DigitalIdProvidersStrings.js +15 -0
- package/dist/DigitalIdUploadErrorScreen.d.ts +31 -0
- package/dist/DigitalIdUploadErrorScreen.js +26 -0
- package/dist/DigitalIdUploadFileTooLargeScreen.d.ts +27 -0
- package/dist/DigitalIdUploadFileTooLargeScreen.js +21 -0
- package/dist/DigitalIdUploadReviewScreen.d.ts +57 -0
- package/dist/DigitalIdUploadReviewScreen.js +44 -0
- package/dist/DigitalIdUploadStrings.d.ts +64 -0
- package/dist/DigitalIdUploadStrings.js +19 -0
- package/dist/DigitalIdUploadTutorialScreen.d.ts +28 -0
- package/dist/DigitalIdUploadTutorialScreen.js +23 -0
- package/dist/DocumentCaptureIllustration.d.ts +1 -1
- package/dist/EkybCountryScreen.d.ts +6 -6
- package/dist/EkybCountryScreen.js +20 -7
- package/dist/EkybStrings.d.ts +6 -1
- package/dist/ErrorScreensScreen.d.ts +5 -2
- package/dist/ErrorScreensScreen.js +15 -4
- package/dist/ErrorScreensStrings.d.ts +17 -2
- package/dist/ErrorScreensStrings.js +18 -10
- package/dist/FaceCaptureCapturingScreen.d.ts +63 -0
- package/dist/FaceCaptureCapturingScreen.js +62 -2
- package/dist/FaceCaptureLayout.css +69 -4
- package/dist/FaceCaptureStrings.d.ts +23 -0
- package/dist/FormScreen.css +14 -0
- package/dist/FormScreen.d.ts +28 -0
- package/dist/FormScreen.js +3 -2
- package/dist/IdCaptureLayout.css +165 -2
- package/dist/IdCaptureStageScreen.d.ts +47 -0
- package/dist/IdCaptureStageScreen.js +39 -3
- package/dist/IdCaptureStrings.d.ts +19 -0
- package/dist/ListScreen.d.ts +19 -0
- package/dist/ListScreen.js +7 -2
- package/dist/LoaderScreen.d.ts +7 -5
- package/dist/LoaderScreen.js +7 -5
- package/dist/LoadersStrings.d.ts +18 -5
- package/dist/OcrReviewErrorScreen.d.ts +30 -0
- package/dist/OcrReviewErrorScreen.js +24 -0
- package/dist/OcrReviewLayout.css +24 -0
- package/dist/OcrReviewLoadingScreen.d.ts +25 -0
- package/dist/OcrReviewLoadingScreen.js +19 -0
- package/dist/OcrReviewScreen.d.ts +76 -0
- package/dist/OcrReviewScreen.js +65 -0
- package/dist/OcrReviewStrings.d.ts +47 -0
- package/dist/OcrReviewStrings.js +17 -0
- package/dist/OcrReviewSuccessScreen.d.ts +30 -0
- package/dist/OcrReviewSuccessScreen.js +24 -0
- package/dist/PermissionsAllowScreen.d.ts +8 -11
- package/dist/PermissionsAllowScreen.js +8 -11
- package/dist/PermissionsAskScreen.d.ts +41 -0
- package/dist/PermissionsAskScreen.js +43 -0
- package/dist/PermissionsBrowserStepsScreen.d.ts +9 -2
- package/dist/PermissionsBrowserStepsScreen.js +12 -3
- package/dist/PermissionsLayout.css +47 -0
- package/dist/PermissionsStrings.d.ts +20 -9
- package/dist/PermissionsStrings.js +10 -4
- package/dist/PhoneInputOtpScreen.d.ts +8 -0
- package/dist/PhoneInputOtpScreen.js +26 -19
- package/dist/PhoneInputStrings.d.ts +11 -3
- package/dist/PhoneInputVerifyScreen.js +21 -5
- package/dist/QualifiedSignatureDocumentScreen.d.ts +8 -5
- package/dist/QualifiedSignatureDocumentScreen.js +9 -6
- package/dist/QualifiedSignatureResultScreen.d.ts +16 -13
- package/dist/QualifiedSignatureResultScreen.js +17 -18
- package/dist/QualifiedSignatureStrings.d.ts +11 -4
- package/dist/ResultScreen.d.ts +8 -0
- package/dist/ResultScreen.js +14 -3
- package/dist/ReusabilityCredentialSelectionScreen.d.ts +95 -0
- package/dist/ReusabilityCredentialSelectionScreen.js +94 -0
- package/dist/ReusabilityLayout.css +241 -0
- package/dist/ReusabilityPrivacyPolicyScreen.d.ts +55 -0
- package/dist/ReusabilityPrivacyPolicyScreen.js +44 -0
- package/dist/ReusabilityStrings.d.ts +85 -0
- package/dist/ReusabilityStrings.js +37 -0
- package/dist/ReviewScreen.d.ts +38 -12
- package/dist/ReviewScreen.js +41 -8
- package/dist/ScreenLayout.css +382 -6
- package/dist/VideoSelfieErrorScreen.js +1 -1
- package/dist/VideoSelfieIdCaptureScreen.js +1 -1
- package/dist/VideoSelfieLayout.css +304 -2
- package/dist/VideoSelfieSelfieCaptureScreen.js +1 -1
- package/dist/VideoSelfieSpeakScreen.js +1 -1
- package/dist/VideoSelfieStrings.d.ts +4 -1
- package/dist/VideoSelfieTurnHeadScreen.js +14 -11
- package/dist/VideoSelfieTutorialScreen.d.ts +9 -0
- package/dist/VideoSelfieTutorialScreen.js +10 -1
- package/dist/VideoSelfieWaveScreen.js +1 -1
- package/dist/ViewfinderScreen.css +36 -0
- package/dist/flows.d.ts +8 -0
- package/dist/flows.js +17 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +17 -0
- package/dist/styles.css +4 -0
- package/package.json +94 -3
- package/samples/video-selfie-camera-wide.jpg +0 -0
- package/samples/video-selfie-room-wide.jpg +0 -0
- package/src/BiometricConsentScreen.tsx +192 -0
- package/src/BiometricConsentStrings.ts +119 -0
- package/src/CaptureScreen.tsx +17 -0
- package/src/DemoScreensLayout.css +16 -0
- package/src/DemoScreensRedirectScreen.tsx +14 -6
- package/src/DemoScreensStrings.ts +5 -0
- package/src/DigitalIdDeviceWalletsDocumentSelectionScreen.tsx +108 -0
- package/src/DigitalIdDeviceWalletsResultScreen.tsx +76 -0
- package/src/DigitalIdDeviceWalletsStrings.ts +80 -0
- package/src/DigitalIdProvidersDocumentSelectionScreen.tsx +112 -0
- package/src/DigitalIdProvidersErrorScreen.tsx +104 -0
- package/src/DigitalIdProvidersLayout.css +59 -0
- package/src/DigitalIdProvidersRedirectScreen.tsx +65 -0
- package/src/DigitalIdProvidersStrings.ts +98 -0
- package/src/DigitalIdUploadErrorScreen.tsx +83 -0
- package/src/DigitalIdUploadFileTooLargeScreen.tsx +67 -0
- package/src/DigitalIdUploadReviewScreen.tsx +119 -0
- package/src/DigitalIdUploadStrings.ts +88 -0
- package/src/DigitalIdUploadTutorialScreen.tsx +59 -0
- package/src/DocumentCaptureIllustration.tsx +1 -1
- package/src/EkybCountryScreen.tsx +23 -6
- package/src/EkybStrings.ts +6 -1
- package/src/ErrorScreensScreen.tsx +15 -4
- package/src/ErrorScreensStrings.ts +37 -12
- package/src/FaceCaptureCapturingScreen.tsx +102 -13
- package/src/FaceCaptureLayout.css +69 -4
- package/src/FaceCaptureStrings.ts +24 -0
- package/src/FormScreen.css +14 -0
- package/src/FormScreen.tsx +34 -0
- package/src/IdCaptureLayout.css +165 -2
- package/src/IdCaptureStageScreen.tsx +75 -0
- package/src/IdCaptureStrings.ts +19 -0
- package/src/ListScreen.tsx +48 -9
- package/src/LoaderScreen.tsx +7 -5
- package/src/LoadersStrings.ts +18 -5
- package/src/OcrReviewErrorScreen.tsx +53 -0
- package/src/OcrReviewLayout.css +24 -0
- package/src/OcrReviewLoadingScreen.tsx +48 -0
- package/src/OcrReviewScreen.tsx +190 -0
- package/src/OcrReviewStrings.ts +69 -0
- package/src/OcrReviewSuccessScreen.tsx +52 -0
- package/src/PermissionsAllowScreen.tsx +9 -10
- package/src/PermissionsAskScreen.tsx +105 -0
- package/src/PermissionsBrowserStepsScreen.tsx +11 -3
- package/src/PermissionsLayout.css +47 -0
- package/src/PermissionsStrings.ts +42 -12
- package/src/PhoneInputOtpScreen.tsx +23 -3
- package/src/PhoneInputStrings.ts +11 -3
- package/src/PhoneInputVerifyScreen.tsx +24 -4
- package/src/QualifiedSignatureDocumentScreen.tsx +9 -7
- package/src/QualifiedSignatureResultScreen.tsx +28 -26
- package/src/QualifiedSignatureStrings.ts +11 -4
- package/src/ResultScreen.tsx +33 -2
- package/src/ReusabilityCredentialSelectionScreen.tsx +246 -0
- package/src/ReusabilityLayout.css +241 -0
- package/src/ReusabilityPrivacyPolicyScreen.tsx +109 -0
- package/src/ReusabilityStrings.ts +127 -0
- package/src/ReviewScreen.tsx +96 -27
- package/src/ScreenLayout.css +382 -6
- package/src/VideoSelfieErrorScreen.tsx +1 -1
- package/src/VideoSelfieIdCaptureScreen.tsx +9 -1
- package/src/VideoSelfieLayout.css +304 -2
- package/src/VideoSelfieSelfieCaptureScreen.tsx +9 -1
- package/src/VideoSelfieSpeakScreen.tsx +9 -1
- package/src/VideoSelfieStrings.ts +4 -2
- package/src/VideoSelfieTurnHeadScreen.tsx +25 -14
- package/src/VideoSelfieTutorialScreen.tsx +11 -0
- package/src/VideoSelfieWaveScreen.tsx +9 -1
- package/src/ViewfinderScreen.css +36 -0
- package/src/flows.ts +25 -0
- package/src/index.ts +116 -3
- package/src/styles.css +4 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { PrizmaSnackbar } from '@incodetech/prizma-core-web/snackbar';
|
|
3
3
|
import { PrizmaResultScreen, type PrizmaResultScreenProps } from './ResultScreen';
|
|
4
4
|
import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
|
|
5
5
|
import type {
|
|
@@ -19,6 +19,7 @@ export interface QualifiedSignatureResultScreenProps
|
|
|
19
19
|
| 'disclaimer'
|
|
20
20
|
| 'ctaLabel'
|
|
21
21
|
| 'secondaryCtaLabel'
|
|
22
|
+
| 'progress'
|
|
22
23
|
| 'verifiedLabel'
|
|
23
24
|
| 'navLabel'
|
|
24
25
|
> {
|
|
@@ -26,6 +27,11 @@ export interface QualifiedSignatureResultScreenProps
|
|
|
26
27
|
strings: QualifiedSignatureStrings;
|
|
27
28
|
/** Which verdict section to render. Default `signed`. */
|
|
28
29
|
variant?: QualifiedSignatureResultVariant;
|
|
30
|
+
/** `signed` · `signedPartner` only — draw the "document downloaded" Snackbar,
|
|
31
|
+
* the state after the person pressed the download control. HOST state, like
|
|
32
|
+
* Error screens' `copied`: the host sets it on the `secondary` action and
|
|
33
|
+
* clears it when its own timer runs out. Default `false`. */
|
|
34
|
+
downloaded?: boolean;
|
|
29
35
|
screenId?: string;
|
|
30
36
|
overrides?: PrizmaScreenOverrides;
|
|
31
37
|
onAction?: PrizmaScreenActionHandler;
|
|
@@ -39,8 +45,10 @@ export interface QualifiedSignatureResultScreenProps
|
|
|
39
45
|
* nav → centred status mark + title block → CTA band → anchored tag — and differ
|
|
40
46
|
* in status, copy and which actions exist:
|
|
41
47
|
* - `signed` — `QSign.success` (10196:67485): the positive mark over a
|
|
42
|
-
*
|
|
43
|
-
* underlined link
|
|
48
|
+
* STACKED pair — "Continue" primary above a "Download PDF" OUTLINED
|
|
49
|
+
* secondary. Figma draws the download as an underlined link; it ships as the
|
|
50
|
+
* partner's secondary Button instead (owner call 2026-10-08, "make the
|
|
51
|
+
* generic one look like Namirial"), so both success endings read alike.
|
|
44
52
|
* - `signedPlain` — `QSign.success` (10196:67494): the SAME mark and line
|
|
45
53
|
* with no actions at all, so the band never renders and the screen reads as
|
|
46
54
|
* the pure §6-C verdict.
|
|
@@ -69,16 +77,12 @@ export interface QualifiedSignatureResultScreenProps
|
|
|
69
77
|
* The owner rule settles the split in favour of keeping it (#PI-8, #F-30) so
|
|
70
78
|
* nothing shifts between states.
|
|
71
79
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* tertiary link's position PER ARCHETYPE and F has never declared one — the
|
|
79
|
-
* archetype request is logged instead of a local override. `signedPartner` is
|
|
80
|
-
* unaffected: its download control is a real outlined secondary Button, which
|
|
81
|
-
* the archetype already places correctly.
|
|
80
|
+
* The download confirmation. Pressing "Download PDF" / "Download document"
|
|
81
|
+
* emits `secondary`; the host then sets `downloaded` and the screen raises a
|
|
82
|
+
* success Snackbar ("Document downloaded") in the archetype's `progress` slot,
|
|
83
|
+
* between the nav and the content, the same slot and component Error screens
|
|
84
|
+
* use for "link copied" (owner call 2026-10-08). Dismissal is the host's: the
|
|
85
|
+
* Snackbar is presentational (snackbar.md §9 item 6).
|
|
82
86
|
*/
|
|
83
87
|
export const QualifiedSignatureResultScreen = forwardRef<
|
|
84
88
|
HTMLDivElement,
|
|
@@ -88,6 +92,7 @@ export const QualifiedSignatureResultScreen = forwardRef<
|
|
|
88
92
|
{
|
|
89
93
|
strings,
|
|
90
94
|
variant = 'signed',
|
|
95
|
+
downloaded = false,
|
|
91
96
|
screenId = `qualified-signature-result-${variant}`,
|
|
92
97
|
overrides,
|
|
93
98
|
onAction,
|
|
@@ -113,24 +118,21 @@ export const QualifiedSignatureResultScreen = forwardRef<
|
|
|
113
118
|
status={variant === 'error' || variant === 'errorRetry' ? 'warning' : 'success'}
|
|
114
119
|
title={copy.title}
|
|
115
120
|
subtitle={copy.subtitle}
|
|
121
|
+
progress={
|
|
122
|
+
downloaded && (signedCopy?.downloadLabel || partnerCopy) ? (
|
|
123
|
+
<PrizmaSnackbar state="success" contentResizing="fill">
|
|
124
|
+
{strings.result.downloadedLabel}
|
|
125
|
+
</PrizmaSnackbar>
|
|
126
|
+
) : undefined
|
|
127
|
+
}
|
|
116
128
|
/* "Continue" · "Done" · "Try again" — the archetype's own primary. */
|
|
117
129
|
ctaLabel={signedCopy?.ctaLabel ?? partnerCopy?.ctaLabel ?? retryCopy?.ctaLabel}
|
|
118
|
-
/* The
|
|
119
|
-
|
|
130
|
+
/* The outlined download, below the primary: "Download PDF" on the
|
|
131
|
+
generic ending, "Download document" on the partner's. */
|
|
132
|
+
secondaryCtaLabel={signedCopy?.downloadLabel ?? partnerCopy?.secondaryCtaLabel}
|
|
120
133
|
/* The partner's "Signed by …" row — the band's centred text slot, which
|
|
121
134
|
puts it above the button pair exactly as Figma draws it. */
|
|
122
135
|
disclaimer={partnerCopy?.signedByLabel}
|
|
123
|
-
bandContent={
|
|
124
|
-
signedCopy?.downloadLabel ? (
|
|
125
|
-
<PrizmaButton
|
|
126
|
-
variant="tertiary-link"
|
|
127
|
-
size="L"
|
|
128
|
-
onClick={() => onAction?.({ type: 'secondary', screenId })}
|
|
129
|
-
>
|
|
130
|
-
{signedCopy.downloadLabel}
|
|
131
|
-
</PrizmaButton>
|
|
132
|
-
) : undefined
|
|
133
|
-
}
|
|
134
136
|
verifiedLabel={strings.verifiedLabel}
|
|
135
137
|
navLabel={strings.navLabel}
|
|
136
138
|
screenId={screenId}
|
|
@@ -62,7 +62,8 @@ export type QualifiedSignatureDocumentVariant = 'document' | 'terms';
|
|
|
62
62
|
* The FIVE verdict frames. Both purple parents draw success twice and error
|
|
63
63
|
* twice, and each pair differs in what the signer can do next:
|
|
64
64
|
* - `signed` — `QSign.success` (10196:67485): the positive mark with
|
|
65
|
-
* "Continue"
|
|
65
|
+
* "Continue" primary above a "Download PDF" outlined secondary (was an
|
|
66
|
+
* underlined link in Figma; owner call 2026-10-08, matches the partner)
|
|
66
67
|
* - `signedPlain` — `QSign.success` (10196:67494): the same mark and line
|
|
67
68
|
* with NO actions at all
|
|
68
69
|
* - `signedPartner` — the `x Namirial` parent's own success frame (6086:40135),
|
|
@@ -192,9 +193,11 @@ export interface QualifiedSignatureStrings {
|
|
|
192
193
|
document: { title: string };
|
|
193
194
|
/** QSign.T&C ("Certificate Application Form"), left-aligned in Figma. */
|
|
194
195
|
terms: { title: string };
|
|
195
|
-
/**
|
|
196
|
+
/** The way back on both document screens
|
|
196
197
|
* ("Back") — they are opened from the accept screen, so they carry a way
|
|
197
|
-
* back to it.
|
|
198
|
+
* back to it. It is the label of a full-width SECONDARY button in the CTA
|
|
199
|
+
* band (owner call 2026-10-08, was the nav chevron) and emits
|
|
200
|
+
* `secondary`. Omit it and no way back renders. */
|
|
198
201
|
backLabel?: string;
|
|
199
202
|
};
|
|
200
203
|
|
|
@@ -231,7 +234,8 @@ export interface QualifiedSignatureStrings {
|
|
|
231
234
|
subtitle?: string;
|
|
232
235
|
/** Primary CTA ("Continue"). */
|
|
233
236
|
ctaLabel: string;
|
|
234
|
-
/**
|
|
237
|
+
/** OUTLINED secondary below the primary ("Download PDF"), the same
|
|
238
|
+
* control as the partner's "Download document". Emits `secondary`. */
|
|
235
239
|
downloadLabel?: string;
|
|
236
240
|
};
|
|
237
241
|
/** QSign.success drawn with no actions. */
|
|
@@ -253,6 +257,9 @@ export interface QualifiedSignatureStrings {
|
|
|
253
257
|
* `secondary`. A real Button, not `signed`'s underlined link. */
|
|
254
258
|
secondaryCtaLabel: string;
|
|
255
259
|
};
|
|
260
|
+
/** The success Snackbar raised after either download control was pressed
|
|
261
|
+
* ("Document downloaded"). Shared by `signed` and `signedPartner`. */
|
|
262
|
+
downloadedLabel: string;
|
|
256
263
|
/** QSign.AcceptSign.error ("Something went wrong"). Figma draws no button. */
|
|
257
264
|
error: { title: string; subtitle?: string };
|
|
258
265
|
/** The retry frame ("Signature failed" + "Try again"). */
|
package/src/ResultScreen.tsx
CHANGED
|
@@ -77,6 +77,14 @@ export interface PrizmaResultScreenProps
|
|
|
77
77
|
* job (Face Match's verdict Snackbar). DEVIATIONS #VS-17.
|
|
78
78
|
*/
|
|
79
79
|
linkLabel?: string;
|
|
80
|
+
/**
|
|
81
|
+
* Where the tertiary link sits in the stack. `below` (default) is archetype
|
|
82
|
+
* A's position; `above` puts it over the primary CTA, which is what the
|
|
83
|
+
* permission frames draw ("Quit process" over "Allow permission",
|
|
84
|
+
* DEVIATIONS #GEN-3, #VS-17). The slot those rows escalated: the archetype
|
|
85
|
+
* still owns both positions, a screen only picks one of them.
|
|
86
|
+
*/
|
|
87
|
+
linkPosition?: 'below' | 'above';
|
|
80
88
|
/** "verified by" attribution copy for the footer tag. */
|
|
81
89
|
verifiedLabel: string;
|
|
82
90
|
navLabel?: string;
|
|
@@ -118,6 +126,7 @@ export const PrizmaResultScreen = forwardRef<HTMLDivElement, PrizmaResultScreenP
|
|
|
118
126
|
ctaLabel,
|
|
119
127
|
secondaryCtaLabel,
|
|
120
128
|
linkLabel,
|
|
129
|
+
linkPosition = 'below',
|
|
121
130
|
verifiedLabel,
|
|
122
131
|
navLabel,
|
|
123
132
|
screenId,
|
|
@@ -152,7 +161,20 @@ export const PrizmaResultScreen = forwardRef<HTMLDivElement, PrizmaResultScreenP
|
|
|
152
161
|
{children}
|
|
153
162
|
</div>
|
|
154
163
|
{ctaLabel || secondaryCtaLabel || linkLabel || disclaimer || bandContent ? (
|
|
155
|
-
<div
|
|
164
|
+
<div
|
|
165
|
+
className={[
|
|
166
|
+
'prizma-screen-layout__band',
|
|
167
|
+
'prizma-screen-layout__band--result',
|
|
168
|
+
// No footer tag to reserve `--pcs-footer-space` for — same gap the
|
|
169
|
+
// Review archetype's `--bare` fallback exists for (ScreenLayout.css).
|
|
170
|
+
// Every existing F consumer always shows the tag, so this has never
|
|
171
|
+
// fired before; without it the CTA sits ~40px further from the
|
|
172
|
+
// bottom than Figma's flat Spacing/24 draws.
|
|
173
|
+
!showFooter ? 'prizma-screen-layout__band--bare' : '',
|
|
174
|
+
]
|
|
175
|
+
.filter(Boolean)
|
|
176
|
+
.join(' ')}
|
|
177
|
+
>
|
|
156
178
|
{bandContent ? (
|
|
157
179
|
<div className="prizma-screen-layout__band__content">{bandContent}</div>
|
|
158
180
|
) : null}
|
|
@@ -168,6 +190,15 @@ export const PrizmaResultScreen = forwardRef<HTMLDivElement, PrizmaResultScreenP
|
|
|
168
190
|
2026-08-19, DEVIATIONS #GEO-1). Not a per-screen choice and not
|
|
169
191
|
a prop — a screen never picks its own button order. `row` pairs
|
|
170
192
|
them side by side instead, where the rule does not apply. */}
|
|
193
|
+
{linkLabel && linkPosition === 'above' ? (
|
|
194
|
+
<PrizmaButton
|
|
195
|
+
variant="tertiary-link"
|
|
196
|
+
size="L"
|
|
197
|
+
onClick={() => onAction?.({ type: 'tertiary', screenId })}
|
|
198
|
+
>
|
|
199
|
+
{linkLabel}
|
|
200
|
+
</PrizmaButton>
|
|
201
|
+
) : null}
|
|
171
202
|
{ctaLabel ? (
|
|
172
203
|
<PrizmaButton
|
|
173
204
|
variant="primary"
|
|
@@ -186,7 +217,7 @@ export const PrizmaResultScreen = forwardRef<HTMLDivElement, PrizmaResultScreenP
|
|
|
186
217
|
{secondaryCtaLabel}
|
|
187
218
|
</PrizmaButton>
|
|
188
219
|
) : null}
|
|
189
|
-
{linkLabel ? (
|
|
220
|
+
{linkLabel && linkPosition === 'below' ? (
|
|
190
221
|
<PrizmaButton
|
|
191
222
|
variant="tertiary-link"
|
|
192
223
|
size="L"
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import { PrizmaBottomSheetContent } from '@incodetech/prizma-core-web/bottom-sheet';
|
|
3
|
+
import { PrizmaCountryFlag } from '@incodetech/prizma-core-web/combined';
|
|
4
|
+
import { PrizmaListScreen, type PrizmaListScreenProps } from './ListScreen';
|
|
5
|
+
import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
|
|
6
|
+
import type { ReusableCredential, ReusabilityStrings } from './ReusabilityStrings';
|
|
7
|
+
import './ScreenLayout.css';
|
|
8
|
+
import './ReusabilityLayout.css';
|
|
9
|
+
|
|
10
|
+
/** The sentinel the SDK submits for the capture row (`SCAN_NEW_DOCUMENT`,
|
|
11
|
+
* `identityReuseStateMachine.ts`): `{ accepted: false }`, then ID Capture. */
|
|
12
|
+
export const REUSABILITY_SCAN_NEW = 'scanNew' as const;
|
|
13
|
+
|
|
14
|
+
export type ReusabilitySelection = string | typeof REUSABILITY_SCAN_NEW;
|
|
15
|
+
|
|
16
|
+
export interface ReusabilityCredentialSelectionScreenProps
|
|
17
|
+
extends Omit<
|
|
18
|
+
PrizmaListScreenProps,
|
|
19
|
+
| 'status'
|
|
20
|
+
| 'title'
|
|
21
|
+
| 'subtitle'
|
|
22
|
+
| 'glyph'
|
|
23
|
+
| 'children'
|
|
24
|
+
| 'listAlign'
|
|
25
|
+
| 'scrollList'
|
|
26
|
+
| 'disclaimer'
|
|
27
|
+
| 'ctaLabel'
|
|
28
|
+
| 'secondaryCtaLabel'
|
|
29
|
+
| 'linkLabel'
|
|
30
|
+
| 'secondaryLinkLabel'
|
|
31
|
+
| 'overlay'
|
|
32
|
+
| 'verifiedLabel'
|
|
33
|
+
| 'navLabel'
|
|
34
|
+
> {
|
|
35
|
+
/** Module copy — this screen reads the `selection` and `sharedDetails` slices. */
|
|
36
|
+
strings: ReusabilityStrings;
|
|
37
|
+
/**
|
|
38
|
+
* The documents the network found for this person, best match FIRST — the
|
|
39
|
+
* backend orders them and the first row wears the "Recommended" pill (SDK
|
|
40
|
+
* `recommended={index === 0}`). One or more; the frame draws two
|
|
41
|
+
* (`Multiple documents`) and one (`Single document`).
|
|
42
|
+
*/
|
|
43
|
+
credentials: ReusableCredential[];
|
|
44
|
+
/**
|
|
45
|
+
* "What data will be shared?" was pressed: Core's bottom sheet listing the
|
|
46
|
+
* recipient's data request is presented over the dimmed selection
|
|
47
|
+
* (`shared info`, 7877:68927). Its one button emits `cta` and closes it.
|
|
48
|
+
*/
|
|
49
|
+
sharedDetails?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Fired with the chosen credential's id, or `REUSABILITY_SCAN_NEW` for the
|
|
52
|
+
* capture row; `onAction` still reports the tap as `cta`. Named like ID
|
|
53
|
+
* Capture's `onDocumentSelect` — `onSelect` is a native <div> event the shell
|
|
54
|
+
* already passes through.
|
|
55
|
+
*/
|
|
56
|
+
onCredentialSelect?: (selection: ReusabilitySelection) => void;
|
|
57
|
+
screenId?: string;
|
|
58
|
+
overrides?: PrizmaScreenOverrides;
|
|
59
|
+
onAction?: PrizmaScreenActionHandler;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Reusability (Incode Bridge) — choose the document to reuse, built on the
|
|
64
|
+
* List archetype (GUIDELINES.md §6-G, `PrizmaListScreen`).
|
|
65
|
+
*
|
|
66
|
+
* ONE screen for three of the section's four frames: `Multiple documents`
|
|
67
|
+
* (7877:68816) and `Single document` (7877:68875) are the same skeleton — nav →
|
|
68
|
+
* Title (H2 + H5) → the credential list → "Scan a new document" → two tertiary
|
|
69
|
+
* links → tag — differing only in how many rows the network returned; and
|
|
70
|
+
* `Shared data` (7877:68927) is that screen with Core's bottom sheet presented
|
|
71
|
+
* over it (`sharedDetails`).
|
|
72
|
+
*
|
|
73
|
+
* WHY ARCHETYPE G. The rows ARE the actions — tapping a document advances the
|
|
74
|
+
* session with no confirm step (consent review 2026-09-16: "remove the confirm
|
|
75
|
+
* button: selecting a document advances the user immediately"; the Web SDK's
|
|
76
|
+
* ENG-57939 built exactly that) — so there is no primary CTA, and G is the one
|
|
77
|
+
* archetype whose band may carry links alone. ID Capture's document chooser is
|
|
78
|
+
* the same shape on the same archetype.
|
|
79
|
+
*
|
|
80
|
+
* Six things are deliberate:
|
|
81
|
+
*
|
|
82
|
+
* 1. The rows are composed here from Core's tokens, not from Core's
|
|
83
|
+
* `PrizmaCardListVerificationOptions`. The frame calls them "Verification
|
|
84
|
+
* options card list", but a reusable credential has a different anatomy —
|
|
85
|
+
* type label + status pill, flag + masked number, verified date — and the
|
|
86
|
+
* capture row is one line with a pill. Core ships neither that row nor a
|
|
87
|
+
* plain status pill; both are proposed (DEVIATIONS #RU-1, #RU-2) and the
|
|
88
|
+
* rules live once in `ReusabilityLayout.css`.
|
|
89
|
+
* 2. Every row is a real `<button>` that emits `cta` and names its credential
|
|
90
|
+
* through `onCredentialSelect` — the one-click rule. No radio, no selected
|
|
91
|
+
* state: the frame draws none and the decision was to drop them. The SDK's
|
|
92
|
+
* shipped `role="radio"` + confirm is the generation BEFORE this frame.
|
|
93
|
+
* 3. The first row wears "Recommended", because the backend sorts best match
|
|
94
|
+
* first; the capture row wears "Slowest". The pills are the frame's own
|
|
95
|
+
* fills on Core tokens; their 12px type is the one value Core's scale
|
|
96
|
+
* cannot express (#RU-2).
|
|
97
|
+
* 4. The flag is Core's raster bank (`PrizmaCountryFlag`, 24×18), never the
|
|
98
|
+
* frame's emoji glyph (owner decision 2026-07-12). A country outside the
|
|
99
|
+
* bank falls back to the emoji the host supplies — Core's own fallback rule
|
|
100
|
+
* (#RU-3).
|
|
101
|
+
* 5. The two links ride the archetype's band: "What data will be shared?" in
|
|
102
|
+
* `linkLabel` (emits `secondary`) and "Incode’s Privacy Policy" in the new
|
|
103
|
+
* `secondaryLinkLabel` slot (emits `tertiary`) — two non-primary actions a
|
|
104
|
+
* host must tell apart (#PI-10), so each has its own action. The band's
|
|
105
|
+
* flat Spacing/16 stands between them where the frame's Button group
|
|
106
|
+
* tightens the pair by 8 (#RU-4).
|
|
107
|
+
* 6. The sheet rides the archetype's new `overlay` slot — the same contract E
|
|
108
|
+
* gained for Biometric Consent (#BC-8): the screen owns the scrim and the
|
|
109
|
+
* anchoring (the foundation's `__sheet-scrim` / `__sheet-panel`), Core owns
|
|
110
|
+
* the panel — `PrizmaBottomSheetContent variant="dialog"` with its H1
|
|
111
|
+
* title, H5 subtitle, the bullet list in `body`, and its own Button Group
|
|
112
|
+
* reduced to "Understood". With the sheet up the rows and links are under
|
|
113
|
+
* the scrim and do not report (#RU-5).
|
|
114
|
+
*
|
|
115
|
+
* The nav keeps the logo and draws no close: the frame's top-right ✕ is the
|
|
116
|
+
* SDK page chrome, not a Prizma screen control (GUIDELINES §3; #RU-6).
|
|
117
|
+
*/
|
|
118
|
+
export const ReusabilityCredentialSelectionScreen = forwardRef<
|
|
119
|
+
HTMLDivElement,
|
|
120
|
+
ReusabilityCredentialSelectionScreenProps
|
|
121
|
+
>(
|
|
122
|
+
(
|
|
123
|
+
{
|
|
124
|
+
strings,
|
|
125
|
+
credentials,
|
|
126
|
+
sharedDetails = false,
|
|
127
|
+
onCredentialSelect,
|
|
128
|
+
screenId = sharedDetails
|
|
129
|
+
? 'reusability-shared-details'
|
|
130
|
+
: `reusability-selection-${credentials.length > 1 ? 'multiple' : 'single'}`,
|
|
131
|
+
overrides,
|
|
132
|
+
onAction,
|
|
133
|
+
...shell
|
|
134
|
+
},
|
|
135
|
+
ref,
|
|
136
|
+
) => {
|
|
137
|
+
const { selection, sharedDetails: shared } = strings;
|
|
138
|
+
|
|
139
|
+
const choose = (choice: ReusabilitySelection) => {
|
|
140
|
+
if (sharedDetails) return;
|
|
141
|
+
onCredentialSelect?.(choice);
|
|
142
|
+
onAction?.({ type: 'cta', screenId });
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const sheet = sharedDetails ? (
|
|
146
|
+
<>
|
|
147
|
+
<div className="prizma-screen-layout__sheet-scrim" aria-hidden="true" />
|
|
148
|
+
<div className="prizma-screen-layout__sheet-panel">
|
|
149
|
+
<PrizmaBottomSheetContent
|
|
150
|
+
variant="dialog"
|
|
151
|
+
title={shared.title}
|
|
152
|
+
subtitle={shared.subtitle}
|
|
153
|
+
body={
|
|
154
|
+
<ul className="reusability-shared-list">
|
|
155
|
+
{shared.items.map((item) => (
|
|
156
|
+
<li key={item}>{item}</li>
|
|
157
|
+
))}
|
|
158
|
+
</ul>
|
|
159
|
+
}
|
|
160
|
+
buttonGroupProps={{
|
|
161
|
+
primaryLabel: shared.ctaLabel,
|
|
162
|
+
showSecondary: false,
|
|
163
|
+
onPrimaryClick: () => onAction?.({ type: 'cta', screenId }),
|
|
164
|
+
}}
|
|
165
|
+
/>
|
|
166
|
+
</div>
|
|
167
|
+
</>
|
|
168
|
+
) : undefined;
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<PrizmaListScreen
|
|
172
|
+
ref={ref}
|
|
173
|
+
title={selection.title}
|
|
174
|
+
subtitle={selection.subtitle}
|
|
175
|
+
linkLabel={selection.sharedDataLink}
|
|
176
|
+
secondaryLinkLabel={selection.privacyPolicyLink}
|
|
177
|
+
verifiedLabel={strings.verifiedLabel}
|
|
178
|
+
navLabel={strings.navLabel}
|
|
179
|
+
screenId={screenId}
|
|
180
|
+
overrides={overrides}
|
|
181
|
+
/* With the sheet up, the links are under the scrim and must not
|
|
182
|
+
report: the sheet's "Understood" is the only action. */
|
|
183
|
+
onAction={sharedDetails ? undefined : onAction}
|
|
184
|
+
overlay={sheet}
|
|
185
|
+
{...shell}
|
|
186
|
+
>
|
|
187
|
+
<div className="reusability-credentials" role="group" aria-label={selection.listLabel}>
|
|
188
|
+
<div className="reusability-credentials__group">
|
|
189
|
+
{credentials.map((credential, index) => (
|
|
190
|
+
<button
|
|
191
|
+
key={credential.id}
|
|
192
|
+
type="button"
|
|
193
|
+
className="reusability-credential"
|
|
194
|
+
onClick={() => choose(credential.id)}
|
|
195
|
+
tabIndex={sharedDetails ? -1 : undefined}
|
|
196
|
+
>
|
|
197
|
+
<span className="reusability-credential__head">
|
|
198
|
+
<span className="reusability-credential__type">
|
|
199
|
+
{selection.documentType[credential.documentType]}
|
|
200
|
+
</span>
|
|
201
|
+
{index === 0 ? (
|
|
202
|
+
<span className="reusability-pill reusability-pill--recommended">
|
|
203
|
+
{selection.recommendedTag}
|
|
204
|
+
</span>
|
|
205
|
+
) : null}
|
|
206
|
+
</span>
|
|
207
|
+
<span className="reusability-credential__number">
|
|
208
|
+
<span className="reusability-credential__flag" aria-hidden="true">
|
|
209
|
+
<PrizmaCountryFlag
|
|
210
|
+
country={{
|
|
211
|
+
code: credential.countryCode,
|
|
212
|
+
name: credential.countryCode,
|
|
213
|
+
dialCode: '',
|
|
214
|
+
flag: credential.countryFlag ?? '',
|
|
215
|
+
}}
|
|
216
|
+
/>
|
|
217
|
+
</span>
|
|
218
|
+
<span>{credential.maskedNumber}</span>
|
|
219
|
+
</span>
|
|
220
|
+
<span className="reusability-credential__verified">
|
|
221
|
+
<span>{selection.verifiedPrefix}</span> <span>{credential.verifiedOn}</span>
|
|
222
|
+
</span>
|
|
223
|
+
</button>
|
|
224
|
+
))}
|
|
225
|
+
</div>
|
|
226
|
+
<div className="reusability-credentials__group">
|
|
227
|
+
<button
|
|
228
|
+
type="button"
|
|
229
|
+
className="reusability-credential"
|
|
230
|
+
onClick={() => choose(REUSABILITY_SCAN_NEW)}
|
|
231
|
+
tabIndex={sharedDetails ? -1 : undefined}
|
|
232
|
+
>
|
|
233
|
+
<span className="reusability-credential__head">
|
|
234
|
+
<span className="reusability-credential__type">{selection.scanNewLabel}</span>
|
|
235
|
+
<span className="reusability-pill reusability-pill--neutral">{selection.slowestTag}</span>
|
|
236
|
+
</span>
|
|
237
|
+
</button>
|
|
238
|
+
</div>
|
|
239
|
+
</div>
|
|
240
|
+
</PrizmaListScreen>
|
|
241
|
+
);
|
|
242
|
+
},
|
|
243
|
+
);
|
|
244
|
+
ReusabilityCredentialSelectionScreen.displayName = 'ReusabilityCredentialSelectionScreen';
|
|
245
|
+
|
|
246
|
+
export default ReusabilityCredentialSelectionScreen;
|