@incodetech/prizma-core-screens 0.2.4 → 0.2.12
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/CurpEnterScreen.d.ts +7 -0
- package/dist/CurpEnterScreen.js +17 -3
- package/dist/CurpGenerateScreen.d.ts +8 -0
- package/dist/CurpGenerateScreen.js +28 -13
- package/dist/CurpLayout.css +8 -34
- package/dist/CurpStrings.d.ts +16 -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/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/EkybAddressDetailsScreen.d.ts +7 -0
- package/dist/EkybAddressDetailsScreen.js +25 -7
- package/dist/EkybBusinessDetailsScreen.d.ts +6 -0
- package/dist/EkybBusinessDetailsScreen.js +23 -6
- package/dist/EkybCountryScreen.d.ts +13 -5
- package/dist/EkybCountryScreen.js +41 -10
- package/dist/EkybOwnersScreen.d.ts +8 -0
- package/dist/EkybOwnersScreen.js +26 -3
- package/dist/EkybStrings.d.ts +32 -10
- package/dist/EkycCountryCatalog.d.ts +4 -1
- package/dist/EkycCountryCatalog.js +5 -3
- package/dist/EkycCountryFormScreen.d.ts +12 -3
- package/dist/EkycCountryFormScreen.js +28 -10
- package/dist/EkycDetailsScreen.d.ts +7 -0
- package/dist/EkycDetailsScreen.js +21 -4
- package/dist/EkycStrings.d.ts +14 -2
- package/dist/ElectronicSignatureLayout.css +6 -0
- package/dist/EmailInputStrings.d.ts +11 -1
- package/dist/EmailInputVerifyScreen.d.ts +7 -0
- package/dist/EmailInputVerifyScreen.js +17 -3
- 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/FaceMatchComparisonScreen.d.ts +3 -3
- package/dist/FaceMatchLayout.css +21 -12
- package/dist/FormScreen.css +30 -0
- package/dist/FormScreen.d.ts +28 -0
- package/dist/FormScreen.js +3 -2
- package/dist/FormsLongFormScreen.d.ts +8 -0
- package/dist/FormsLongFormScreen.js +34 -13
- package/dist/FormsStrings.d.ts +11 -1
- package/dist/GeolocationBrowserStepsScreen.d.ts +6 -2
- package/dist/GeolocationBrowserStepsScreen.js +7 -3
- package/dist/GeolocationStrings.d.ts +3 -0
- package/dist/IdCaptureLayout.css +205 -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 +21 -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/PhoneInputLayout.css +10 -9
- package/dist/PhoneInputOtpScreen.d.ts +8 -0
- package/dist/PhoneInputOtpScreen.js +26 -19
- package/dist/PhoneInputStrings.d.ts +22 -4
- package/dist/PhoneInputVerifyScreen.d.ts +8 -0
- package/dist/PhoneInputVerifyScreen.js +36 -7
- package/dist/QualifiedSignatureAcceptScreen.js +6 -1
- package/dist/QualifiedSignatureDocumentScreen.d.ts +17 -10
- package/dist/QualifiedSignatureDocumentScreen.js +22 -17
- package/dist/QualifiedSignatureLayout.css +76 -0
- package/dist/QualifiedSignatureResultScreen.d.ts +16 -13
- package/dist/QualifiedSignatureResultScreen.js +17 -18
- package/dist/QualifiedSignatureStrings.d.ts +19 -2
- 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/ScreenNav.css +8 -0
- package/dist/ScreenNav.d.ts +15 -2
- package/dist/ScreenNav.js +10 -3
- package/dist/VideoSelfieErrorScreen.js +1 -1
- package/dist/VideoSelfieIdCaptureScreen.d.ts +10 -3
- package/dist/VideoSelfieIdCaptureScreen.js +45 -14
- package/dist/VideoSelfieLayout.css +467 -34
- package/dist/VideoSelfieSelfieCaptureScreen.d.ts +44 -27
- package/dist/VideoSelfieSelfieCaptureScreen.js +65 -39
- package/dist/VideoSelfieSpeakScreen.js +19 -2
- package/dist/VideoSelfieStrings.d.ts +82 -13
- package/dist/VideoSelfieTurnHeadScreen.d.ts +51 -0
- package/dist/VideoSelfieTurnHeadScreen.js +66 -0
- package/dist/VideoSelfieTutorialScreen.d.ts +9 -0
- package/dist/VideoSelfieTutorialScreen.js +22 -5
- package/dist/VideoSelfieWaveScreen.d.ts +53 -0
- package/dist/VideoSelfieWaveScreen.js +62 -0
- package/dist/ViewfinderScreen.css +36 -0
- package/dist/WatchlistBusinessFormScreen.d.ts +11 -7
- package/dist/WatchlistBusinessFormScreen.js +27 -13
- package/dist/WatchlistBusinessStrings.d.ts +21 -7
- package/dist/flows.d.ts +8 -0
- package/dist/flows.js +17 -0
- package/dist/index.d.ts +19 -1
- package/dist/index.js +14 -0
- package/dist/styles.css +3 -0
- package/dist/types.d.ts +3 -1
- package/package.json +79 -3
- package/samples/video-selfie-camera-wide.jpg +0 -0
- package/samples/video-selfie-room-wide.jpg +0 -0
- package/samples/video-selfie-room.png +0 -0
- package/src/BiometricConsentScreen.tsx +192 -0
- package/src/BiometricConsentStrings.ts +119 -0
- package/src/CaptureScreen.tsx +17 -0
- package/src/CurpEnterScreen.tsx +21 -4
- package/src/CurpGenerateScreen.tsx +46 -22
- package/src/CurpLayout.css +8 -34
- package/src/CurpStrings.ts +22 -2
- package/src/DemoScreensLayout.css +16 -0
- package/src/DemoScreensRedirectScreen.tsx +14 -6
- package/src/DemoScreensStrings.ts +5 -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/EkybAddressDetailsScreen.tsx +32 -4
- package/src/EkybBusinessDetailsScreen.tsx +23 -5
- package/src/EkybCountryScreen.tsx +45 -7
- package/src/EkybOwnersScreen.tsx +34 -3
- package/src/EkybStrings.ts +34 -10
- package/src/EkycCountryCatalog.ts +9 -4
- package/src/EkycCountryFormScreen.tsx +51 -12
- package/src/EkycDetailsScreen.tsx +22 -1
- package/src/EkycStrings.ts +14 -2
- package/src/ElectronicSignatureLayout.css +6 -0
- package/src/EmailInputStrings.ts +12 -1
- package/src/EmailInputVerifyScreen.tsx +21 -4
- 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/FaceMatchComparisonScreen.tsx +3 -3
- package/src/FaceMatchLayout.css +21 -12
- package/src/FormScreen.css +30 -0
- package/src/FormScreen.tsx +34 -0
- package/src/FormsLongFormScreen.tsx +41 -13
- package/src/FormsStrings.ts +12 -1
- package/src/GeolocationBrowserStepsScreen.tsx +6 -3
- package/src/GeolocationStrings.ts +3 -0
- package/src/IdCaptureLayout.css +205 -2
- package/src/IdCaptureStageScreen.tsx +75 -0
- package/src/IdCaptureStrings.ts +19 -0
- package/src/ListScreen.tsx +58 -10
- 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/PhoneInputLayout.css +10 -9
- package/src/PhoneInputOtpScreen.tsx +23 -3
- package/src/PhoneInputStrings.ts +23 -4
- package/src/PhoneInputVerifyScreen.tsx +41 -5
- package/src/QualifiedSignatureAcceptScreen.tsx +12 -1
- package/src/QualifiedSignatureDocumentScreen.tsx +31 -19
- package/src/QualifiedSignatureLayout.css +76 -0
- package/src/QualifiedSignatureResultScreen.tsx +28 -26
- package/src/QualifiedSignatureStrings.ts +19 -2
- 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/ScreenNav.css +8 -0
- package/src/ScreenNav.tsx +35 -5
- package/src/VideoSelfieErrorScreen.tsx +1 -1
- package/src/VideoSelfieIdCaptureScreen.tsx +125 -31
- package/src/VideoSelfieLayout.css +467 -34
- package/src/VideoSelfieSelfieCaptureScreen.tsx +110 -57
- package/src/VideoSelfieSpeakScreen.tsx +34 -15
- package/src/VideoSelfieStrings.ts +89 -14
- package/src/VideoSelfieTurnHeadScreen.tsx +162 -0
- package/src/VideoSelfieTutorialScreen.tsx +45 -23
- package/src/VideoSelfieWaveScreen.tsx +143 -0
- package/src/ViewfinderScreen.css +36 -0
- package/src/WatchlistBusinessFormScreen.tsx +35 -16
- package/src/WatchlistBusinessStrings.ts +21 -7
- package/src/flows.ts +25 -0
- package/src/index.ts +88 -3
- package/src/styles.css +3 -0
- package/src/types.ts +3 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Digital ID Upload module — copy contract.
|
|
2
|
+
//
|
|
3
|
+
// Every Digital ID Upload screen receives the SAME `strings:
|
|
4
|
+
// DigitalIdUploadStrings` object (rule: all copy via props, no hardcoded
|
|
5
|
+
// English — GUIDELINES.md §9).
|
|
6
|
+
//
|
|
7
|
+
// Authoritative screens: the "Web Happy Path - Light Mode" purple section of
|
|
8
|
+
// the Upload Digital ID Figma file (wxFsHRvllern4VnjRqM4JO, node 25351:14721)
|
|
9
|
+
// — covers `tutorial` and the `review` / `analyzing` / `success` stages of
|
|
10
|
+
// the confirm flow — plus TWO separate `Errors` sections: node 25874:11955
|
|
11
|
+
// (`ID type is not accepted`) and node 26083:3981 (`File Limit Error`, "File
|
|
12
|
+
// is too large"). Three frames of the happy-path section are NOT part of
|
|
13
|
+
// this contract: `1-1-1-how to verify` (a verification-method chooser shared
|
|
14
|
+
// with ID Capture — see IdCaptureDocumentSelectionScreen.tsx, which is one
|
|
15
|
+
// row short of this Figma's version), a native iOS file-browser frame (OS
|
|
16
|
+
// chrome, DEVIATIONS.md #DC-20 precedent), and `1-18-1-id-hold-on` (ID
|
|
17
|
+
// Capture's own server-side-wait screen — dropped from this module by
|
|
18
|
+
// product decision, not a gap to fill).
|
|
19
|
+
|
|
20
|
+
/** The three stages the confirm flow's screen shares — matches
|
|
21
|
+
* `PrizmaReviewScreen`'s own `PrizmaReviewStage` (ReviewScreen.tsx). Kept as
|
|
22
|
+
* a separate module-scoped type rather than importing it, same convention as
|
|
23
|
+
* `DocumentCaptureConfirmStage` (DocumentCaptureStrings.ts). */
|
|
24
|
+
export type DigitalIdUploadConfirmStage = 'review' | 'analyzing' | 'success';
|
|
25
|
+
|
|
26
|
+
export interface DigitalIdUploadStrings {
|
|
27
|
+
/** Accessible name for the logo nav region (i18n — no baked-in English). */
|
|
28
|
+
navLabel?: string;
|
|
29
|
+
/** "verified by" attribution copy for the footer tag. */
|
|
30
|
+
verifiedLabel: string;
|
|
31
|
+
|
|
32
|
+
/** `Tutorial Screen` (node 25351:14722). */
|
|
33
|
+
tutorial: {
|
|
34
|
+
title: string;
|
|
35
|
+
subtitle?: string;
|
|
36
|
+
/** "Upload PDF" */
|
|
37
|
+
ctaLabel: string;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/** `Review Document` / `Analyzing` / `Success` (nodes
|
|
41
|
+
* 25351:14725/14726/14727) — one screen, three stages. */
|
|
42
|
+
review: {
|
|
43
|
+
/** `review` title ("Review document"). */
|
|
44
|
+
title: string;
|
|
45
|
+
/** `review` description. Figma draws no subtitle on `analyzing` or
|
|
46
|
+
* `success` — the shared `PrizmaReviewScreen` archetype already only
|
|
47
|
+
* shows one on `review`, so this needs no per-stage handling here. */
|
|
48
|
+
subtitle?: string;
|
|
49
|
+
/** Loading-bar caption on `analyzing` ("Analyzing.."). */
|
|
50
|
+
analyzingLabel: string;
|
|
51
|
+
/** H2 on `success` ("Successfully processed!"). */
|
|
52
|
+
successTitle: string;
|
|
53
|
+
/** Secondary CTA on `review` ("Replace file"). */
|
|
54
|
+
replaceLabel: string;
|
|
55
|
+
/** Primary CTA on `review` / `success` ("Continue"). */
|
|
56
|
+
ctaLabel: string;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/** `Errors` section, `Error` frame (node 25874:11957) — the uploaded file
|
|
60
|
+
* itself was rejected (wrong document type). Built on the SAME
|
|
61
|
+
* `PrizmaReviewScreen` archetype as `review`, stage `"error"`: the card
|
|
62
|
+
* reuses `PrizmaCaptureDigitalId state="error"` (red 4px border), not a
|
|
63
|
+
* generic archetype-F verdict screen (DigitalIdUploadErrorScreen.tsx). */
|
|
64
|
+
error: {
|
|
65
|
+
/** "ID type is not accepted" */
|
|
66
|
+
title: string;
|
|
67
|
+
/** "Please try scanning a different document" */
|
|
68
|
+
subtitle?: string;
|
|
69
|
+
/** "Scan your ID" */
|
|
70
|
+
ctaLabel: string;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/** `Errors` section, `File Limit Error` frame (node 26083:3981) — the file
|
|
74
|
+
* was never uploaded at all (client-side size check), so there is no
|
|
75
|
+
* rejected document to show. Built on Archetype F (`PrizmaResultScreen`,
|
|
76
|
+
* ResultScreen.tsx) rather than the review archetype `error` uses above —
|
|
77
|
+
* Figma centres the status + title + subtitle in the full available
|
|
78
|
+
* height with no media stage at all, exactly F's shape, not H's
|
|
79
|
+
* header-above-a-card one (DigitalIdUploadFileTooLargeScreen.tsx). */
|
|
80
|
+
fileTooLarge: {
|
|
81
|
+
/** "File is too large" */
|
|
82
|
+
title: string;
|
|
83
|
+
/** "The selected file is larger than 5 MB, please upload a smaller one" */
|
|
84
|
+
subtitle?: string;
|
|
85
|
+
/** "Choose another file" */
|
|
86
|
+
ctaLabel: string;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import { PrizmaCaptureDigitalId } from '@incodetech/prizma-core-web/capture-digital-id';
|
|
3
|
+
import { PrizmaTutorialScreen, type PrizmaTutorialScreenProps } from './TutorialScreen';
|
|
4
|
+
import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
|
|
5
|
+
import type { DigitalIdUploadStrings } from './DigitalIdUploadStrings';
|
|
6
|
+
import './ScreenLayout.css';
|
|
7
|
+
|
|
8
|
+
export interface DigitalIdUploadTutorialScreenProps
|
|
9
|
+
extends Omit<
|
|
10
|
+
PrizmaTutorialScreenProps,
|
|
11
|
+
'title' | 'subtitle' | 'ctaLabel' | 'illustration' | 'verifiedLabel' | 'navLabel'
|
|
12
|
+
> {
|
|
13
|
+
/** Module copy — this screen reads the `tutorial` slice (+ shared labels). */
|
|
14
|
+
strings: DigitalIdUploadStrings;
|
|
15
|
+
screenId?: string;
|
|
16
|
+
overrides?: PrizmaScreenOverrides;
|
|
17
|
+
onAction?: PrizmaScreenActionHandler;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Digital ID Upload — tutorial, built on the `PrizmaTutorialScreen` archetype
|
|
22
|
+
* (GUIDELINES.md §6-A). Figma: `Upload Digital ID` file
|
|
23
|
+
* (wxFsHRvllern4VnjRqM4JO), "Web Happy Path - Light Mode" section, `Tutorial
|
|
24
|
+
* Screen` (node 25351:14722).
|
|
25
|
+
*
|
|
26
|
+
* The illustration slot is Core's own `PrizmaCaptureDigitalId` in its
|
|
27
|
+
* `tutorial` state — the Figma file names this exact instance "Capture /
|
|
28
|
+
* Digital ID" (node 26161:10686, Figma description: "Incode specific
|
|
29
|
+
* component for Digital ID module experience"), the same managed component
|
|
30
|
+
* already shipped as `core/platforms/web/src/CaptureDigitalId.tsx`. No module
|
|
31
|
+
* illustration is drawn here — the component owns its own tutorial artwork
|
|
32
|
+
* (`PrizmaIllustrationDigitalId`).
|
|
33
|
+
*/
|
|
34
|
+
export const DigitalIdUploadTutorialScreen = forwardRef<
|
|
35
|
+
HTMLDivElement,
|
|
36
|
+
DigitalIdUploadTutorialScreenProps
|
|
37
|
+
>(
|
|
38
|
+
(
|
|
39
|
+
{ strings, screenId = 'digital-id-upload-tutorial', overrides, onAction, ...shell },
|
|
40
|
+
ref,
|
|
41
|
+
) => (
|
|
42
|
+
<PrizmaTutorialScreen
|
|
43
|
+
ref={ref}
|
|
44
|
+
title={strings.tutorial.title}
|
|
45
|
+
subtitle={strings.tutorial.subtitle}
|
|
46
|
+
ctaLabel={strings.tutorial.ctaLabel}
|
|
47
|
+
illustration={<PrizmaCaptureDigitalId state="tutorial" />}
|
|
48
|
+
verifiedLabel={strings.verifiedLabel}
|
|
49
|
+
navLabel={strings.navLabel}
|
|
50
|
+
screenId={screenId}
|
|
51
|
+
overrides={overrides}
|
|
52
|
+
onAction={onAction}
|
|
53
|
+
{...shell}
|
|
54
|
+
/>
|
|
55
|
+
),
|
|
56
|
+
);
|
|
57
|
+
DigitalIdUploadTutorialScreen.displayName = 'DigitalIdUploadTutorialScreen';
|
|
58
|
+
|
|
59
|
+
export default DigitalIdUploadTutorialScreen;
|
|
@@ -7,7 +7,7 @@ import './DocumentCaptureLayout.css';
|
|
|
7
7
|
*
|
|
8
8
|
* WHY IT LIVES IN THE MODULE LAYER: `prizma-core-web` ships
|
|
9
9
|
* `PrizmaIllustrationSelfie`, `…IdTutorial`, `…IdIntro`, `…IdFlip`,
|
|
10
|
-
* `…IdHint`, `…IdFeedback`, `…NfcScan`, `…
|
|
10
|
+
* `…IdHint`, `…IdFeedback`, `…NfcScan`, `…Geolocation`,
|
|
11
11
|
* `…DigitalId` and `…Avatar` — there is NO document / proof-of-address
|
|
12
12
|
* illustration. GUIDELINES.md §10 is the standing asset rule for that gap
|
|
13
13
|
* ("Illustrations…: inline SVG React components (Figma-sourced), tintable via
|
|
@@ -82,6 +82,13 @@ export interface EkybAddressDetailsScreenProps
|
|
|
82
82
|
* segment 2 solid, segment 3 grey) is Core's `PrizmaStepper` at
|
|
83
83
|
* `currentState={2}`, composed into the archetype's `progress` slot. This is
|
|
84
84
|
* step 2 of 3.
|
|
85
|
+
*
|
|
86
|
+
* `emptyError` is Continue pressed with the fields still empty (Elena,
|
|
87
|
+
* 2026-09-30, GUIDELINES §6-E empty-submit rule; precedent `FormsFieldScreen`'s
|
|
88
|
+
* `emptyError`): every field renders empty, the five REQUIRED ones (State
|
|
89
|
+
* included) in Core's `error` state with `requiredError` and no placeholder,
|
|
90
|
+
* Address line 2 unflagged (optional, DEVIATIONS #EKC-6's rule), and Continue
|
|
91
|
+
* disabled. `empty` keeps Continue enabled so the press can happen.
|
|
85
92
|
*/
|
|
86
93
|
export const EkybAddressDetailsScreen = forwardRef<
|
|
87
94
|
HTMLDivElement,
|
|
@@ -91,9 +98,10 @@ export const EkybAddressDetailsScreen = forwardRef<
|
|
|
91
98
|
{
|
|
92
99
|
strings,
|
|
93
100
|
state = 'empty',
|
|
94
|
-
values,
|
|
101
|
+
values: valuesProp,
|
|
95
102
|
states = [],
|
|
96
103
|
screenId = `ekyb-address-${state}`,
|
|
104
|
+
ctaDisabled,
|
|
97
105
|
className,
|
|
98
106
|
overrides,
|
|
99
107
|
onAction,
|
|
@@ -102,6 +110,14 @@ export const EkybAddressDetailsScreen = forwardRef<
|
|
|
102
110
|
ref,
|
|
103
111
|
) => {
|
|
104
112
|
const copy = strings.address;
|
|
113
|
+
const emptyError = state === 'emptyError';
|
|
114
|
+
const values = emptyError ? undefined : valuesProp;
|
|
115
|
+
// Core's own error treatment, spread AFTER each required field's own
|
|
116
|
+
// placeholder so the error state shows none (the `FormsFieldScreen`
|
|
117
|
+
// precedent). Address line 2 never receives it.
|
|
118
|
+
const missing = emptyError
|
|
119
|
+
? { error: true, errorText: strings.requiredError, placeholder: undefined }
|
|
120
|
+
: {};
|
|
105
121
|
|
|
106
122
|
return (
|
|
107
123
|
<PrizmaFormScreen
|
|
@@ -122,6 +138,8 @@ export const EkybAddressDetailsScreen = forwardRef<
|
|
|
122
138
|
title={copy.title}
|
|
123
139
|
subtitle={copy.subtitle}
|
|
124
140
|
ctaLabel={copy.ctaLabel}
|
|
141
|
+
/* Disabled only after the empty submit; `empty` keeps it enabled. */
|
|
142
|
+
ctaDisabled={emptyError || ctaDisabled}
|
|
125
143
|
linkContent={
|
|
126
144
|
<PrizmaButton
|
|
127
145
|
variant="secondary"
|
|
@@ -136,17 +154,20 @@ export const EkybAddressDetailsScreen = forwardRef<
|
|
|
136
154
|
screenId={screenId}
|
|
137
155
|
overrides={{ align: overrides?.align ?? 'left', logo: overrides?.logo }}
|
|
138
156
|
onAction={onAction}
|
|
139
|
-
/* Exploration ekyb-desktop: on a wide frame
|
|
140
|
-
|
|
141
|
-
|
|
157
|
+
/* Exploration ekyb-desktop: on a wide frame the fields pair up in
|
|
158
|
+
three rows, Street + House number, Address line 2 + City (Elena,
|
|
159
|
+
2026-09-28), and State + Postal code (Figma 6407:43637). On the
|
|
160
|
+
phone nothing changes. */
|
|
142
161
|
responsive
|
|
143
162
|
{...shell}
|
|
144
163
|
>
|
|
164
|
+
<PrizmaFormRow>
|
|
145
165
|
<PrizmaTextField
|
|
146
166
|
label={copy.street.label}
|
|
147
167
|
placeholder={copy.street.placeholder}
|
|
148
168
|
required
|
|
149
169
|
requiredHint={strings.requiredHint}
|
|
170
|
+
{...missing}
|
|
150
171
|
autoComplete="off"
|
|
151
172
|
defaultValue={values?.street ?? ''}
|
|
152
173
|
/>
|
|
@@ -155,9 +176,12 @@ export const EkybAddressDetailsScreen = forwardRef<
|
|
|
155
176
|
placeholder={copy.houseNumber.placeholder}
|
|
156
177
|
required
|
|
157
178
|
requiredHint={strings.requiredHint}
|
|
179
|
+
{...missing}
|
|
158
180
|
autoComplete="off"
|
|
159
181
|
defaultValue={values?.houseNumber ?? ''}
|
|
160
182
|
/>
|
|
183
|
+
</PrizmaFormRow>
|
|
184
|
+
<PrizmaFormRow>
|
|
161
185
|
{/* The one field 6340:50731 draws without an asterisk. */}
|
|
162
186
|
<PrizmaTextField
|
|
163
187
|
label={copy.addressLine2.label}
|
|
@@ -170,15 +194,18 @@ export const EkybAddressDetailsScreen = forwardRef<
|
|
|
170
194
|
placeholder={copy.city.placeholder}
|
|
171
195
|
required
|
|
172
196
|
requiredHint={strings.requiredHint}
|
|
197
|
+
{...missing}
|
|
173
198
|
autoComplete="off"
|
|
174
199
|
defaultValue={values?.city ?? ''}
|
|
175
200
|
/>
|
|
201
|
+
</PrizmaFormRow>
|
|
176
202
|
<PrizmaFormRow>
|
|
177
203
|
<PrizmaDropdown
|
|
178
204
|
label={copy.state.label}
|
|
179
205
|
placeholder={copy.state.placeholder}
|
|
180
206
|
required
|
|
181
207
|
requiredHint={strings.requiredHint}
|
|
208
|
+
{...missing}
|
|
182
209
|
options={states}
|
|
183
210
|
/* Both sections draw the placeholder unless the host supplies a
|
|
184
211
|
value — see the docstring note on 6340:38197. */
|
|
@@ -193,6 +220,7 @@ export const EkybAddressDetailsScreen = forwardRef<
|
|
|
193
220
|
placeholder={copy.postalCode.placeholder}
|
|
194
221
|
required
|
|
195
222
|
requiredHint={strings.requiredHint}
|
|
223
|
+
{...missing}
|
|
196
224
|
autoComplete="off"
|
|
197
225
|
defaultValue={values?.postalCode ?? ''}
|
|
198
226
|
/>
|
|
@@ -2,7 +2,7 @@ import React, { forwardRef } from 'react';
|
|
|
2
2
|
import { PrizmaTextField } from '@incodetech/prizma-core-web/text-field';
|
|
3
3
|
import { PrizmaButton } from '@incodetech/prizma-core-web/button';
|
|
4
4
|
import { PrizmaStepper } from '@incodetech/prizma-core-web/stepper';
|
|
5
|
-
import { PrizmaFormScreen,
|
|
5
|
+
import { PrizmaFormScreen, type PrizmaFormScreenProps } from './FormScreen';
|
|
6
6
|
import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
|
|
7
7
|
import type { EkybBusinessState, EkybBusinessValues, EkybStrings } from './EkybStrings';
|
|
8
8
|
import './ScreenLayout.css';
|
|
@@ -69,6 +69,12 @@ export interface EkybBusinessDetailsScreenProps
|
|
|
69
69
|
* bar is at `currentState="Start"`: segment 1 filled, segments 2 and 3 grey,
|
|
70
70
|
* exactly what 5919:68599 renders. Both offsets around it live in
|
|
71
71
|
* `ScreenLayout.css`, never here.
|
|
72
|
+
*
|
|
73
|
+
* `emptyError` is Continue pressed with the fields still empty (Elena,
|
|
74
|
+
* 2026-09-30, GUIDELINES §6-E empty-submit rule; precedent `FormsFieldScreen`'s
|
|
75
|
+
* `emptyError`): both REQUIRED fields render empty in Core's `error` state with
|
|
76
|
+
* `requiredError` under them, and Continue is disabled. `empty` keeps Continue
|
|
77
|
+
* enabled so the press can happen.
|
|
72
78
|
*/
|
|
73
79
|
export const EkybBusinessDetailsScreen = forwardRef<
|
|
74
80
|
HTMLDivElement,
|
|
@@ -78,8 +84,9 @@ export const EkybBusinessDetailsScreen = forwardRef<
|
|
|
78
84
|
{
|
|
79
85
|
strings,
|
|
80
86
|
state = 'empty',
|
|
81
|
-
values,
|
|
87
|
+
values: valuesProp,
|
|
82
88
|
screenId = `ekyb-business-${state}`,
|
|
89
|
+
ctaDisabled,
|
|
83
90
|
overrides,
|
|
84
91
|
onAction,
|
|
85
92
|
...shell
|
|
@@ -87,6 +94,13 @@ export const EkybBusinessDetailsScreen = forwardRef<
|
|
|
87
94
|
ref,
|
|
88
95
|
) => {
|
|
89
96
|
const copy = strings.business;
|
|
97
|
+
const emptyError = state === 'emptyError';
|
|
98
|
+
const values = emptyError ? undefined : valuesProp;
|
|
99
|
+
// Core's own error treatment, spread onto the REQUIRED fields only; the
|
|
100
|
+
// error state shows no placeholder (the `FormsFieldScreen` precedent).
|
|
101
|
+
const missing = emptyError
|
|
102
|
+
? { error: true, errorText: strings.requiredError, placeholder: undefined }
|
|
103
|
+
: {};
|
|
90
104
|
|
|
91
105
|
return (
|
|
92
106
|
<PrizmaFormScreen
|
|
@@ -104,6 +118,8 @@ export const EkybBusinessDetailsScreen = forwardRef<
|
|
|
104
118
|
title={copy.title}
|
|
105
119
|
subtitle={copy.subtitle}
|
|
106
120
|
ctaLabel={copy.ctaLabel}
|
|
121
|
+
/* Disabled only after the empty submit; `empty` keeps it enabled. */
|
|
122
|
+
ctaDisabled={emptyError || ctaDisabled}
|
|
107
123
|
linkContent={
|
|
108
124
|
<PrizmaButton
|
|
109
125
|
variant="secondary"
|
|
@@ -121,16 +137,18 @@ export const EkybBusinessDetailsScreen = forwardRef<
|
|
|
121
137
|
overrides={{ align: overrides?.align ?? 'left', logo: overrides?.logo }}
|
|
122
138
|
onAction={onAction}
|
|
123
139
|
/* Exploration ekyb-desktop: on a tablet or desktop frame the two
|
|
124
|
-
fields
|
|
140
|
+
fields stay on two rows, each spanning the column (Elena,
|
|
141
|
+
2026-09-28); `responsive` still pairs Continue and Back. On the
|
|
142
|
+
phone nothing changes. */
|
|
125
143
|
responsive
|
|
126
144
|
{...shell}
|
|
127
145
|
>
|
|
128
|
-
<PrizmaFormRow>
|
|
129
146
|
<PrizmaTextField
|
|
130
147
|
label={copy.businessName.label}
|
|
131
148
|
placeholder={copy.businessName.placeholder}
|
|
132
149
|
required
|
|
133
150
|
requiredHint={strings.requiredHint}
|
|
151
|
+
{...missing}
|
|
134
152
|
autoComplete="off"
|
|
135
153
|
defaultValue={values?.businessName ?? ''}
|
|
136
154
|
/>
|
|
@@ -139,10 +157,10 @@ export const EkybBusinessDetailsScreen = forwardRef<
|
|
|
139
157
|
placeholder={copy.taxId.placeholder}
|
|
140
158
|
required
|
|
141
159
|
requiredHint={strings.requiredHint}
|
|
160
|
+
{...missing}
|
|
142
161
|
autoComplete="off"
|
|
143
162
|
defaultValue={values?.taxId ?? ''}
|
|
144
163
|
/>
|
|
145
|
-
</PrizmaFormRow>
|
|
146
164
|
</PrizmaFormScreen>
|
|
147
165
|
);
|
|
148
166
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react';
|
|
2
2
|
import { PrizmaDropdown } from '@incodetech/prizma-core-web/dropdown';
|
|
3
|
+
import { PrizmaCountryFlag } from '@incodetech/prizma-core-web/combined';
|
|
3
4
|
import { PrizmaFormScreen, type PrizmaFormScreenProps } from './FormScreen';
|
|
4
5
|
import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
|
|
5
6
|
import type { EkybCountryState, EkybOption, EkybStrings } from './EkybStrings';
|
|
@@ -55,14 +56,22 @@ export interface EkybCountryScreenProps
|
|
|
55
56
|
* live interaction) — the same mechanism Phone Input's `countryCode` and
|
|
56
57
|
* CURP's `Gene.dropdown` sections use. The search bar Figma draws inside the
|
|
57
58
|
* menu is Core's own `searchable`.
|
|
58
|
-
* 3.
|
|
59
|
-
* 5707:54174 draws
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
59
|
+
* 3. Menu rows and the closed field read the same flag + "United States",
|
|
60
|
+
* no dial code. Figma 5707:54174 draws the rows with Phone Input's "+1"
|
|
61
|
+
* prefixes, dropped by the owner (Elena, 2026-09-28) because a country of
|
|
62
|
+
* registration has no phone prefix. The flag is Core's raster in the
|
|
63
|
+
* dropdown's leading slot, not an emoji in the label (Elena, 2026-10-23;
|
|
64
|
+
* #PI-3, the WatchlistBusinessFormScreen precedent).
|
|
63
65
|
*
|
|
64
66
|
* This page is the only eKYB form page with NO "Back" secondary and NO Stepper —
|
|
65
67
|
* it is step 0, before the three-step wizard starts.
|
|
68
|
+
*
|
|
69
|
+
* `emptyError` is Continue pressed with no country chosen (Elena, 2026-09-30,
|
|
70
|
+
* GUIDELINES §6-E empty-submit rule; precedent `FormsFieldScreen`'s
|
|
71
|
+
* `emptyError`): the dropdown renders empty, with no placeholder, in Core's
|
|
72
|
+
* `error` state with `requiredError` under it, and Continue is disabled. The
|
|
73
|
+
* field draws no `*`, but it is the page's only input and the flow cannot go on
|
|
74
|
+
* without it, so it is treated as required. `empty` keeps Continue enabled.
|
|
66
75
|
*/
|
|
67
76
|
export const EkybCountryScreen = forwardRef<HTMLDivElement, EkybCountryScreenProps>(
|
|
68
77
|
(
|
|
@@ -72,6 +81,7 @@ export const EkybCountryScreen = forwardRef<HTMLDivElement, EkybCountryScreenPro
|
|
|
72
81
|
countries = [],
|
|
73
82
|
value,
|
|
74
83
|
screenId = `ekyb-country-${state}`,
|
|
84
|
+
ctaDisabled,
|
|
75
85
|
overrides,
|
|
76
86
|
onAction,
|
|
77
87
|
...shell
|
|
@@ -81,7 +91,9 @@ export const EkybCountryScreen = forwardRef<HTMLDivElement, EkybCountryScreenPro
|
|
|
81
91
|
const copy = strings.country;
|
|
82
92
|
// `empty` is the only section drawn on the placeholder; both other sections
|
|
83
93
|
// draw a chosen country in the closed field.
|
|
84
|
-
const
|
|
94
|
+
const emptyError = state === 'emptyError';
|
|
95
|
+
const selected =
|
|
96
|
+
state === 'empty' || emptyError ? null : (value ?? countries[0]?.value ?? null);
|
|
85
97
|
|
|
86
98
|
return (
|
|
87
99
|
<PrizmaFormScreen
|
|
@@ -89,6 +101,8 @@ export const EkybCountryScreen = forwardRef<HTMLDivElement, EkybCountryScreenPro
|
|
|
89
101
|
title={copy.title}
|
|
90
102
|
subtitle={copy.subtitle}
|
|
91
103
|
ctaLabel={copy.ctaLabel}
|
|
104
|
+
/* Disabled only after the empty submit; `empty` keeps it enabled. */
|
|
105
|
+
ctaDisabled={emptyError || ctaDisabled}
|
|
92
106
|
verifiedLabel={strings.verifiedLabel}
|
|
93
107
|
navLabel={strings.navLabel}
|
|
94
108
|
screenId={screenId}
|
|
@@ -102,7 +116,15 @@ export const EkybCountryScreen = forwardRef<HTMLDivElement, EkybCountryScreenPro
|
|
|
102
116
|
>
|
|
103
117
|
<PrizmaDropdown
|
|
104
118
|
label={copy.field.label}
|
|
105
|
-
|
|
119
|
+
/* Required, but UNMARKED: a single-input screen shows no asterisk
|
|
120
|
+
and no legend (Core pattern "Optimistic submission", single-input
|
|
121
|
+
screens; Elena 2026-09-30). The requirement surfaces on submit,
|
|
122
|
+
through the empty-submit error. */
|
|
123
|
+
/* The error state draws the field with nothing in it, not even the
|
|
124
|
+
placeholder (the `FormsFieldScreen` precedent). */
|
|
125
|
+
placeholder={emptyError ? undefined : copy.field.placeholder}
|
|
126
|
+
error={emptyError}
|
|
127
|
+
errorText={emptyError ? strings.requiredError : undefined}
|
|
106
128
|
options={countries}
|
|
107
129
|
/* Uncontrolled: a screen is one static spec state, so no `onChange` is
|
|
108
130
|
needed. Core's `readOnly`/`disabled` are NOT used to freeze it —
|
|
@@ -114,6 +136,22 @@ export const EkybCountryScreen = forwardRef<HTMLDivElement, EkybCountryScreenPro
|
|
|
114
136
|
clearSearchLabel={copy.clearSearchLabel}
|
|
115
137
|
/* The `dropdown` section IS the open-menu spec state. */
|
|
116
138
|
forceOpen={state === 'dropdown'}
|
|
139
|
+
/* Core's canonical flag raster in the closed field and every menu
|
|
140
|
+
row (see note 3). A country outside the bank falls back to its
|
|
141
|
+
`flag` emoji. */
|
|
142
|
+
renderLeading={(option) => {
|
|
143
|
+
const match = countries.find((c) => c.value === option.value);
|
|
144
|
+
return match ? (
|
|
145
|
+
<PrizmaCountryFlag
|
|
146
|
+
country={{
|
|
147
|
+
code: match.value,
|
|
148
|
+
name: match.label,
|
|
149
|
+
dialCode: '',
|
|
150
|
+
flag: match.flag ?? '',
|
|
151
|
+
}}
|
|
152
|
+
/>
|
|
153
|
+
) : null;
|
|
154
|
+
}}
|
|
117
155
|
/>
|
|
118
156
|
</PrizmaFormScreen>
|
|
119
157
|
);
|
package/src/EkybOwnersScreen.tsx
CHANGED
|
@@ -59,6 +59,14 @@ export interface EkybOwnersScreenProps
|
|
|
59
59
|
* - `loading` 5663:94390 — `directorFilled` with the submission in
|
|
60
60
|
* flight: every field, both "Add another" links and "Back" go inert, and the
|
|
61
61
|
* spinner rides the CTA, never a field (the Phone Input lesson, #PI-5)
|
|
62
|
+
* - `uboEmptyError` / `directorEmptyError` (no frame) — `uboEmpty` /
|
|
63
|
+
* `directorEmpty` after Continue was pressed with the fields still empty
|
|
64
|
+
* (Elena, 2026-09-30, GUIDELINES §6-E empty-submit rule; precedent
|
|
65
|
+
* `FormsFieldScreen`'s `emptyError`): every field renders empty, the two
|
|
66
|
+
* REQUIRED UBO fields in Core's `error` state with `requiredError` and no
|
|
67
|
+
* placeholder, the optional Director fields unflagged, and Continue
|
|
68
|
+
* disabled. The `*Empty` states keep Continue enabled so the press can
|
|
69
|
+
* happen.
|
|
62
70
|
*
|
|
63
71
|
* Four things are deliberate:
|
|
64
72
|
*
|
|
@@ -99,8 +107,9 @@ export const EkybOwnersScreen = forwardRef<HTMLDivElement, EkybOwnersScreenProps
|
|
|
99
107
|
{
|
|
100
108
|
strings,
|
|
101
109
|
state = 'uboEmpty',
|
|
102
|
-
values,
|
|
110
|
+
values: valuesProp,
|
|
103
111
|
screenId = `ekyb-owners-${state}`,
|
|
112
|
+
ctaDisabled,
|
|
104
113
|
className,
|
|
105
114
|
overrides,
|
|
106
115
|
onAction,
|
|
@@ -111,8 +120,20 @@ export const EkybOwnersScreen = forwardRef<HTMLDivElement, EkybOwnersScreenProps
|
|
|
111
120
|
const copy = strings.owners;
|
|
112
121
|
const busy = state === 'loading';
|
|
113
122
|
const secondUbo = state === 'uboAdded';
|
|
123
|
+
const emptyError = state === 'uboEmptyError' || state === 'directorEmptyError';
|
|
124
|
+
const values = emptyError ? undefined : valuesProp;
|
|
114
125
|
const showDirector =
|
|
115
|
-
state === 'directorEmpty' ||
|
|
126
|
+
state === 'directorEmpty' ||
|
|
127
|
+
state === 'directorFilled' ||
|
|
128
|
+
state === 'directorEmptyError' ||
|
|
129
|
+
secondUbo ||
|
|
130
|
+
busy;
|
|
131
|
+
// Core's own error treatment, spread AFTER each required UBO field's own
|
|
132
|
+
// placeholder so the error state shows none (the `FormsFieldScreen`
|
|
133
|
+
// precedent). The Director fields are optional and never receive it.
|
|
134
|
+
const missing = emptyError
|
|
135
|
+
? { error: true, errorText: strings.requiredError, placeholder: undefined }
|
|
136
|
+
: {};
|
|
116
137
|
|
|
117
138
|
return (
|
|
118
139
|
<PrizmaFormScreen
|
|
@@ -134,6 +155,9 @@ export const EkybOwnersScreen = forwardRef<HTMLDivElement, EkybOwnersScreenProps
|
|
|
134
155
|
title={copy.title}
|
|
135
156
|
subtitle={copy.subtitle}
|
|
136
157
|
ctaLabel={copy.ctaLabel}
|
|
158
|
+
/* Disabled only after the empty submit; the `*Empty` states keep it
|
|
159
|
+
enabled. */
|
|
160
|
+
ctaDisabled={emptyError || ctaDisabled}
|
|
137
161
|
/* `loading` swaps the CTA label for Core's designed spinner. */
|
|
138
162
|
ctaLoading={busy}
|
|
139
163
|
ctaLoadingLabel={copy.ctaLoadingLabel}
|
|
@@ -164,14 +188,19 @@ export const EkybOwnersScreen = forwardRef<HTMLDivElement, EkybOwnersScreenProps
|
|
|
164
188
|
placeholder={copy.uboName.placeholder}
|
|
165
189
|
required
|
|
166
190
|
requiredHint={strings.requiredHint}
|
|
191
|
+
{...missing}
|
|
167
192
|
autoComplete="off"
|
|
168
193
|
defaultValue={values?.uboName ?? ''}
|
|
169
194
|
disabled={busy}
|
|
170
195
|
/>
|
|
171
|
-
{/*
|
|
196
|
+
{/* Required since 2026-09-28 (Elena): the frames drew no asterisk on the
|
|
197
|
+
surname, but a beneficial owner needs both names. */}
|
|
172
198
|
<PrizmaTextField
|
|
173
199
|
label={copy.uboSurname.label}
|
|
174
200
|
placeholder={copy.uboSurname.placeholder}
|
|
201
|
+
required
|
|
202
|
+
requiredHint={strings.requiredHint}
|
|
203
|
+
{...missing}
|
|
175
204
|
autoComplete="off"
|
|
176
205
|
defaultValue={values?.uboSurname ?? ''}
|
|
177
206
|
disabled={busy}
|
|
@@ -192,6 +221,8 @@ export const EkybOwnersScreen = forwardRef<HTMLDivElement, EkybOwnersScreenProps
|
|
|
192
221
|
<PrizmaTextField
|
|
193
222
|
label={copy.uboSurname.label}
|
|
194
223
|
placeholder={copy.uboSurname.placeholder}
|
|
224
|
+
required
|
|
225
|
+
requiredHint={strings.requiredHint}
|
|
195
226
|
autoComplete="off"
|
|
196
227
|
defaultValue={values?.secondUboSurname ?? ''}
|
|
197
228
|
/>
|
package/src/EkybStrings.ts
CHANGED
|
@@ -34,15 +34,21 @@
|
|
|
34
34
|
* - `dropdown` — the same selection with the MENU OPEN over the form: search
|
|
35
35
|
* bar plus the country rows (Core's documentation-only `forceOpen`, since a
|
|
36
36
|
* screen is one static spec state and never a live interaction)
|
|
37
|
+
* - `emptyError` — Continue was pressed with no country chosen (GUIDELINES
|
|
38
|
+
* §6-E empty-submit rule, Elena 2026-09-30): the dropdown in Core's error
|
|
39
|
+
* state with `requiredError`, Continue disabled. Not a Figma frame.
|
|
37
40
|
*/
|
|
38
|
-
export type EkybCountryState = 'empty' | 'filled' | 'dropdown';
|
|
41
|
+
export type EkybCountryState = 'empty' | 'filled' | 'dropdown' | 'emptyError';
|
|
39
42
|
|
|
40
43
|
/** The two `eKYB.Bdetails` (business identity) sections: every field on its
|
|
41
|
-
* resting empty surface, or every field carrying a value
|
|
42
|
-
|
|
44
|
+
* resting empty surface, or every field carrying a value — plus `emptyError`,
|
|
45
|
+
* Continue pressed with the fields empty (empty-submit rule, 2026-09-30):
|
|
46
|
+
* every required field in Core's error state, Continue disabled. */
|
|
47
|
+
export type EkybBusinessState = 'empty' | 'filled' | 'emptyError';
|
|
43
48
|
|
|
44
|
-
/** The two address sections (the SECOND `eKYB.Bdetails` parent). Same axis
|
|
45
|
-
|
|
49
|
+
/** The two address sections (the SECOND `eKYB.Bdetails` parent). Same axis,
|
|
50
|
+
* same `emptyError` (the optional Address line 2 shows no error). */
|
|
51
|
+
export type EkybAddressState = 'empty' | 'filled' | 'emptyError';
|
|
46
52
|
|
|
47
53
|
/**
|
|
48
54
|
* The `eKYB.UBO.*` and `eKYB.director.*` sections — one screen family, because
|
|
@@ -63,6 +69,11 @@ export type EkybAddressState = 'empty' | 'filled';
|
|
|
63
69
|
* flight, so EVERY field, both "Add another" links and "Back" go inert and
|
|
64
70
|
* the spinner rides the CTA, never a field (the Phone Input lesson,
|
|
65
71
|
* DEVIATIONS #PI-5)
|
|
72
|
+
* - `uboEmptyError` / `directorEmptyError` — `uboEmpty` / `directorEmpty` after
|
|
73
|
+
* Continue was pressed with the fields empty (GUIDELINES §6-E empty-submit
|
|
74
|
+
* rule, Elena 2026-09-30): the two REQUIRED UBO fields in Core's error state
|
|
75
|
+
* with `requiredError`, the optional Director fields unflagged, Continue
|
|
76
|
+
* disabled. Not Figma frames.
|
|
66
77
|
*/
|
|
67
78
|
export type EkybOwnersState =
|
|
68
79
|
| 'uboEmpty'
|
|
@@ -70,7 +81,9 @@ export type EkybOwnersState =
|
|
|
70
81
|
| 'directorEmpty'
|
|
71
82
|
| 'directorFilled'
|
|
72
83
|
| 'uboAdded'
|
|
73
|
-
| 'loading'
|
|
84
|
+
| 'loading'
|
|
85
|
+
| 'uboEmptyError'
|
|
86
|
+
| 'directorEmptyError';
|
|
74
87
|
|
|
75
88
|
/**
|
|
76
89
|
* One selectable row in the country / state menus. Runtime data, not copy — the
|
|
@@ -84,10 +97,14 @@ export interface EkybOption {
|
|
|
84
97
|
/** The row label as drawn in the open menu. */
|
|
85
98
|
label: string;
|
|
86
99
|
/** Compact face for the CLOSED field when it differs from the menu row —
|
|
87
|
-
* Core's own `PrizmaDropdownOption.fieldLabel`.
|
|
88
|
-
*
|
|
89
|
-
*
|
|
100
|
+
* Core's own `PrizmaDropdownOption.fieldLabel`. The eKYB country list
|
|
101
|
+
* does not need it: rows and field both read "United States" after the
|
|
102
|
+
* flag. */
|
|
90
103
|
fieldLabel?: string;
|
|
104
|
+
/** Country menus only: the emoji fallback for a `value` outside Core's
|
|
105
|
+
* flag raster bank. The country screen draws the bank's flag by `value`,
|
|
106
|
+
* so this never travels inside `label`. */
|
|
107
|
+
flag?: string;
|
|
91
108
|
}
|
|
92
109
|
|
|
93
110
|
/** The values the business-identity page carries. Runtime data, never copy. */
|
|
@@ -139,6 +156,13 @@ export interface EkybStrings {
|
|
|
139
156
|
* localizable and never hardcoded in a screen.
|
|
140
157
|
*/
|
|
141
158
|
requiredHint?: string;
|
|
159
|
+
/**
|
|
160
|
+
* Under every empty REQUIRED field once the primary was pressed with it
|
|
161
|
+
* still empty — the `emptyError` states (GUIDELINES §6-E empty-submit rule,
|
|
162
|
+
* Elena 2026-09-30). Core's own `errorText` slot; SDK key
|
|
163
|
+
* `dynamicForms.fieldRequired`.
|
|
164
|
+
*/
|
|
165
|
+
requiredError: string;
|
|
142
166
|
/** Shared "Back" secondary action drawn under "Continue" on every page except
|
|
143
167
|
* `country`. Emits `secondary`. */
|
|
144
168
|
backLabel: string;
|
|
@@ -217,7 +241,7 @@ export interface EkybStrings {
|
|
|
217
241
|
title: string;
|
|
218
242
|
subtitle?: string;
|
|
219
243
|
uboName: EkybFieldStrings;
|
|
220
|
-
/**
|
|
244
|
+
/** Required, like the name (Elena, 2026-09-28); the frames drew no `*`. */
|
|
221
245
|
uboSurname: EkybFieldStrings;
|
|
222
246
|
/** The tertiary link under the UBO block ("Add another UBO (Optional)"). */
|
|
223
247
|
addUboLabel: string;
|