@myazahq/kyc-sdk-react-native 3.0.0 → 3.1.0
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/package.json +8 -7
- package/src/components/GlassIconButton.tsx +2 -5
- package/src/components/Icon.tsx +17 -14
- package/src/components/KycFlow.tsx +1 -0
- package/src/components/KycSheet.tsx +0 -1
- package/src/components/StepView.tsx +3 -0
- package/src/components/icons/glyphs.ts +35 -0
- package/src/components/icons/index.ts +3 -0
- package/src/components/icons/map.ts +165 -0
- package/src/components/icons/names.ts +86 -0
- package/src/components/stepHeaderMeta.tsx +15 -0
- package/src/config/stepOrder.ts +20 -5
- package/src/config/supportingDocuments.ts +131 -0
- package/src/config/theme.ts +29 -3
- package/src/config/workflowMerge.ts +13 -0
- package/src/lib/supportingDocumentsIntro.ts +35 -0
- package/src/screens/BusinessDocumentSlot.tsx +37 -8
- package/src/screens/SupportingDocumentCard.tsx +134 -0
- package/src/screens/SupportingDocumentsStep.tsx +203 -0
- package/src/screens/consent/model.ts +22 -5
- package/src/screens/liveness/CaptureRing.tsx +31 -17
- package/src/screens/supportingDocumentParts.tsx +126 -0
- package/src/screens/useBusinessDocumentAttach.ts +20 -9
- package/src/services/api-types.ts +3 -0
- package/src/services/deviceMetadata.ts +1 -1
- package/src/store/derive.ts +11 -0
- package/src/store/kycStore.ts +15 -0
- package/src/store/session.ts +18 -0
- package/src/store/state.ts +26 -0
- package/src/store/submit.ts +11 -0
- package/src/types/config.ts +10 -0
- package/src/types/workflow.ts +39 -0
- package/src/components/icon-map.ts +0 -176
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myazahq/kyc-sdk-react-native",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "Myaza KYC SDK for React Native (Expo) — ID verification, liveness detection, and document capture",
|
|
5
5
|
"author": "Flitstack Technologies Inc.",
|
|
6
6
|
"repository": {
|
|
@@ -54,7 +54,6 @@
|
|
|
54
54
|
"expo-document-picker": ">=56",
|
|
55
55
|
"expo-localization": ">=56",
|
|
56
56
|
"expo-task-manager": ">=14",
|
|
57
|
-
"react-native-webview": ">=13",
|
|
58
57
|
"react": ">=19",
|
|
59
58
|
"react-native": ">=0.83",
|
|
60
59
|
"react-native-nitro-image": ">=0.15",
|
|
@@ -62,6 +61,7 @@
|
|
|
62
61
|
"react-native-safe-area-context": ">=4",
|
|
63
62
|
"react-native-svg": ">=15",
|
|
64
63
|
"react-native-vision-camera-worklets": ">=5",
|
|
64
|
+
"react-native-webview": ">=13",
|
|
65
65
|
"react-native-worklets": ">=0.8"
|
|
66
66
|
},
|
|
67
67
|
"peerDependenciesMeta": {
|
|
@@ -85,21 +85,22 @@
|
|
|
85
85
|
}
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
|
+
"@hugeicons/core-free-icons": "4.3.5",
|
|
89
|
+
"@hugeicons/react-native": "1.0.16",
|
|
88
90
|
"country-flag-icons": "^1.6.17",
|
|
89
|
-
"libphonenumber-js": "^1.13.8",
|
|
90
|
-
"expo-crypto": "~56.0.4",
|
|
91
91
|
"expo-clipboard": "~56.0.0",
|
|
92
|
+
"expo-crypto": "~56.0.4",
|
|
93
|
+
"expo-file-system": "~56.0.0",
|
|
92
94
|
"expo-font": "~56.0.5",
|
|
93
95
|
"expo-glass-effect": "~56.0.4",
|
|
94
96
|
"expo-image-manipulator": "~56.0.17",
|
|
95
97
|
"expo-image-picker": "~56.0.16",
|
|
96
98
|
"expo-location": "~56.0.24",
|
|
97
99
|
"expo-speech": "~56.0.3",
|
|
98
|
-
"
|
|
100
|
+
"libphonenumber-js": "^1.13.8",
|
|
99
101
|
"react-native-compressor": "^1.19.0",
|
|
100
102
|
"react-native-vision-camera": "^5.0.11",
|
|
101
|
-
"zustand": "^5.0.2"
|
|
102
|
-
"expo-file-system": "~56.0.0"
|
|
103
|
+
"zustand": "^5.0.2"
|
|
103
104
|
},
|
|
104
105
|
"devDependencies": {
|
|
105
106
|
"@types/jest": "^29.5.12",
|
|
@@ -17,8 +17,6 @@ export interface GlassIconButtonProps {
|
|
|
17
17
|
size?: number;
|
|
18
18
|
iconSize?: number;
|
|
19
19
|
disabled?: boolean;
|
|
20
|
-
/** Render the glyph solid/filled (e.g. the theme toggle). */
|
|
21
|
-
solid?: boolean;
|
|
22
20
|
/**
|
|
23
21
|
* Skip this button's own glass surface — used when it sits inside a
|
|
24
22
|
* {@link GlassGroup} that already provides one shared glass capsule, so the
|
|
@@ -35,7 +33,6 @@ export function GlassIconButton({
|
|
|
35
33
|
size = 40,
|
|
36
34
|
iconSize = 20,
|
|
37
35
|
disabled = false,
|
|
38
|
-
solid = false,
|
|
39
36
|
plain = false,
|
|
40
37
|
accessibilityLabel,
|
|
41
38
|
}: GlassIconButtonProps): React.ReactElement {
|
|
@@ -54,7 +51,7 @@ export function GlassIconButton({
|
|
|
54
51
|
overflow: 'hidden',
|
|
55
52
|
}}
|
|
56
53
|
>
|
|
57
|
-
<Icon name={icon} size={iconSize} color={iconColor}
|
|
54
|
+
<Icon name={icon} size={iconSize} color={iconColor} />
|
|
58
55
|
</View>
|
|
59
56
|
);
|
|
60
57
|
|
|
@@ -71,7 +68,7 @@ export function GlassIconButton({
|
|
|
71
68
|
justifyContent: 'center',
|
|
72
69
|
}}
|
|
73
70
|
>
|
|
74
|
-
<Icon name={icon} size={iconSize} color={iconColor}
|
|
71
|
+
<Icon name={icon} size={iconSize} color={iconColor} />
|
|
75
72
|
</GlassSurface>
|
|
76
73
|
) : (
|
|
77
74
|
glyph
|
package/src/components/Icon.tsx
CHANGED
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { HugeiconsIcon } from '@hugeicons/react-native';
|
|
2
3
|
|
|
3
|
-
import { ICONS, type IconName } from './
|
|
4
|
+
import { ICONS, type IconName } from './icons';
|
|
4
5
|
|
|
5
|
-
export type { IconName } from './
|
|
6
|
+
export type { IconName } from './icons';
|
|
6
7
|
|
|
7
8
|
export interface IconProps {
|
|
8
9
|
name: IconName;
|
|
9
10
|
size?: number;
|
|
10
11
|
color: string;
|
|
11
12
|
strokeWidth?: number;
|
|
12
|
-
/** Render a solid/filled glyph (used for the theme toggle, matching Flutter's filled moon/sun). */
|
|
13
|
-
solid?: boolean;
|
|
14
13
|
}
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Every icon this SDK draws goes through here.
|
|
17
|
+
*
|
|
18
|
+
* The stroke is 1.6 to match the web SDK and the dashboard, which draw the
|
|
19
|
+
* same set at that weight. It was 2 while this SDK drew Lucide, whose glyphs
|
|
20
|
+
* are built for it.
|
|
21
|
+
*
|
|
22
|
+
* There is deliberately no `solid` prop. It existed to fill the theme toggle's
|
|
23
|
+
* moon and sun, which worked because Lucide's glyph bodies take a fill.
|
|
24
|
+
* Hugeicons' free pack is Stroke Rounded only - the solid styles are Pro - so
|
|
25
|
+
* the toggle now draws stroked, which is what Flutter has always done.
|
|
26
|
+
*/
|
|
27
|
+
export function Icon({ name, size = 20, color, strokeWidth = 1.6 }: IconProps): React.ReactElement {
|
|
28
|
+
return <HugeiconsIcon icon={ICONS[name]} size={size} color={color} strokeWidth={strokeWidth} />;
|
|
26
29
|
}
|
|
@@ -11,6 +11,7 @@ import { LivenessStep } from '../screens/LivenessStep';
|
|
|
11
11
|
import { SubmittedStep } from '../screens/SubmittedStep';
|
|
12
12
|
import { QuestionnaireStep } from '../screens/QuestionnaireStep';
|
|
13
13
|
import { ContactVerificationStep } from '../screens/ContactVerificationStep';
|
|
14
|
+
import { SupportingDocumentsStep } from '../screens/SupportingDocumentsStep';
|
|
14
15
|
import { ProofOfAddressStep } from '../screens/ProofOfAddressStep';
|
|
15
16
|
import {
|
|
16
17
|
AddressEntranceStep,
|
|
@@ -84,6 +85,8 @@ function stepScreen(step: KYCStep, onClose: () => void): React.ReactElement {
|
|
|
84
85
|
return <ContactVerificationStep key="contact-phone" channel="phone" />;
|
|
85
86
|
case 'proof-of-address':
|
|
86
87
|
return <ProofOfAddressStep />;
|
|
88
|
+
case 'supporting-documents':
|
|
89
|
+
return <SupportingDocumentsStep />;
|
|
87
90
|
// The address flow, in order: find it, confirm it, show it, commit it.
|
|
88
91
|
// 'address-collection' is the PIN step and keeps that wire name so older
|
|
89
92
|
// session progress restores cleanly.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { IconSvgElement } from '@hugeicons/react-native';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Glyphs Hugeicons does not carry, drawn in the set's own stroke language.
|
|
5
|
+
*
|
|
6
|
+
* Kept to the strict minimum: every other icon comes from the set, and this
|
|
7
|
+
* file exists only where the set has no equivalent at all. It MIRRORS the web
|
|
8
|
+
* SDK's `components/icons/glyphs.ts` - same geometry, same stroke attributes -
|
|
9
|
+
* so the two platforms draw one arrow rather than two near-misses.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const STROKE = {
|
|
13
|
+
stroke: 'currentColor',
|
|
14
|
+
strokeLinecap: 'round',
|
|
15
|
+
strokeLinejoin: 'round',
|
|
16
|
+
strokeWidth: '1.5',
|
|
17
|
+
} as const;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A LONG left arrow - a full-width shaft with a small head.
|
|
21
|
+
*
|
|
22
|
+
* Hugeicons has no such glyph. Its longest one-way left arrow is
|
|
23
|
+
* `ArrowLeft02Icon`, whose shaft spans 13.5 of the 24-unit viewBox; the rest
|
|
24
|
+
* are shorter, bare chevrons, or arrows into a vertical bar. This SDK's back
|
|
25
|
+
* control drew Lucide's `MoveLeft` before the migration, whose shaft is 20
|
|
26
|
+
* units, so moving to the set would visibly shorten it.
|
|
27
|
+
*
|
|
28
|
+
* The geometry is Lucide's, inset to sit on the same optical margins as its
|
|
29
|
+
* Hugeicons siblings (they start at ~3.5 rather than Lucide's 2), and the
|
|
30
|
+
* stroke attributes are copied from the set so weight and joins match exactly.
|
|
31
|
+
*/
|
|
32
|
+
export const LONG_ARROW_LEFT: IconSvgElement = [
|
|
33
|
+
['path', { d: 'M20.5 12H3.5', ...STROKE, key: '0' }],
|
|
34
|
+
['path', { d: 'M8 7.5L3.5 12L8 16.5', ...STROKE, key: '1' }],
|
|
35
|
+
];
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import type { IconSvgElement } from '@hugeicons/react-native';
|
|
2
|
+
|
|
3
|
+
import Add01Icon from '@hugeicons/core-free-icons/Add01Icon';
|
|
4
|
+
import AlertCircleIcon from '@hugeicons/core-free-icons/AlertCircleIcon';
|
|
5
|
+
import BadgeCheckIcon from '@hugeicons/core-free-icons/BadgeCheckIcon';
|
|
6
|
+
import BellRingIcon from '@hugeicons/core-free-icons/BellRingIcon';
|
|
7
|
+
import BookUserIcon from '@hugeicons/core-free-icons/BookUserIcon';
|
|
8
|
+
import BubbleChatIcon from '@hugeicons/core-free-icons/BubbleChatIcon';
|
|
9
|
+
import Building02Icon from '@hugeicons/core-free-icons/Building02Icon';
|
|
10
|
+
import BulbIcon from '@hugeicons/core-free-icons/BulbIcon';
|
|
11
|
+
import Calendar01Icon from '@hugeicons/core-free-icons/Calendar01Icon';
|
|
12
|
+
import Camera01Icon from '@hugeicons/core-free-icons/Camera01Icon';
|
|
13
|
+
import CameraOff01Icon from '@hugeicons/core-free-icons/CameraOff01Icon';
|
|
14
|
+
import Cancel01Icon from '@hugeicons/core-free-icons/Cancel01Icon';
|
|
15
|
+
import CancelCircleIcon from '@hugeicons/core-free-icons/CancelCircleIcon';
|
|
16
|
+
import Car01Icon from '@hugeicons/core-free-icons/Car01Icon';
|
|
17
|
+
import CheckIcon from '@hugeicons/core-free-icons/CheckIcon';
|
|
18
|
+
import CheckmarkCircle02Icon from '@hugeicons/core-free-icons/CheckmarkCircle02Icon';
|
|
19
|
+
import ChevronDownIcon from '@hugeicons/core-free-icons/ChevronDownIcon';
|
|
20
|
+
import ChevronLeftIcon from '@hugeicons/core-free-icons/ChevronLeftIcon';
|
|
21
|
+
import ChevronRightIcon from '@hugeicons/core-free-icons/ChevronRightIcon';
|
|
22
|
+
import CircleDashedIcon from '@hugeicons/core-free-icons/CircleDashedIcon';
|
|
23
|
+
import ContactIcon from '@hugeicons/core-free-icons/ContactIcon';
|
|
24
|
+
import CopyIcon from '@hugeicons/core-free-icons/CopyIcon';
|
|
25
|
+
import CreditCardIcon from '@hugeicons/core-free-icons/CreditCardIcon';
|
|
26
|
+
import ExpandIcon from '@hugeicons/core-free-icons/ExpandIcon';
|
|
27
|
+
import FaceIdIcon from '@hugeicons/core-free-icons/FaceIdIcon';
|
|
28
|
+
import File02Icon from '@hugeicons/core-free-icons/File02Icon';
|
|
29
|
+
import FilterIcon from '@hugeicons/core-free-icons/FilterIcon';
|
|
30
|
+
import FingerPrintIcon from '@hugeicons/core-free-icons/FingerPrintIcon';
|
|
31
|
+
import FlashOffIcon from '@hugeicons/core-free-icons/FlashOffIcon';
|
|
32
|
+
import FlaskConicalIcon from '@hugeicons/core-free-icons/FlaskConicalIcon';
|
|
33
|
+
import GlobeIcon from '@hugeicons/core-free-icons/GlobeIcon';
|
|
34
|
+
import Gps02Icon from '@hugeicons/core-free-icons/Gps02Icon';
|
|
35
|
+
import HelpCircleIcon from '@hugeicons/core-free-icons/HelpCircleIcon';
|
|
36
|
+
import Home01Icon from '@hugeicons/core-free-icons/Home01Icon';
|
|
37
|
+
import IdentityCardIcon from '@hugeicons/core-free-icons/IdentityCardIcon';
|
|
38
|
+
import Image01Icon from '@hugeicons/core-free-icons/Image01Icon';
|
|
39
|
+
import InformationCircleIcon from '@hugeicons/core-free-icons/InformationCircleIcon';
|
|
40
|
+
import LandmarkIcon from '@hugeicons/core-free-icons/LandmarkIcon';
|
|
41
|
+
import Link02Icon from '@hugeicons/core-free-icons/Link02Icon';
|
|
42
|
+
import Location02Icon from '@hugeicons/core-free-icons/Location02Icon';
|
|
43
|
+
import LocationCheck01Icon from '@hugeicons/core-free-icons/LocationCheck01Icon';
|
|
44
|
+
import LockIcon from '@hugeicons/core-free-icons/LockIcon';
|
|
45
|
+
import Mail01Icon from '@hugeicons/core-free-icons/Mail01Icon';
|
|
46
|
+
import MapPinHouseIcon from '@hugeicons/core-free-icons/MapPinHouseIcon';
|
|
47
|
+
import MapPinIcon from '@hugeicons/core-free-icons/MapPinIcon';
|
|
48
|
+
import Message01Icon from '@hugeicons/core-free-icons/Message01Icon';
|
|
49
|
+
import MinusSignIcon from '@hugeicons/core-free-icons/MinusSignIcon';
|
|
50
|
+
import MoonIcon from '@hugeicons/core-free-icons/MoonIcon';
|
|
51
|
+
import NfcIcon from '@hugeicons/core-free-icons/NfcIcon';
|
|
52
|
+
import PencilEdit01Icon from '@hugeicons/core-free-icons/PencilEdit01Icon';
|
|
53
|
+
import PencilIcon from '@hugeicons/core-free-icons/PencilIcon';
|
|
54
|
+
import Radar01Icon from '@hugeicons/core-free-icons/Radar01Icon';
|
|
55
|
+
import RefreshCwIcon from '@hugeicons/core-free-icons/RefreshCwIcon';
|
|
56
|
+
import RefreshIcon from '@hugeicons/core-free-icons/RefreshIcon';
|
|
57
|
+
import ScanIcon from '@hugeicons/core-free-icons/ScanIcon';
|
|
58
|
+
import Search01Icon from '@hugeicons/core-free-icons/Search01Icon';
|
|
59
|
+
import SecurityCheckIcon from '@hugeicons/core-free-icons/SecurityCheckIcon';
|
|
60
|
+
import Share01Icon from '@hugeicons/core-free-icons/Share01Icon';
|
|
61
|
+
import SlidersHorizontalIcon from '@hugeicons/core-free-icons/SlidersHorizontalIcon';
|
|
62
|
+
import SmartPhone01Icon from '@hugeicons/core-free-icons/SmartPhone01Icon';
|
|
63
|
+
import StampIcon from '@hugeicons/core-free-icons/StampIcon';
|
|
64
|
+
import Sun01Icon from '@hugeicons/core-free-icons/Sun01Icon';
|
|
65
|
+
import Timer01Icon from '@hugeicons/core-free-icons/Timer01Icon';
|
|
66
|
+
import Upload01Icon from '@hugeicons/core-free-icons/Upload01Icon';
|
|
67
|
+
import UserAdd01Icon from '@hugeicons/core-free-icons/UserAdd01Icon';
|
|
68
|
+
import UserCircleIcon from '@hugeicons/core-free-icons/UserCircleIcon';
|
|
69
|
+
import UserGroupIcon from '@hugeicons/core-free-icons/UserGroupIcon';
|
|
70
|
+
import VideoOffIcon from '@hugeicons/core-free-icons/VideoOffIcon';
|
|
71
|
+
import VoteIcon from '@hugeicons/core-free-icons/VoteIcon';
|
|
72
|
+
import ZapIcon from '@hugeicons/core-free-icons/ZapIcon';
|
|
73
|
+
|
|
74
|
+
import { LONG_ARROW_LEFT } from './glyphs';
|
|
75
|
+
import type { IconName } from './names';
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Each role, and the glyph that draws it.
|
|
79
|
+
*
|
|
80
|
+
* Imports are DEEP - one module per icon - and must stay that way. Importing
|
|
81
|
+
* from the package index instead pulls the whole 6,025-icon pack into the
|
|
82
|
+
* bundle: measured at +8.33 MB for five icons against +7 KB for the same five
|
|
83
|
+
* imported this way. The pack declares a `./*` export for exactly this, and
|
|
84
|
+
* iconImports.test.ts fails the build on a barrel import.
|
|
85
|
+
*
|
|
86
|
+
* The glyphs are the ones the web SDK and Flutter already chose for these
|
|
87
|
+
* names, so the three SDKs draw one set. Where neither had a choice to copy,
|
|
88
|
+
* it was made against the catalogue by meaning and is noted below.
|
|
89
|
+
*/
|
|
90
|
+
export const ICONS: Record<IconName, IconSvgElement> = {
|
|
91
|
+
close: Cancel01Icon,
|
|
92
|
+
back: LONG_ARROW_LEFT,
|
|
93
|
+
moon: MoonIcon,
|
|
94
|
+
sun: Sun01Icon,
|
|
95
|
+
check: CheckIcon,
|
|
96
|
+
lock: LockIcon,
|
|
97
|
+
alert: AlertCircleIcon,
|
|
98
|
+
// The environment banner's mark, shared with the web SDK (same lucide glyph)
|
|
99
|
+
// and mirrored by Flutter's Icons.science_outlined.
|
|
100
|
+
flask: FlaskConicalIcon,
|
|
101
|
+
refresh: RefreshCwIcon,
|
|
102
|
+
'refresh-ccw': RefreshIcon,
|
|
103
|
+
maximize: ExpandIcon,
|
|
104
|
+
calendar: Calendar01Icon,
|
|
105
|
+
image: Image01Icon,
|
|
106
|
+
'chevron-left': ChevronLeftIcon,
|
|
107
|
+
'chevron-right': ChevronRightIcon,
|
|
108
|
+
'chevron-down': ChevronDownIcon,
|
|
109
|
+
shield: SecurityCheckIcon,
|
|
110
|
+
'badge-check': BadgeCheckIcon,
|
|
111
|
+
'circle-dashed': CircleDashedIcon,
|
|
112
|
+
'circle-check': CheckmarkCircle02Icon,
|
|
113
|
+
'circle-help': HelpCircleIcon,
|
|
114
|
+
'circle-x': CancelCircleIcon,
|
|
115
|
+
'building-2': Building02Icon,
|
|
116
|
+
stamp: StampIcon,
|
|
117
|
+
user: UserCircleIcon,
|
|
118
|
+
info: InformationCircleIcon,
|
|
119
|
+
'user-plus': UserAdd01Icon,
|
|
120
|
+
plus: Add01Icon,
|
|
121
|
+
link: Link02Icon,
|
|
122
|
+
copy: CopyIcon,
|
|
123
|
+
share: Share01Icon,
|
|
124
|
+
users: UserGroupIcon,
|
|
125
|
+
'scan-line': ScanIcon,
|
|
126
|
+
'scan-face': FaceIdIcon,
|
|
127
|
+
nfc: NfcIcon,
|
|
128
|
+
filter: FilterIcon,
|
|
129
|
+
pencil: PencilIcon,
|
|
130
|
+
'pencil-line': PencilEdit01Icon,
|
|
131
|
+
search: Search01Icon,
|
|
132
|
+
zap: ZapIcon,
|
|
133
|
+
'zap-off': FlashOffIcon,
|
|
134
|
+
timer: Timer01Icon,
|
|
135
|
+
fingerprint: FingerPrintIcon,
|
|
136
|
+
'credit-card': CreditCardIcon,
|
|
137
|
+
globe: GlobeIcon,
|
|
138
|
+
car: Car01Icon,
|
|
139
|
+
vote: VoteIcon,
|
|
140
|
+
'file-text': File02Icon,
|
|
141
|
+
house: Home01Icon,
|
|
142
|
+
landmark: LandmarkIcon,
|
|
143
|
+
'map-pin': MapPinIcon,
|
|
144
|
+
'map-pin-house': MapPinHouseIcon,
|
|
145
|
+
'map-pin-check': LocationCheck01Icon,
|
|
146
|
+
'map-pinned': Location02Icon,
|
|
147
|
+
radar: Radar01Icon,
|
|
148
|
+
'bell-ring': BellRingIcon,
|
|
149
|
+
sliders: SlidersHorizontalIcon,
|
|
150
|
+
locate: Gps02Icon,
|
|
151
|
+
minus: MinusSignIcon,
|
|
152
|
+
'id-card': IdentityCardIcon,
|
|
153
|
+
contact: ContactIcon,
|
|
154
|
+
passport: BookUserIcon,
|
|
155
|
+
camera: Camera01Icon,
|
|
156
|
+
'camera-off': CameraOff01Icon,
|
|
157
|
+
'video-off': VideoOffIcon,
|
|
158
|
+
upload: Upload01Icon,
|
|
159
|
+
x: Cancel01Icon,
|
|
160
|
+
lightbulb: BulbIcon,
|
|
161
|
+
mail: Mail01Icon,
|
|
162
|
+
smartphone: SmartPhone01Icon,
|
|
163
|
+
'message-square': Message01Icon,
|
|
164
|
+
'message-circle': BubbleChatIcon,
|
|
165
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The icon roles this SDK draws, by MEANING rather than by glyph name.
|
|
3
|
+
*
|
|
4
|
+
* This is the boundary that lets the set underneath change without touching a
|
|
5
|
+
* call site: a screen asks for 'close', and `icons/map.ts` decides what that
|
|
6
|
+
* looks like. Adding a role here means adding its glyph there.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export type IconName =
|
|
10
|
+
// chrome
|
|
11
|
+
| 'close'
|
|
12
|
+
| 'back'
|
|
13
|
+
| 'moon'
|
|
14
|
+
| 'sun'
|
|
15
|
+
| 'check'
|
|
16
|
+
| 'lock'
|
|
17
|
+
| 'alert'
|
|
18
|
+
| 'flask'
|
|
19
|
+
| 'refresh'
|
|
20
|
+
| 'refresh-ccw'
|
|
21
|
+
| 'maximize'
|
|
22
|
+
| 'calendar'
|
|
23
|
+
| 'image'
|
|
24
|
+
| 'chevron-left'
|
|
25
|
+
| 'chevron-right'
|
|
26
|
+
| 'chevron-down'
|
|
27
|
+
// consent hero + process steps
|
|
28
|
+
| 'shield'
|
|
29
|
+
| 'badge-check'
|
|
30
|
+
| 'circle-dashed'
|
|
31
|
+
| 'circle-check'
|
|
32
|
+
| 'circle-help'
|
|
33
|
+
| 'circle-x'
|
|
34
|
+
| 'building-2'
|
|
35
|
+
| 'stamp'
|
|
36
|
+
| 'user'
|
|
37
|
+
| 'user-plus'
|
|
38
|
+
| 'plus'
|
|
39
|
+
| 'info'
|
|
40
|
+
| 'users'
|
|
41
|
+
| 'scan-line'
|
|
42
|
+
| 'scan-face'
|
|
43
|
+
| 'nfc'
|
|
44
|
+
| 'filter'
|
|
45
|
+
| 'pencil'
|
|
46
|
+
| 'pencil-line'
|
|
47
|
+
| 'search'
|
|
48
|
+
| 'zap'
|
|
49
|
+
| 'link'
|
|
50
|
+
| 'copy'
|
|
51
|
+
| 'share'
|
|
52
|
+
| 'zap-off'
|
|
53
|
+
| 'timer'
|
|
54
|
+
// id-type glyphs
|
|
55
|
+
| 'fingerprint'
|
|
56
|
+
| 'credit-card'
|
|
57
|
+
| 'globe'
|
|
58
|
+
| 'car'
|
|
59
|
+
| 'vote'
|
|
60
|
+
| 'file-text'
|
|
61
|
+
| 'house'
|
|
62
|
+
| 'landmark'
|
|
63
|
+
| 'id-card'
|
|
64
|
+
| 'contact'
|
|
65
|
+
| 'passport'
|
|
66
|
+
| 'camera'
|
|
67
|
+
| 'camera-off'
|
|
68
|
+
| 'video-off'
|
|
69
|
+
| 'upload'
|
|
70
|
+
| 'x'
|
|
71
|
+
// address collection (map picker + the presence milestone track)
|
|
72
|
+
| 'map-pin'
|
|
73
|
+
| 'map-pin-house'
|
|
74
|
+
| 'map-pin-check'
|
|
75
|
+
| 'map-pinned'
|
|
76
|
+
| 'radar'
|
|
77
|
+
| 'bell-ring'
|
|
78
|
+
| 'sliders'
|
|
79
|
+
| 'locate'
|
|
80
|
+
| 'minus'
|
|
81
|
+
| 'lightbulb'
|
|
82
|
+
// contact verification (OTP channels + step footer)
|
|
83
|
+
| 'mail'
|
|
84
|
+
| 'smartphone'
|
|
85
|
+
| 'message-square'
|
|
86
|
+
| 'message-circle';
|
|
@@ -10,6 +10,8 @@ import { addressStepMeta } from '../screens/address';
|
|
|
10
10
|
import { countrySelectMeta } from '../screens/CountrySelectStep';
|
|
11
11
|
import { businessDetailsMeta } from '../screens/BusinessDetailsStep';
|
|
12
12
|
import { businessKeyPeopleMeta } from '../screens/BusinessKeyPeopleStep';
|
|
13
|
+
import { supportingDocumentsMeta } from '../screens/SupportingDocumentsStep';
|
|
14
|
+
import { resolveSupportingDocuments, verifiedIdsFor } from '../config/supportingDocuments';
|
|
13
15
|
import { businessDocumentsMeta } from '../screens/BusinessDocumentsStep';
|
|
14
16
|
import { applicantRoleMeta } from '../screens/ApplicantRoleStep';
|
|
15
17
|
import { nfcMeta } from '../screens/NfcStep';
|
|
@@ -49,6 +51,9 @@ export interface StepHeaderContext {
|
|
|
49
51
|
/** The proof-of-address kind the applicant has picked, so the header can ask
|
|
50
52
|
* for what the workflow's name rule wants on THAT document. */
|
|
51
53
|
poaDocumentType?: string | null;
|
|
54
|
+
/** The committed multi-ID slots, so the supporting-documents header resolves
|
|
55
|
+
* the SAME list the screen shows. */
|
|
56
|
+
multiIdSlots?: Array<{ idType: string }>;
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
export function stepHeaderMeta(
|
|
@@ -62,6 +67,7 @@ export function stepHeaderMeta(
|
|
|
62
67
|
addressIntroPending,
|
|
63
68
|
addressEntranceFraming,
|
|
64
69
|
poaDocumentType,
|
|
70
|
+
multiIdSlots,
|
|
65
71
|
}: StepHeaderContext,
|
|
66
72
|
): { title: string; description: string | null } {
|
|
67
73
|
const label = labelFor(country, selectedIdType);
|
|
@@ -121,6 +127,15 @@ export function stepHeaderMeta(
|
|
|
121
127
|
return businessKeyPeopleMeta;
|
|
122
128
|
case 'business-documents':
|
|
123
129
|
return businessDocumentsMeta;
|
|
130
|
+
case 'supporting-documents':
|
|
131
|
+
// Resolved exactly as the screen resolves its own slots, or the header
|
|
132
|
+
// could name a number the body does not show.
|
|
133
|
+
return supportingDocumentsMeta(
|
|
134
|
+
resolveSupportingDocuments(
|
|
135
|
+
config.supportingDocuments,
|
|
136
|
+
verifiedIdsFor({ country, idType: selectedIdType, multiIdSlots }),
|
|
137
|
+
),
|
|
138
|
+
);
|
|
124
139
|
case 'applicant-role':
|
|
125
140
|
return applicantRoleMeta;
|
|
126
141
|
case 'nfc':
|
package/src/config/stepOrder.ts
CHANGED
|
@@ -44,6 +44,14 @@ export interface StepOrderOptions {
|
|
|
44
44
|
hasEmailVerification: boolean;
|
|
45
45
|
hasPhoneVerification: boolean;
|
|
46
46
|
hasPoa: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Whether the supporting-documents step has anything to ask for on THIS
|
|
49
|
+
* attempt. Resolved by the caller (config/supportingDocuments.ts) because
|
|
50
|
+
* the list depends on the ID the person actually picked — a document scoped
|
|
51
|
+
* to one ID is not asked of somebody who used another, and a step with an
|
|
52
|
+
* empty list must not appear at all.
|
|
53
|
+
*/
|
|
54
|
+
hasSupportingDocuments: boolean;
|
|
47
55
|
hasAddressCollection: boolean;
|
|
48
56
|
/**
|
|
49
57
|
* Which address screens the flow has, from the ONE `addressFlowFor` call.
|
|
@@ -120,11 +128,15 @@ function fullStepOrder(o: StepOrderOptions): KYCStep[] {
|
|
|
120
128
|
if (o.scope === 'address') {
|
|
121
129
|
const steps: KYCStep[] = [...openingSteps(o), ...contactSteps(o)];
|
|
122
130
|
if (o.hasPoa) steps.push('proof-of-address');
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
131
|
+
// Gated like the full flow, and like Flutter has always done it: an
|
|
132
|
+
// address flow that asks only for proof of address never opens a map.
|
|
133
|
+
if (o.hasAddressCollection) {
|
|
134
|
+
steps.push(
|
|
135
|
+
...addressFlowSteps(
|
|
136
|
+
o.addressFlow ?? { searchAvailable: false, photoMode: 'optional', streetViewOffered: false },
|
|
137
|
+
),
|
|
138
|
+
);
|
|
139
|
+
}
|
|
128
140
|
if (o.hasQuestionnaire) steps.push('questionnaire');
|
|
129
141
|
steps.push('submitted');
|
|
130
142
|
return steps;
|
|
@@ -143,6 +155,9 @@ function fullStepOrder(o: StepOrderOptions): KYCStep[] {
|
|
|
143
155
|
}
|
|
144
156
|
|
|
145
157
|
const middle: KYCStep[] = [...captureLeg(o)];
|
|
158
|
+
// Paperwork the org files comes BEFORE the address evidence the
|
|
159
|
+
// verification is judged on (user decision 2026-09-22).
|
|
160
|
+
if (o.hasSupportingDocuments) middle.push('supporting-documents');
|
|
146
161
|
if (o.hasPoa) middle.push('proof-of-address');
|
|
147
162
|
// The address flow is FOUR real steps on an individual flow (find it, confirm
|
|
148
163
|
// it, show it, commit it), so the progress bar advances through them and back
|