@incodetech/prizma-core-screens 0.1.2 → 0.2.3
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/DemoScreensConfigScreen.d.ts +36 -0
- package/dist/DemoScreensConfigScreen.js +30 -0
- package/dist/DemoScreensConfigSheetScreen.d.ts +39 -0
- package/dist/DemoScreensConfigSheetScreen.js +33 -0
- package/dist/DemoScreensEditSheetScreen.d.ts +30 -0
- package/dist/DemoScreensEditSheetScreen.js +28 -0
- package/dist/DemoScreensEndScreen.d.ts +9 -21
- package/dist/DemoScreensEndScreen.js +9 -14
- package/dist/DemoScreensLaunchScreen.d.ts +28 -0
- package/dist/DemoScreensLaunchScreen.js +26 -0
- package/dist/DemoScreensLayout.css +542 -0
- package/dist/DemoScreensRedirectScreen.d.ts +50 -0
- package/dist/DemoScreensRedirectScreen.js +38 -0
- package/dist/DemoScreensResultScreen.d.ts +52 -0
- package/dist/DemoScreensResultScreen.js +46 -0
- package/dist/DemoScreensRunningScreen.d.ts +22 -0
- package/dist/DemoScreensRunningScreen.js +16 -0
- package/dist/DemoScreensSettingsScreen.d.ts +37 -0
- package/dist/DemoScreensSettingsScreen.js +40 -0
- package/dist/DemoScreensSplashScreen.d.ts +27 -0
- package/dist/DemoScreensSplashScreen.js +25 -0
- package/dist/DemoScreensStartScreen.d.ts +38 -0
- package/dist/DemoScreensStartScreen.js +37 -0
- package/dist/DemoScreensStrings.d.ts +192 -0
- package/dist/DemoScreensStrings.js +11 -11
- package/dist/DemoScreensTermsScreen.d.ts +28 -0
- package/dist/DemoScreensTermsScreen.js +26 -0
- package/dist/EkybAddressDetailsScreen.js +9 -5
- package/dist/EkybBusinessDetailsScreen.js +6 -3
- package/dist/EkybOwnersScreen.d.ts +4 -0
- package/dist/EkybOwnersScreen.js +13 -5
- package/dist/EkybStrings.d.ts +12 -1
- package/dist/EkycCountryCatalog.d.ts +46 -0
- package/dist/EkycCountryCatalog.js +139 -0
- package/dist/EkycCountryFormScreen.d.ts +36 -0
- package/dist/EkycCountryFormScreen.js +94 -0
- package/dist/EkycDetailsScreen.js +11 -4
- package/dist/EkycLayout.css +23 -0
- package/dist/EkycLicenseScreen.js +7 -3
- package/dist/EkycStrings.d.ts +26 -0
- package/dist/EmailInputStrings.d.ts +11 -1
- package/dist/FaceMatchComparisonScreen.d.ts +4 -2
- package/dist/FaceMatchComparisonScreen.js +3 -1
- package/dist/FaceMatchLayout.css +53 -3
- package/dist/FormScreen.css +74 -0
- package/dist/FormScreen.d.ts +17 -0
- package/dist/FormScreen.js +12 -1
- package/dist/PhoneInputStrings.d.ts +10 -1
- package/dist/index.d.ts +15 -2
- package/dist/index.js +13 -0
- package/dist/styles.css +1 -0
- package/package.json +62 -1
- package/src/DemoScreensConfigScreen.tsx +101 -0
- package/src/DemoScreensConfigSheetScreen.tsx +120 -0
- package/src/DemoScreensEditSheetScreen.tsx +103 -0
- package/src/DemoScreensEndScreen.tsx +14 -38
- package/src/DemoScreensLaunchScreen.tsx +96 -0
- package/src/DemoScreensLayout.css +542 -0
- package/src/DemoScreensRedirectScreen.tsx +190 -0
- package/src/DemoScreensResultScreen.tsx +115 -0
- package/src/DemoScreensRunningScreen.tsx +45 -0
- package/src/DemoScreensSettingsScreen.tsx +101 -0
- package/src/DemoScreensSplashScreen.tsx +47 -0
- package/src/DemoScreensStartScreen.tsx +105 -0
- package/src/DemoScreensStrings.ts +204 -11
- package/src/DemoScreensTermsScreen.tsx +82 -0
- package/src/EkybAddressDetailsScreen.tsx +7 -1
- package/src/EkybBusinessDetailsScreen.tsx +6 -1
- package/src/EkybOwnersScreen.tsx +46 -2
- package/src/EkybStrings.ts +12 -0
- package/src/EkycCountryCatalog.ts +199 -0
- package/src/EkycCountryFormScreen.tsx +184 -0
- package/src/EkycDetailsScreen.tsx +29 -20
- package/src/EkycLayout.css +23 -0
- package/src/EkycLicenseScreen.tsx +22 -16
- package/src/EkycStrings.ts +25 -0
- package/src/EmailInputStrings.ts +11 -1
- package/src/FaceMatchComparisonScreen.tsx +11 -3
- package/src/FaceMatchLayout.css +53 -3
- package/src/FormScreen.css +74 -0
- package/src/FormScreen.tsx +27 -1
- package/src/PhoneInputStrings.ts +10 -1
- package/src/index.ts +65 -1
- package/src/styles.css +1 -0
|
@@ -1,31 +1,224 @@
|
|
|
1
1
|
// Demo screens — copy contract for the GENERIC family.
|
|
2
2
|
//
|
|
3
|
-
// Figma
|
|
3
|
+
// Figma, two sources:
|
|
4
|
+
// · `Demo App - Latest Design` (FA4ZXKH3meKQnFmDsBsMdk), page "Full flow map",
|
|
5
|
+
// section `Web` (2010:5731) — the flow the Demo App runs in production on
|
|
6
|
+
// the web, phone and desktop: splash → start → (settings) → running →
|
|
7
|
+
// approved / rejected. Traced 2026-09-24.
|
|
8
|
+
// · `Module Generic Screens` (qGJjfL4O0JSjz1x4tOjJn8), frame `63:399`, and the
|
|
9
|
+
// same file's "DemoApp: End Screens" thread — the two end screens that are
|
|
10
|
+
// not a verdict: the result is with a human (`end`), or the flow broke
|
|
11
|
+
// before it reached one (`notCompleted`).
|
|
4
12
|
//
|
|
5
13
|
// The screens that bracket a DEMO session rather than a real one — what a
|
|
6
|
-
// prospect sees
|
|
7
|
-
// definition: the demo does not belong to any module, it strings several of
|
|
14
|
+
// prospect sees before the first module and after the last. They are generic
|
|
15
|
+
// by definition: the demo does not belong to any module, it strings several of
|
|
8
16
|
// them together.
|
|
9
17
|
//
|
|
10
|
-
// ONLY the end screen exists so far. The owner is supplying the start screen
|
|
11
|
-
// separately (Camila 2026-09-03: "that's the end screen but we need the start
|
|
12
|
-
// too, I will add it some other time"), so `start` is deliberately absent from
|
|
13
|
-
// this contract rather than guessed — an invented start screen would be a
|
|
14
|
-
// second source of truth for a frame that already exists in someone's file.
|
|
15
|
-
//
|
|
16
|
-
// The family has no flow of its own. Core Lab lists it as a library of states.
|
|
17
|
-
//
|
|
18
18
|
// No hardcoded English anywhere in a screen: every visible string arrives here.
|
|
19
19
|
|
|
20
|
+
export interface DemoScreensLanguage {
|
|
21
|
+
/** The dropdown option value — a BCP 47 tag (`en-US`, `es-MX`). */
|
|
22
|
+
value: string;
|
|
23
|
+
/** The row label, exactly as the app lists it ("English (US)"). */
|
|
24
|
+
label: string;
|
|
25
|
+
/** ISO 3166-1 alpha-2 code for the canonical flag bank (`US`, `RS`). Absent
|
|
26
|
+
* when the bank has no raster for that country yet — the row then draws
|
|
27
|
+
* no flag rather than an emoji. */
|
|
28
|
+
countryCode?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** One row of a picker: an environment, a flow. */
|
|
32
|
+
export interface DemoScreensOption {
|
|
33
|
+
value: string;
|
|
34
|
+
label: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
20
37
|
export interface DemoScreensStrings {
|
|
21
38
|
/** Accessible name for the logo nav region (i18n — no baked-in English). */
|
|
22
39
|
navLabel?: string;
|
|
23
40
|
/** "verified by" attribution copy for the footer tag. */
|
|
24
41
|
verifiedLabel: string;
|
|
42
|
+
/** The caption under the wordmark on the splash and the start screen. */
|
|
43
|
+
appName: string;
|
|
44
|
+
|
|
45
|
+
/** NATIVE · `Configuration` (2010:4704) — Client ID + Environment before the
|
|
46
|
+
* app knows who you are. `demo_2` empty, `demo_4` filled, `demo_3` custom
|
|
47
|
+
* URL, `Error Client ID` (2116:10697). */
|
|
48
|
+
config: {
|
|
49
|
+
clientIdLabel: string;
|
|
50
|
+
clientIdPlaceholder: string;
|
|
51
|
+
/** The value the filled states show. */
|
|
52
|
+
clientIdValue: string;
|
|
53
|
+
/** Error line under a Client ID the backend rejected. */
|
|
54
|
+
clientIdError: string;
|
|
55
|
+
environmentLabel: string;
|
|
56
|
+
environmentPlaceholder: string;
|
|
57
|
+
environments: DemoScreensOption[];
|
|
58
|
+
/** The environment whose choice reveals the URL field. */
|
|
59
|
+
customEnvironment: string;
|
|
60
|
+
urlLabel: string;
|
|
61
|
+
urlValue: string;
|
|
62
|
+
ctaLabel: string;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/** NATIVE · `Accept Terms` (2010:4923 · 4012:8731) — two documents, each
|
|
66
|
+
* with its consent checkbox. */
|
|
67
|
+
terms: {
|
|
68
|
+
/** "Last Modified: August 5, 2024" — the line under the logo. */
|
|
69
|
+
lastModified: string;
|
|
70
|
+
documents: Record<'terms' | 'privacy', { consentLabel: string; body: string }>;
|
|
71
|
+
ctaLabel: string;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** NATIVE · `Launch screen` (2010:5024) · `Loading` (2082:8004) — the app
|
|
75
|
+
* is configured; one CTA runs the flow. */
|
|
76
|
+
launch: {
|
|
77
|
+
/** "Flow: Digital ID Flow" — the header's left text. */
|
|
78
|
+
flowLabel: string;
|
|
79
|
+
menuLabel: string;
|
|
80
|
+
ctaLabel: string;
|
|
81
|
+
/** "Environment:" — the caption under the CTA … */
|
|
82
|
+
environmentCaption: string;
|
|
83
|
+
/** … and its highlighted value ("Stage"). */
|
|
84
|
+
environmentValue: string;
|
|
85
|
+
/** Snackbar after the configuration sheet saved ("Flow saved"). */
|
|
86
|
+
savedSnackbar: string;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/** NATIVE · `Configuration › Demo config screen` (2118:20999) — the sheet
|
|
90
|
+
* the menu opens: pick a flow, or go edit Client ID / Environment. */
|
|
91
|
+
configSheet: {
|
|
92
|
+
title: string;
|
|
93
|
+
subtitle: string;
|
|
94
|
+
closeLabel: string;
|
|
95
|
+
flowLabel: string;
|
|
96
|
+
/** The flow shown before any change ("Build Predefined"). */
|
|
97
|
+
flowValue: string;
|
|
98
|
+
/** The flow the `selected` state shows ("uxv2"). */
|
|
99
|
+
flowSelected: string;
|
|
100
|
+
flows: DemoScreensOption[];
|
|
101
|
+
searchPlaceholder: string;
|
|
102
|
+
clearSearchLabel: string;
|
|
103
|
+
/** The two read-only lines under the picker. */
|
|
104
|
+
clientIdLine: string;
|
|
105
|
+
environmentLine: string;
|
|
106
|
+
saveLabel: string;
|
|
107
|
+
editLinkLabel: string;
|
|
108
|
+
/** "Build: 2020" — the caption at the foot of both sheets. */
|
|
109
|
+
buildLabel: string;
|
|
110
|
+
savedSnackbar: string;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/** NATIVE · `Edit Client ID or Environment` (2118:21000 …) — the second
|
|
114
|
+
* sheet, reached from the first. */
|
|
115
|
+
editSheet: {
|
|
116
|
+
title: string;
|
|
117
|
+
subtitle: string;
|
|
118
|
+
backLabel: string;
|
|
119
|
+
closeLabel: string;
|
|
120
|
+
clientIdLabel: string;
|
|
121
|
+
clientIdValue: string;
|
|
122
|
+
clientIdError: string;
|
|
123
|
+
environmentLabel: string;
|
|
124
|
+
/** The environment shown before any change ("Kubernetes Stage"). */
|
|
125
|
+
environmentValue: string;
|
|
126
|
+
/** The environment the `filled` state shows ("Demo"). */
|
|
127
|
+
environmentSelected: string;
|
|
128
|
+
environments: DemoScreensOption[];
|
|
129
|
+
ctaLabel: string;
|
|
130
|
+
buildLabel: string;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/** DESKTOP · `Redirect` (4272:11166) — the browser page that hands the
|
|
134
|
+
* session to a phone: a QR, or a link by SMS, or carry on right here. */
|
|
135
|
+
redirect: {
|
|
136
|
+
title: string;
|
|
137
|
+
/** Under the title when both QR and SMS are offered. */
|
|
138
|
+
subtitle: string;
|
|
139
|
+
/** Under the title when only the QR is offered, with the desktop option … */
|
|
140
|
+
subtitleQrDesktop: string;
|
|
141
|
+
/** … and without it. */
|
|
142
|
+
subtitleQrOnly: string;
|
|
143
|
+
tabs: { qr: string; sms: string };
|
|
144
|
+
/** "Scan the QR code to verify on your mobile device." */
|
|
145
|
+
qrHint: string;
|
|
146
|
+
/** "Enter your phone number to receive a link to verify via SMS" */
|
|
147
|
+
smsHint: string;
|
|
148
|
+
phoneLabel: string;
|
|
149
|
+
phonePlaceholder: string;
|
|
150
|
+
/** The typed number the filled state shows. */
|
|
151
|
+
phoneValue: string;
|
|
152
|
+
/** ISO code of the country the picker opens on (`RS`). */
|
|
153
|
+
countryCode: string;
|
|
154
|
+
sendLabel: string;
|
|
155
|
+
/** "or" — between the phone leg and the desktop option. */
|
|
156
|
+
orLabel: string;
|
|
157
|
+
desktopLabel: string;
|
|
158
|
+
sent: {
|
|
159
|
+
title: string;
|
|
160
|
+
/** "To" — followed by the dial code and number. */
|
|
161
|
+
toPrefix: string;
|
|
162
|
+
/** "Resend in 30s" — the countdown state. */
|
|
163
|
+
resendIn: string;
|
|
164
|
+
/** "Resend" — once the countdown is over. */
|
|
165
|
+
resend: string;
|
|
166
|
+
changeLabel: string;
|
|
167
|
+
resentSnackbar: string;
|
|
168
|
+
};
|
|
169
|
+
tooMany: {
|
|
170
|
+
title: string;
|
|
171
|
+
subtitle: string;
|
|
172
|
+
changeLabel: string;
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/** WEB · `demo_2` — the front door: language, the wordmark, one CTA. */
|
|
177
|
+
start: {
|
|
178
|
+
/** Small label over the current language, top left. */
|
|
179
|
+
languageLabel: string;
|
|
180
|
+
/** The current language as the front door shows it ("English (US)"). */
|
|
181
|
+
languageValue: string;
|
|
182
|
+
/** Accessible name for the menu affordance, top right. */
|
|
183
|
+
menuLabel: string;
|
|
184
|
+
ctaLabel: string;
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/** `demo_3` … `demo_5` — the settings sheet: one dropdown, Done. */
|
|
188
|
+
settings: {
|
|
189
|
+
title: string;
|
|
190
|
+
closeLabel: string;
|
|
191
|
+
languageLabel: string;
|
|
192
|
+
languages: DemoScreensLanguage[];
|
|
193
|
+
searchPlaceholder: string;
|
|
194
|
+
clearSearchLabel: string;
|
|
195
|
+
ctaLabel: string;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/** `demo_6` — the wait while the session is scored. */
|
|
199
|
+
running: {
|
|
200
|
+
title: string;
|
|
201
|
+
subtitle?: string;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/** `demo_7` / `demo_8` — the two verdicts the production app renders. */
|
|
205
|
+
result: {
|
|
206
|
+
approved: { title: string; subtitle?: string };
|
|
207
|
+
rejected: { title: string; subtitle?: string };
|
|
208
|
+
/** The CTA under a verdict ("Restart onboarding"). */
|
|
209
|
+
restartLabel: string;
|
|
210
|
+
};
|
|
25
211
|
|
|
26
212
|
/** `63:399` — the demo is over and the result is with a human. */
|
|
27
213
|
end: {
|
|
28
214
|
title: string;
|
|
29
215
|
subtitle?: string;
|
|
30
216
|
};
|
|
217
|
+
|
|
218
|
+
/** "DemoApp: End Screens" · `Processnotcompleted` — the flow broke before a
|
|
219
|
+
* verdict; the app currently shows this title over the error's message. */
|
|
220
|
+
notCompleted: {
|
|
221
|
+
title: string;
|
|
222
|
+
subtitle?: string;
|
|
223
|
+
};
|
|
31
224
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import { PrizmaButton } from '@incodetech/prizma-core-web/button';
|
|
3
|
+
import { PrizmaCheckbox } from '@incodetech/prizma-core-web/checkbox';
|
|
4
|
+
import { PrizmaLogo } from '@incodetech/prizma-core-web/logo';
|
|
5
|
+
import { PrizmaScreenShell, type PrizmaScreenShellProps } from './ScreenShell';
|
|
6
|
+
import type { PrizmaScreenActionHandler } from './types';
|
|
7
|
+
import type { DemoScreensStrings } from './DemoScreensStrings';
|
|
8
|
+
import './ScreenLayout.css';
|
|
9
|
+
import './DemoScreensLayout.css';
|
|
10
|
+
|
|
11
|
+
export interface DemoScreensTermsScreenProps
|
|
12
|
+
extends Omit<PrizmaScreenShellProps, 'dark' | 'title' | 'children'> {
|
|
13
|
+
/** Family copy — this screen reads the `terms` slice. */
|
|
14
|
+
strings: DemoScreensStrings;
|
|
15
|
+
/** Which document is on screen. Default `terms`. */
|
|
16
|
+
document?: 'terms' | 'privacy';
|
|
17
|
+
/** The consent box is ticked and Continue is live. */
|
|
18
|
+
accepted?: boolean;
|
|
19
|
+
screenId?: string;
|
|
20
|
+
onAction?: PrizmaScreenActionHandler;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Demo screens · NATIVE — `Accept Terms` (2010:4923 · 4012:8731): the logo on
|
|
25
|
+
* the left, the "Last Modified" line, the document scrolling in the middle,
|
|
26
|
+
* and the consent checkbox over the CTA. Two documents, Terms of Use then
|
|
27
|
+
* Privacy Policy, each in an unchecked and a checked state.
|
|
28
|
+
*
|
|
29
|
+
* No archetype has a left-aligned logo or a scrolling document body, so the
|
|
30
|
+
* screen composes Core's Logo, Checkbox and Button over the layout classes.
|
|
31
|
+
* The document text arrives through `strings`, as every other string does.
|
|
32
|
+
*/
|
|
33
|
+
export const DemoScreensTermsScreen = forwardRef<HTMLDivElement, DemoScreensTermsScreenProps>(
|
|
34
|
+
(
|
|
35
|
+
{
|
|
36
|
+
strings,
|
|
37
|
+
document = 'terms',
|
|
38
|
+
accepted = false,
|
|
39
|
+
screenId = `demo-screens-${document}${accepted ? '-accepted' : ''}`,
|
|
40
|
+
onAction,
|
|
41
|
+
...shell
|
|
42
|
+
},
|
|
43
|
+
ref,
|
|
44
|
+
) => {
|
|
45
|
+
const t = strings.terms;
|
|
46
|
+
const doc = t.documents[document];
|
|
47
|
+
return (
|
|
48
|
+
<PrizmaScreenShell ref={ref} data-screen-id={screenId} {...shell}>
|
|
49
|
+
<header className="demo-screens-terms__header" aria-label={strings.navLabel}>
|
|
50
|
+
<PrizmaLogo variant="incode" />
|
|
51
|
+
</header>
|
|
52
|
+
<div className="prizma-screen-layout__content">
|
|
53
|
+
<p className="demo-screens-terms__meta">{t.lastModified}</p>
|
|
54
|
+
<div className="demo-screens-terms__body">{doc.body}</div>
|
|
55
|
+
</div>
|
|
56
|
+
<div className="prizma-screen-layout__band prizma-screen-layout__band--bare demo-screens-band">
|
|
57
|
+
<div className="demo-screens-terms__consent">
|
|
58
|
+
<PrizmaCheckbox
|
|
59
|
+
size="M"
|
|
60
|
+
checked={accepted}
|
|
61
|
+
label={doc.consentLabel}
|
|
62
|
+
onCheckedChange={() => onAction?.({ type: 'secondary', screenId })}
|
|
63
|
+
/>
|
|
64
|
+
</div>
|
|
65
|
+
<div className="prizma-screen-layout__band__ctas">
|
|
66
|
+
<PrizmaButton
|
|
67
|
+
variant="primary"
|
|
68
|
+
size="L"
|
|
69
|
+
disabled={!accepted}
|
|
70
|
+
onClick={() => onAction?.({ type: 'cta', screenId })}
|
|
71
|
+
>
|
|
72
|
+
{t.ctaLabel}
|
|
73
|
+
</PrizmaButton>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</PrizmaScreenShell>
|
|
77
|
+
);
|
|
78
|
+
},
|
|
79
|
+
);
|
|
80
|
+
DemoScreensTermsScreen.displayName = 'DemoScreensTermsScreen';
|
|
81
|
+
|
|
82
|
+
export default DemoScreensTermsScreen;
|
|
@@ -3,7 +3,7 @@ import { PrizmaTextField } from '@incodetech/prizma-core-web/text-field';
|
|
|
3
3
|
import { PrizmaDropdown } from '@incodetech/prizma-core-web/dropdown';
|
|
4
4
|
import { PrizmaButton } from '@incodetech/prizma-core-web/button';
|
|
5
5
|
import { PrizmaStepper } from '@incodetech/prizma-core-web/stepper';
|
|
6
|
-
import { PrizmaFormScreen, type PrizmaFormScreenProps } from './FormScreen';
|
|
6
|
+
import { PrizmaFormScreen, PrizmaFormRow, type PrizmaFormScreenProps } from './FormScreen';
|
|
7
7
|
import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
|
|
8
8
|
import type {
|
|
9
9
|
EkybAddressState,
|
|
@@ -136,6 +136,10 @@ export const EkybAddressDetailsScreen = forwardRef<
|
|
|
136
136
|
screenId={screenId}
|
|
137
137
|
overrides={{ align: overrides?.align ?? 'left', logo: overrides?.logo }}
|
|
138
138
|
onAction={onAction}
|
|
139
|
+
/* Exploration ekyb-desktop: on a wide frame only State + Postal code
|
|
140
|
+
share a row (Figma 6407:43637); the four text fields above span the
|
|
141
|
+
column. On the phone nothing changes. */
|
|
142
|
+
responsive
|
|
139
143
|
{...shell}
|
|
140
144
|
>
|
|
141
145
|
<PrizmaTextField
|
|
@@ -169,6 +173,7 @@ export const EkybAddressDetailsScreen = forwardRef<
|
|
|
169
173
|
autoComplete="off"
|
|
170
174
|
defaultValue={values?.city ?? ''}
|
|
171
175
|
/>
|
|
176
|
+
<PrizmaFormRow>
|
|
172
177
|
<PrizmaDropdown
|
|
173
178
|
label={copy.state.label}
|
|
174
179
|
placeholder={copy.state.placeholder}
|
|
@@ -191,6 +196,7 @@ export const EkybAddressDetailsScreen = forwardRef<
|
|
|
191
196
|
autoComplete="off"
|
|
192
197
|
defaultValue={values?.postalCode ?? ''}
|
|
193
198
|
/>
|
|
199
|
+
</PrizmaFormRow>
|
|
194
200
|
</PrizmaFormScreen>
|
|
195
201
|
);
|
|
196
202
|
},
|
|
@@ -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, type PrizmaFormScreenProps } from './FormScreen';
|
|
5
|
+
import { PrizmaFormScreen, PrizmaFormRow, 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';
|
|
@@ -120,8 +120,12 @@ export const EkybBusinessDetailsScreen = forwardRef<
|
|
|
120
120
|
`align` still wins (#GEO-2). */
|
|
121
121
|
overrides={{ align: overrides?.align ?? 'left', logo: overrides?.logo }}
|
|
122
122
|
onAction={onAction}
|
|
123
|
+
/* Exploration ekyb-desktop: on a tablet or desktop frame the two
|
|
124
|
+
fields share a row; on the phone nothing changes. */
|
|
125
|
+
responsive
|
|
123
126
|
{...shell}
|
|
124
127
|
>
|
|
128
|
+
<PrizmaFormRow>
|
|
125
129
|
<PrizmaTextField
|
|
126
130
|
label={copy.businessName.label}
|
|
127
131
|
placeholder={copy.businessName.placeholder}
|
|
@@ -138,6 +142,7 @@ export const EkybBusinessDetailsScreen = forwardRef<
|
|
|
138
142
|
autoComplete="off"
|
|
139
143
|
defaultValue={values?.taxId ?? ''}
|
|
140
144
|
/>
|
|
145
|
+
</PrizmaFormRow>
|
|
141
146
|
</PrizmaFormScreen>
|
|
142
147
|
);
|
|
143
148
|
},
|
package/src/EkybOwnersScreen.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import { PrizmaTextField } from '@incodetech/prizma-core-web/text-field';
|
|
|
3
3
|
import { PrizmaTitle } from '@incodetech/prizma-core-web/title';
|
|
4
4
|
import { PrizmaButton } from '@incodetech/prizma-core-web/button';
|
|
5
5
|
import { PrizmaStepper } from '@incodetech/prizma-core-web/stepper';
|
|
6
|
-
import { PrizmaFormScreen, type PrizmaFormScreenProps } from './FormScreen';
|
|
6
|
+
import { PrizmaFormScreen, PrizmaFormRow, type PrizmaFormScreenProps } from './FormScreen';
|
|
7
7
|
import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
|
|
8
8
|
import type { EkybOwnersState, EkybOwnersValues, EkybStrings } from './EkybStrings';
|
|
9
9
|
import './ScreenLayout.css';
|
|
@@ -52,6 +52,10 @@ export interface EkybOwnersScreenProps
|
|
|
52
52
|
* - `uboFilled` 5707:49608 — UBO block only, both fields carrying a value
|
|
53
53
|
* - `directorEmpty` 5655:56032 — UBO block + Director block, all four blank
|
|
54
54
|
* - `directorFilled` 5707:49782 — UBO block + Director block, all four filled
|
|
55
|
+
* - `uboAdded` (no frame) — `directorFilled` after "Add another UBO": a
|
|
56
|
+
* second, blank UBO pair under the first with its own "Remove UBO" link,
|
|
57
|
+
* then the same "Add another UBO" link and the Director block. Elena asked
|
|
58
|
+
* for the screen the link leads to (2026-09-24); the frames stop at the link.
|
|
55
59
|
* - `loading` 5663:94390 — `directorFilled` with the submission in
|
|
56
60
|
* flight: every field, both "Add another" links and "Back" go inert, and the
|
|
57
61
|
* spinner rides the CTA, never a field (the Phone Input lesson, #PI-5)
|
|
@@ -106,8 +110,9 @@ export const EkybOwnersScreen = forwardRef<HTMLDivElement, EkybOwnersScreenProps
|
|
|
106
110
|
) => {
|
|
107
111
|
const copy = strings.owners;
|
|
108
112
|
const busy = state === 'loading';
|
|
113
|
+
const secondUbo = state === 'uboAdded';
|
|
109
114
|
const showDirector =
|
|
110
|
-
state === 'directorEmpty' || state === 'directorFilled' || busy;
|
|
115
|
+
state === 'directorEmpty' || state === 'directorFilled' || secondUbo || busy;
|
|
111
116
|
|
|
112
117
|
return (
|
|
113
118
|
<PrizmaFormScreen
|
|
@@ -148,8 +153,12 @@ export const EkybOwnersScreen = forwardRef<HTMLDivElement, EkybOwnersScreenProps
|
|
|
148
153
|
screenId={screenId}
|
|
149
154
|
overrides={{ align: overrides?.align ?? 'left', logo: overrides?.logo }}
|
|
150
155
|
onAction={onAction}
|
|
156
|
+
/* Exploration ekyb-desktop: name + surname share a row per block on a
|
|
157
|
+
wide frame; on the phone nothing changes. */
|
|
158
|
+
responsive
|
|
151
159
|
{...shell}
|
|
152
160
|
>
|
|
161
|
+
<PrizmaFormRow>
|
|
153
162
|
<PrizmaTextField
|
|
154
163
|
label={copy.uboName.label}
|
|
155
164
|
placeholder={copy.uboName.placeholder}
|
|
@@ -167,6 +176,39 @@ export const EkybOwnersScreen = forwardRef<HTMLDivElement, EkybOwnersScreenProps
|
|
|
167
176
|
defaultValue={values?.uboSurname ?? ''}
|
|
168
177
|
disabled={busy}
|
|
169
178
|
/>
|
|
179
|
+
</PrizmaFormRow>
|
|
180
|
+
{secondUbo ? (
|
|
181
|
+
<>
|
|
182
|
+
{/* The second UBO: the same two fields, blank, and the way back. */}
|
|
183
|
+
<PrizmaFormRow>
|
|
184
|
+
<PrizmaTextField
|
|
185
|
+
label={copy.uboName.label}
|
|
186
|
+
placeholder={copy.uboName.placeholder}
|
|
187
|
+
required
|
|
188
|
+
requiredHint={strings.requiredHint}
|
|
189
|
+
autoComplete="off"
|
|
190
|
+
defaultValue={values?.secondUboName ?? ''}
|
|
191
|
+
/>
|
|
192
|
+
<PrizmaTextField
|
|
193
|
+
label={copy.uboSurname.label}
|
|
194
|
+
placeholder={copy.uboSurname.placeholder}
|
|
195
|
+
autoComplete="off"
|
|
196
|
+
defaultValue={values?.secondUboSurname ?? ''}
|
|
197
|
+
/>
|
|
198
|
+
</PrizmaFormRow>
|
|
199
|
+
{copy.removeUboLabel ? (
|
|
200
|
+
<PrizmaButton
|
|
201
|
+
variant="tertiary-link"
|
|
202
|
+
size="L"
|
|
203
|
+
onClick={() =>
|
|
204
|
+
onAction?.({ type: 'tertiary', screenId: `${screenId}-remove-ubo` })
|
|
205
|
+
}
|
|
206
|
+
>
|
|
207
|
+
{copy.removeUboLabel}
|
|
208
|
+
</PrizmaButton>
|
|
209
|
+
) : null}
|
|
210
|
+
</>
|
|
211
|
+
) : null}
|
|
170
212
|
<PrizmaButton
|
|
171
213
|
variant="tertiary-link"
|
|
172
214
|
size="L"
|
|
@@ -192,6 +234,7 @@ export const EkybOwnersScreen = forwardRef<HTMLDivElement, EkybOwnersScreenProps
|
|
|
192
234
|
showSubtitle={Boolean(copy.directorSubtitle)}
|
|
193
235
|
subtitle={copy.directorSubtitle}
|
|
194
236
|
/>
|
|
237
|
+
<PrizmaFormRow>
|
|
195
238
|
<PrizmaTextField
|
|
196
239
|
label={copy.directorName.label}
|
|
197
240
|
placeholder={copy.directorName.placeholder}
|
|
@@ -206,6 +249,7 @@ export const EkybOwnersScreen = forwardRef<HTMLDivElement, EkybOwnersScreenProps
|
|
|
206
249
|
defaultValue={values?.directorSurname ?? ''}
|
|
207
250
|
disabled={busy}
|
|
208
251
|
/>
|
|
252
|
+
</PrizmaFormRow>
|
|
209
253
|
<PrizmaButton
|
|
210
254
|
variant="tertiary-link"
|
|
211
255
|
size="L"
|
package/src/EkybStrings.ts
CHANGED
|
@@ -55,6 +55,10 @@ export type EkybAddressState = 'empty' | 'filled';
|
|
|
55
55
|
* - `directorEmpty` — `eKYB.director.empty` (5655:56032): UBO block plus the
|
|
56
56
|
* Director block, every field blank
|
|
57
57
|
* - `directorFilled`— `eKYB.directorFilled` (5707:49782): all four filled
|
|
58
|
+
* - `uboAdded` — what "Add another UBO" does: a second UBO name + surname
|
|
59
|
+
* pair opens under the first, blank, with a "Remove" link of its own, and the
|
|
60
|
+
* Director block below as before. Not a Figma frame — the frames draw the
|
|
61
|
+
* link and stop there; Elena asked for the screen it leads to (2026-09-24).
|
|
58
62
|
* - `loading` — `eKYB.directorloading` (5663:94390): the submission is in
|
|
59
63
|
* flight, so EVERY field, both "Add another" links and "Back" go inert and
|
|
60
64
|
* the spinner rides the CTA, never a field (the Phone Input lesson,
|
|
@@ -65,6 +69,7 @@ export type EkybOwnersState =
|
|
|
65
69
|
| 'uboFilled'
|
|
66
70
|
| 'directorEmpty'
|
|
67
71
|
| 'directorFilled'
|
|
72
|
+
| 'uboAdded'
|
|
68
73
|
| 'loading';
|
|
69
74
|
|
|
70
75
|
/**
|
|
@@ -106,6 +111,9 @@ export interface EkybAddressValues {
|
|
|
106
111
|
export interface EkybOwnersValues {
|
|
107
112
|
uboName?: string;
|
|
108
113
|
uboSurname?: string;
|
|
114
|
+
/** The second UBO, present only in `uboAdded`. */
|
|
115
|
+
secondUboName?: string;
|
|
116
|
+
secondUboSurname?: string;
|
|
109
117
|
directorName?: string;
|
|
110
118
|
directorSurname?: string;
|
|
111
119
|
}
|
|
@@ -213,6 +221,10 @@ export interface EkybStrings {
|
|
|
213
221
|
uboSurname: EkybFieldStrings;
|
|
214
222
|
/** The tertiary link under the UBO block ("Add another UBO (Optional)"). */
|
|
215
223
|
addUboLabel: string;
|
|
224
|
+
/** The tertiary link under a second UBO's pair ("Remove UBO"), `uboAdded`
|
|
225
|
+
* only. Optional so existing hosts keep compiling; without it the second
|
|
226
|
+
* pair cannot be taken away again. */
|
|
227
|
+
removeUboLabel?: string;
|
|
216
228
|
/** The Director block's own heading + description. Rendered by Core's
|
|
217
229
|
* `PrizmaTitle` inside the field stack; see the screen's docstring and the
|
|
218
230
|
* module's reported deviation about the second heading. */
|