@myazahq/kyc-sdk-react-native 2.4.0 → 2.5.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.
Files changed (117) hide show
  1. package/android/build.gradle +35 -3
  2. package/android/src/main/java/com/margelo/nitro/myazakyc/HybridMyazaFaceDetector.kt +75 -0
  3. package/ios/HybridMyazaFaceDetector.swift +8 -0
  4. package/nitrogen/generated/android/c++/JHybridMyazaFaceDetectorSpec.cpp +23 -0
  5. package/nitrogen/generated/android/c++/JHybridMyazaFaceDetectorSpec.hpp +2 -0
  6. package/nitrogen/generated/android/kotlin/com/margelo/nitro/myazakyc/HybridMyazaFaceDetectorSpec.kt +9 -0
  7. package/nitrogen/generated/ios/KycSdkReactNative-Swift-Cxx-Bridge.cpp +8 -0
  8. package/nitrogen/generated/ios/KycSdkReactNative-Swift-Cxx-Bridge.hpp +43 -0
  9. package/nitrogen/generated/ios/c++/HybridMyazaFaceDetectorSpecSwift.hpp +17 -0
  10. package/nitrogen/generated/ios/swift/Func_void_bool.swift +46 -0
  11. package/nitrogen/generated/ios/swift/HybridMyazaFaceDetectorSpec.swift +2 -0
  12. package/nitrogen/generated/ios/swift/HybridMyazaFaceDetectorSpec_cxx.swift +31 -0
  13. package/nitrogen/generated/shared/c++/HybridMyazaFaceDetectorSpec.cpp +2 -0
  14. package/nitrogen/generated/shared/c++/HybridMyazaFaceDetectorSpec.hpp +3 -0
  15. package/package.json +1 -1
  16. package/src/MyazaKYC.tsx +12 -0
  17. package/src/components/DashedBorder.tsx +55 -0
  18. package/src/components/DialCodePicker.tsx +14 -7
  19. package/src/components/Icon.tsx +9 -0
  20. package/src/components/MultiIdProgress.tsx +107 -0
  21. package/src/components/MyazaInput.tsx +23 -4
  22. package/src/components/MyazaSelect.tsx +2 -1
  23. package/src/components/OwnershipSlider.tsx +102 -0
  24. package/src/components/PhoneNumberInput.tsx +37 -4
  25. package/src/components/StaggerIn.tsx +63 -0
  26. package/src/components/StepView.tsx +26 -0
  27. package/src/components/glass/FloatingSheet.tsx +73 -21
  28. package/src/components/glass/GlassSheet.tsx +14 -2
  29. package/src/components/stepHeaderMeta.tsx +3 -1
  30. package/src/config/business.ts +6 -6
  31. package/src/config/businessDetailsValidity.ts +52 -0
  32. package/src/config/businessPrefill.ts +72 -0
  33. package/src/config/businessSteps.ts +14 -3
  34. package/src/config/keyPeople.ts +111 -7
  35. package/src/config/keyPeopleCorporate.ts +19 -0
  36. package/src/config/keyPeopleOwnerTypes.ts +12 -0
  37. package/src/config/keyPeopleOwners.ts +26 -0
  38. package/src/config/keyPeoplePrefill.ts +138 -0
  39. package/src/config/keyPeopleSectionDefs.ts +65 -0
  40. package/src/config/keyPeopleSections.ts +167 -0
  41. package/src/config/registrationHint.ts +1 -1
  42. package/src/config/stepOrder.ts +24 -4
  43. package/src/config/theme.ts +8 -2
  44. package/src/config/website.ts +36 -0
  45. package/src/config/workflowMerge.ts +5 -0
  46. package/src/emrtd/activeAuth.ts +100 -0
  47. package/src/emrtd/extras.ts +76 -0
  48. package/src/emrtd/files.ts +5 -0
  49. package/src/emrtd/index.ts +1 -0
  50. package/src/emrtd/read.ts +8 -1
  51. package/src/emrtd/session.ts +41 -0
  52. package/src/emrtd/stages.ts +11 -0
  53. package/src/lib/contact-recovery.ts +44 -0
  54. package/src/lib/multi-id.ts +210 -0
  55. package/src/lib/resubmit.ts +130 -0
  56. package/src/lib/screen-corners.ts +50 -0
  57. package/src/lib/step-log.ts +24 -3
  58. package/src/lib/use-multi-id-plan.ts +29 -0
  59. package/src/liveness/useModelReady.ts +65 -0
  60. package/src/liveness/visionCameraFaceDetector.ts +35 -0
  61. package/src/screens/ApplicantRoleStep.tsx +9 -5
  62. package/src/screens/BusinessCheckPanel.tsx +89 -0
  63. package/src/screens/BusinessDetailsFields.tsx +109 -0
  64. package/src/screens/BusinessDetailsStep.tsx +131 -145
  65. package/src/screens/BusinessDocumentSlot.tsx +2 -3
  66. package/src/screens/BusinessDocumentsStep.tsx +1 -1
  67. package/src/screens/BusinessKeyPeopleStep.tsx +103 -71
  68. package/src/screens/BusinessPickedCard.tsx +86 -0
  69. package/src/screens/BusinessPickedSection.tsx +51 -0
  70. package/src/screens/BusinessRegistryPickers.tsx +67 -0
  71. package/src/screens/BusinessSandboxToggle.tsx +114 -0
  72. package/src/screens/BusinessSearch.tsx +199 -0
  73. package/src/screens/BusinessSearchResults.tsx +115 -0
  74. package/src/screens/CompanyInfoFields.tsx +86 -51
  75. package/src/screens/ConsentStep.tsx +31 -0
  76. package/src/screens/ContactDestinationField.tsx +1 -0
  77. package/src/screens/ContactVerificationStep.tsx +34 -3
  78. package/src/screens/IdTypeStep.tsx +12 -5
  79. package/src/screens/KeepLinksSheet.tsx +88 -0
  80. package/src/screens/KeyPeopleAwaitCard.tsx +204 -0
  81. package/src/screens/KeyPeopleAwaitList.tsx +126 -0
  82. package/src/screens/KeyPeoplePending.tsx +154 -0
  83. package/src/screens/KeyPeopleSection.tsx +162 -0
  84. package/src/screens/KeyPeopleSectionsList.tsx +103 -0
  85. package/src/screens/KeyPeopleUboExemption.tsx +72 -0
  86. package/src/screens/KeyPersonCard.tsx +36 -4
  87. package/src/screens/KeyPersonForm.tsx +195 -36
  88. package/src/screens/KeyPersonKindToggle.tsx +68 -0
  89. package/src/screens/KeyPersonOwners.tsx +109 -0
  90. package/src/screens/KeyPersonRoleChips.tsx +68 -0
  91. package/src/screens/KeyPersonSheet.tsx +92 -108
  92. package/src/screens/LivenessStep.tsx +18 -0
  93. package/src/screens/NfcStep.tsx +14 -0
  94. package/src/screens/ProofOfAddressStep.tsx +6 -3
  95. package/src/screens/SubmittedStep.tsx +66 -10
  96. package/src/screens/nfc/NfcReadProgress.tsx +1 -0
  97. package/src/screens/useAwaitingPeople.ts +90 -0
  98. package/src/services/api-types.ts +158 -2
  99. package/src/services/api-verify-types.ts +53 -1
  100. package/src/services/api.ts +104 -0
  101. package/src/services/deviceMetadata.ts +1 -1
  102. package/src/services/errors.ts +10 -2
  103. package/src/services/workflowGate.ts +1 -0
  104. package/src/specs/MyazaFaceDetector.nitro.ts +29 -0
  105. package/src/store/businessCheck.ts +113 -0
  106. package/src/store/derive.ts +15 -0
  107. package/src/store/kycStore.ts +241 -14
  108. package/src/store/serverConfig.ts +2 -0
  109. package/src/store/session.ts +208 -0
  110. package/src/store/state.ts +155 -2
  111. package/src/store/submit.ts +63 -13
  112. package/src/store/submitApplicant.ts +5 -11
  113. package/src/types/business.ts +23 -2
  114. package/src/types/config.ts +22 -1
  115. package/src/types/verification.ts +1 -1
  116. package/src/types/workflow.ts +15 -0
  117. package/src/screens/KeyPeopleInviteLinks.tsx +0 -239
@@ -1,239 +0,0 @@
1
- import React, { useState } from 'react';
2
- import { Pressable, Share, View } from 'react-native';
3
- import * as Clipboard from 'expo-clipboard';
4
-
5
- import { radius, spacing } from '../config/theme';
6
- import { useKyc, useTheme } from '../components/runtime';
7
- import { MyazaText } from '../components/Typography';
8
- import { Icon } from '../components/Icon';
9
- import { CountryFlag } from '../components/CountryFlag';
10
- import { regionCountryName } from '../config/regions';
11
- import { KEY_PERSON_ROLE_LABELS } from '../config/keyPeople';
12
- import type { KeyPersonInvite } from '../services/api-types';
13
- import type { ApplicantRole, KeyPersonRole } from '../types/business';
14
-
15
- // ---------------------------------------------------------------------------
16
- // "Awaiting users" — the KYB success screen's people section. Every person the
17
- // review is waiting on, grouped by role, each with a status pill; pending
18
- // people carry a shareable verification link, and the APPLICANT (who verified
19
- // in-flow) appears with a green Submitted pill so the picture is complete.
20
- // Mirrors the web SDK's KeyPeopleInviteLinks 1:1 — mobile shares via the
21
- // native sheet (reaches WhatsApp/SMS, still offers Copy inside).
22
- // ---------------------------------------------------------------------------
23
-
24
- type AwaitRole = ApplicantRole;
25
-
26
- interface AwaitRow {
27
- name: string;
28
- role: AwaitRole;
29
- pct: string | null;
30
- country: string | null;
31
- status: 'submitted' | 'pending';
32
- inviteUrl?: string;
33
- isApplicant?: boolean;
34
- }
35
-
36
- const ROLE_LABELS: Record<AwaitRole, string> = {
37
- ...KEY_PERSON_ROLE_LABELS,
38
- authorized_representative: 'Authorized representative',
39
- };
40
-
41
- const SECTIONS: Array<{ role: AwaitRole; label: string }> = [
42
- { role: 'beneficial_owner', label: 'UBOS' },
43
- { role: 'director', label: 'DIRECTORS' },
44
- { role: 'signatory', label: 'SIGNATORIES' },
45
- { role: 'shareholder', label: 'SHAREHOLDERS' },
46
- { role: 'authorized_representative', label: 'REPRESENTATIVES' },
47
- ];
48
-
49
- export function KeyPeopleInviteLinks({
50
- invites,
51
- }: {
52
- invites: KeyPersonInvite[];
53
- }): React.ReactElement | null {
54
- const { colors } = useTheme();
55
- const app = useKyc((s) => s.businessApplication);
56
- if (invites.length === 0) return null;
57
-
58
- const rows: AwaitRow[] = [];
59
-
60
- // The applicant themselves — verified in-flow, nothing more to do.
61
- if (app.applicantRole) {
62
- const self =
63
- app.applicantKeyPersonIndex !== null ? app.keyPeople[app.applicantKeyPersonIndex] : null;
64
- rows.push({
65
- name: (self?.name ?? app.applicantName).trim() || 'You',
66
- role: (self?.role ?? app.applicantRole) as AwaitRole,
67
- pct: self?.ownershipPct.trim() || null,
68
- country: self?.country.trim() ? self.country.trim().toUpperCase() : null,
69
- status: 'submitted',
70
- isApplicant: true,
71
- });
72
- }
73
-
74
- // Everyone the server minted a link for — enriched from the entered rows.
75
- for (const invite of invites) {
76
- const entered = app.keyPeople.find((p) => p.name.trim() === invite.name.trim());
77
- rows.push({
78
- name: invite.name,
79
- role: (entered?.role ?? 'director') as AwaitRole,
80
- pct: entered?.ownershipPct.trim() || null,
81
- country: entered?.country.trim() ? entered.country.trim().toUpperCase() : null,
82
- status: 'pending',
83
- inviteUrl: invite.inviteUrl,
84
- });
85
- }
86
-
87
- return (
88
- <View style={{ width: '100%', marginTop: spacing.lg }}>
89
- <MyazaText variant="bodySmall" color={colors.textMuted} style={{ textAlign: 'center', marginBottom: spacing.md }}>
90
- To complete the review, the people below must verify their identity with a KYC check.
91
- Anyone with an email on file has already been sent their link.
92
- </MyazaText>
93
-
94
- {SECTIONS.map(({ role, label }) => {
95
- const group = rows.filter((r) => r.role === role);
96
- if (group.length === 0) return null;
97
- return (
98
- <View key={role} style={{ marginBottom: spacing.sm }}>
99
- <MyazaText
100
- variant="bodySmall"
101
- color={colors.textMuted}
102
- style={{ fontWeight: '600', letterSpacing: 1.2, marginBottom: spacing.xs + 2 }}
103
- >
104
- {label}
105
- </MyazaText>
106
- {group.map((row, i) => (
107
- <AwaitCard key={`${role}-${i}`} row={row} />
108
- ))}
109
- </View>
110
- );
111
- })}
112
-
113
- <MyazaText variant="bodySmall" color={colors.textMuted} style={{ textAlign: 'center' }}>
114
- Links are valid for 14 days.
115
- </MyazaText>
116
- </View>
117
- );
118
- }
119
-
120
- function AwaitCard({ row }: { row: AwaitRow }): React.ReactElement {
121
- const { colors } = useTheme();
122
- const submitted = row.status === 'submitted';
123
- const [copied, setCopied] = useState(false);
124
-
125
- const share = (): void => {
126
- if (!row.inviteUrl) return;
127
- Share.share({ message: row.inviteUrl }).catch(() => undefined);
128
- };
129
- const copy = (): void => {
130
- if (!row.inviteUrl) return;
131
- Clipboard.setStringAsync(row.inviteUrl)
132
- .then(() => {
133
- setCopied(true);
134
- setTimeout(() => setCopied(false), 2000);
135
- })
136
- .catch(() => undefined);
137
- };
138
-
139
- return (
140
- <View
141
- style={{
142
- backgroundColor: colors.backgroundSecondary,
143
- borderRadius: radius.md,
144
- padding: spacing.md,
145
- marginBottom: spacing.sm,
146
- }}
147
- >
148
- <View style={{ flexDirection: 'row', alignItems: 'flex-start' }}>
149
- <View style={{ flex: 1, minWidth: 0, marginRight: spacing.sm }}>
150
- <MyazaText variant="bodyMedium" numberOfLines={1} style={{ fontWeight: '700' }}>
151
- {row.name}
152
- {row.isApplicant ? (
153
- <MyazaText variant="bodySmall" color={colors.textMuted}>
154
- {' (you)'}
155
- </MyazaText>
156
- ) : null}
157
- </MyazaText>
158
- <View style={{ flexDirection: 'row', alignItems: 'center', flexWrap: 'wrap', marginTop: 2 }}>
159
- <MyazaText variant="bodySmall" color={colors.textMuted}>
160
- {ROLE_LABELS[row.role]}
161
- {row.pct ? ` · ${row.pct}%` : ''}
162
- {row.country ? ' · ' : ''}
163
- </MyazaText>
164
- {row.country ? (
165
- <>
166
- <CountryFlag country={row.country} size={14} />
167
- <MyazaText variant="bodySmall" color={colors.textMuted}>
168
- {` ${regionCountryName(row.country)}`}
169
- </MyazaText>
170
- </>
171
- ) : null}
172
- </View>
173
- </View>
174
- <View
175
- style={{
176
- borderRadius: radius.full,
177
- paddingHorizontal: spacing.sm + 4,
178
- paddingVertical: spacing.xs,
179
- backgroundColor: submitted ? colors.successBg : colors.primary100,
180
- }}
181
- >
182
- <MyazaText
183
- variant="bodySmall"
184
- color={submitted ? colors.success : colors.primary}
185
- style={{ fontWeight: '700', fontSize: 11, letterSpacing: 0.6 }}
186
- >
187
- {submitted ? 'SUBMITTED' : 'KYC PENDING'}
188
- </MyazaText>
189
- </View>
190
- </View>
191
-
192
- {row.status === 'pending' && row.inviteUrl ? (
193
- // Both actions, since it's mobile: Copy for pasting anywhere, Share
194
- // for the native sheet (WhatsApp/SMS directly).
195
- <View style={{ flexDirection: 'row', marginTop: spacing.sm + 4 }}>
196
- <Pressable
197
- onPress={copy}
198
- accessibilityRole="button"
199
- accessibilityLabel={`Copy ${row.name}'s verification link`}
200
- style={{
201
- flex: 1,
202
- flexDirection: 'row',
203
- alignItems: 'center',
204
- justifyContent: 'center',
205
- backgroundColor: colors.primary100,
206
- borderRadius: radius.full,
207
- paddingVertical: spacing.sm + 2,
208
- marginRight: spacing.sm,
209
- }}
210
- >
211
- <Icon name={copied ? 'check' : 'copy'} size={15} color={colors.primary} />
212
- <MyazaText variant="bodySmall" color={colors.primary} style={{ fontWeight: '700', marginLeft: spacing.xs + 2 }}>
213
- {copied ? 'Copied' : 'Copy link'}
214
- </MyazaText>
215
- </Pressable>
216
- <Pressable
217
- onPress={share}
218
- accessibilityRole="button"
219
- accessibilityLabel={`Share ${row.name}'s verification link`}
220
- style={{
221
- flex: 1,
222
- flexDirection: 'row',
223
- alignItems: 'center',
224
- justifyContent: 'center',
225
- backgroundColor: colors.primary100,
226
- borderRadius: radius.full,
227
- paddingVertical: spacing.sm + 2,
228
- }}
229
- >
230
- <Icon name="share" size={15} color={colors.primary} />
231
- <MyazaText variant="bodySmall" color={colors.primary} style={{ fontWeight: '700', marginLeft: spacing.xs + 2 }}>
232
- Share
233
- </MyazaText>
234
- </Pressable>
235
- </View>
236
- ) : null}
237
- </View>
238
- );
239
- }