@incodetech/web 2.0.0-alpha.1 → 2.0.0-alpha.11

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 (209) hide show
  1. package/dist/base.css +1071 -0
  2. package/dist/browser-ponyfill-B6W6hHVY.js +344 -0
  3. package/dist/email/email.es.js +145 -0
  4. package/dist/email/styles.css +123 -0
  5. package/dist/flow/flow.es.js +555 -0
  6. package/dist/flow/styles.css +1119 -0
  7. package/dist/incodeModule-Dv8Qllrv.js +254 -0
  8. package/dist/index.es.js +6 -0
  9. package/dist/instance-B-q0ZREN.js +2140 -0
  10. package/dist/otpInput-BtoZe0Wz.js +151 -0
  11. package/dist/page-Dh_Zw2ik.js +234 -0
  12. package/dist/phone/phone.es.js +3441 -0
  13. package/dist/phone/styles.css +305 -0
  14. package/dist/selfie/selfie.es.js +893 -0
  15. package/dist/selfie/styles.css +590 -0
  16. package/dist/selfieTutorial-C-u5GufD.js +29 -0
  17. package/dist/setup-wNL83jmW.js +20 -0
  18. package/dist/themes/dark.css +652 -0
  19. package/dist/themes/light.css +543 -0
  20. package/dist/title-BfO5Dlzk.js +25 -0
  21. package/dist/types/base.d.ts +1 -0
  22. package/dist/types/dark.d.ts +1 -0
  23. package/dist/types/email.d.ts +57 -0
  24. package/dist/types/flow.d.ts +69 -0
  25. package/dist/types/index.d.ts +38 -0
  26. package/dist/types/light.d.ts +1 -0
  27. package/dist/types/phone.d.ts +58 -0
  28. package/dist/types/selfie.d.ts +31 -0
  29. package/dist/types/styles.d.ts +1 -0
  30. package/dist/types/themes/dark.d.ts +1 -0
  31. package/dist/types/themes/light.d.ts +1 -0
  32. package/dist/uiConfig-CQ1W9cUD.js +23 -0
  33. package/dist/vendor-preact-CK0WeTOR.js +584 -0
  34. package/package.json +32 -26
  35. package/dev/README.md +0 -163
  36. package/dev/getToken.ts +0 -36
  37. package/dev/headless.html +0 -875
  38. package/dev/index.html +0 -366
  39. package/dev/main-headless.tsx +0 -1332
  40. package/dev/main-orchestrated-flow.tsx +0 -1158
  41. package/dev/main-preact.tsx +0 -323
  42. package/dev/main-simplified.tsx +0 -123
  43. package/dev/main-web-component.tsx +0 -256
  44. package/dev/main.tsx +0 -332
  45. package/dev/manual.html +0 -27
  46. package/dev/orchestrated-flow.html +0 -64
  47. package/dev/simplified.html +0 -64
  48. package/dev/tiktok-logo.svg +0 -7
  49. package/src/defineCustomElement.tsx +0 -30
  50. package/src/email/email.test.tsx +0 -368
  51. package/src/email/email.tsx +0 -255
  52. package/src/email/emailInput.test.tsx +0 -264
  53. package/src/email/emailInput.tsx +0 -85
  54. package/src/email/styles.css +0 -59
  55. package/src/flow/flow.test.tsx +0 -796
  56. package/src/flow/flow.tsx +0 -292
  57. package/src/flow/flowCompleted.css +0 -30
  58. package/src/flow/flowCompleted.test.tsx +0 -331
  59. package/src/flow/flowCompleted.tsx +0 -121
  60. package/src/flow/flowInit.test.ts +0 -264
  61. package/src/flow/flowInit.ts +0 -94
  62. package/src/flow/flowStart.css +0 -58
  63. package/src/flow/flowStart.test.tsx +0 -49
  64. package/src/flow/flowStart.tsx +0 -41
  65. package/src/flow/incode-logo.svg +0 -8
  66. package/src/flow/index.ts +0 -7
  67. package/src/flow/preloadFlow.test.ts +0 -421
  68. package/src/flow/preloadFlow.ts +0 -171
  69. package/src/flow/styles.css +0 -9
  70. package/src/flow/unsupportedModule.css +0 -21
  71. package/src/flow/unsupportedModule.tsx +0 -39
  72. package/src/flow/useFlowInitialization.test.tsx +0 -292
  73. package/src/flow/useFlowInitialization.ts +0 -128
  74. package/src/flow/useModuleLoader.test.tsx +0 -212
  75. package/src/flow/useModuleLoader.ts +0 -92
  76. package/src/hooks/index.ts +0 -1
  77. package/src/hooks/useManager.test.ts +0 -91
  78. package/src/hooks/useManager.ts +0 -40
  79. package/src/i18n/index.ts +0 -3
  80. package/src/i18n/instance.ts +0 -16
  81. package/src/i18n/setup.ts +0 -184
  82. package/src/i18n/useTranslation.ts +0 -42
  83. package/src/index.ts +0 -27
  84. package/src/permissions/assets/android-dots-icon.svg +0 -7
  85. package/src/permissions/assets/android-settings-icon.svg +0 -16
  86. package/src/permissions/assets/android-toggle-icon.svg +0 -20
  87. package/src/permissions/assets/bank-card-icon.svg +0 -14
  88. package/src/permissions/assets/camera-icon.svg +0 -12
  89. package/src/permissions/assets/camera-ios.svg +0 -53
  90. package/src/permissions/assets/check-icon.svg +0 -8
  91. package/src/permissions/assets/chrome-icon.svg +0 -43
  92. package/src/permissions/assets/password-icon.svg +0 -11
  93. package/src/permissions/assets/permissions-img.svg +0 -51
  94. package/src/permissions/assets/safari-icon.svg +0 -37
  95. package/src/permissions/assets/settings-icon.svg +0 -33
  96. package/src/permissions/assets/toggle-icon.svg +0 -19
  97. package/src/permissions/assets/warning-icon.svg +0 -6
  98. package/src/permissions/boldWithArrow.css +0 -9
  99. package/src/permissions/boldWithArrow.tsx +0 -41
  100. package/src/permissions/denied.css +0 -37
  101. package/src/permissions/denied.tsx +0 -29
  102. package/src/permissions/deniedAndroid.tsx +0 -56
  103. package/src/permissions/deniedDesktop.css +0 -9
  104. package/src/permissions/deniedDesktop.tsx +0 -64
  105. package/src/permissions/deniedIOS.tsx +0 -73
  106. package/src/permissions/deniedInstructions.tsx +0 -19
  107. package/src/permissions/iconWrapper.css +0 -9
  108. package/src/permissions/iconWrapper.tsx +0 -15
  109. package/src/permissions/learnMore.css +0 -37
  110. package/src/permissions/learnMore.tsx +0 -85
  111. package/src/permissions/numberedStep.css +0 -13
  112. package/src/permissions/numberedStep.tsx +0 -14
  113. package/src/permissions/permissions.css +0 -13
  114. package/src/permissions/permissions.tsx +0 -68
  115. package/src/phone/phone.tsx +0 -246
  116. package/src/phone/phoneInput.test.tsx +0 -275
  117. package/src/phone/phoneInput.tsx +0 -249
  118. package/src/phone/styles.css +0 -158
  119. package/src/selfie/cameraButton.css +0 -13
  120. package/src/selfie/cameraButton.tsx +0 -35
  121. package/src/selfie/capture.css +0 -57
  122. package/src/selfie/capture.tsx +0 -232
  123. package/src/selfie/errorModal.tsx +0 -218
  124. package/src/selfie/errorModalContent.css +0 -33
  125. package/src/selfie/errorModalContent.tsx +0 -44
  126. package/src/selfie/faceOutline.css +0 -5
  127. package/src/selfie/faceOutline.tsx +0 -22
  128. package/src/selfie/loadingBorder.css +0 -12
  129. package/src/selfie/loadingBorder.tsx +0 -77
  130. package/src/selfie/manualCaptureButton.css +0 -13
  131. package/src/selfie/manualCaptureButton.tsx +0 -35
  132. package/src/selfie/noMoreAttemptsModal.tsx +0 -44
  133. package/src/selfie/notification.css +0 -9
  134. package/src/selfie/notification.tsx +0 -36
  135. package/src/selfie/retryErrorModal.tsx +0 -56
  136. package/src/selfie/selfie.test.tsx +0 -458
  137. package/src/selfie/selfie.tsx +0 -83
  138. package/src/selfie/selfieTutorial.json +0 -2626
  139. package/src/selfie/styles.css +0 -1
  140. package/src/selfie/tutorial.test.tsx +0 -200
  141. package/src/selfie/tutorial.tsx +0 -43
  142. package/src/setup.ts +0 -33
  143. package/src/shared/baseTutorial/baseTutorial.css +0 -21
  144. package/src/shared/baseTutorial/baseTutorial.test.tsx +0 -184
  145. package/src/shared/baseTutorial/baseTutorial.tsx +0 -55
  146. package/src/shared/baseTutorial/replaceBaseTutorial.test.ts +0 -267
  147. package/src/shared/baseTutorial/replaceBaseTutorial.ts +0 -68
  148. package/src/shared/button/button.css +0 -55
  149. package/src/shared/button/button.test.tsx +0 -101
  150. package/src/shared/button/button.tsx +0 -47
  151. package/src/shared/componentRoot/incodeComponent.tsx +0 -12
  152. package/src/shared/countries/countries.test.ts +0 -75
  153. package/src/shared/countries/countries.ts +0 -139
  154. package/src/shared/countries/index.ts +0 -6
  155. package/src/shared/icons/chevronDown.tsx +0 -22
  156. package/src/shared/icons/index.ts +0 -2
  157. package/src/shared/icons/successIcon.css +0 -5
  158. package/src/shared/icons/successIcon.test.tsx +0 -40
  159. package/src/shared/icons/successIcon.tsx +0 -26
  160. package/src/shared/loader/loadingIcon.css +0 -28
  161. package/src/shared/loader/loadingIcon.tsx +0 -67
  162. package/src/shared/lottie/lottie.tsx +0 -108
  163. package/src/shared/otpInput/otpInput.css +0 -85
  164. package/src/shared/otpInput/otpInput.test.tsx +0 -356
  165. package/src/shared/otpInput/otpInput.tsx +0 -241
  166. package/src/shared/page/incode-logo.svg +0 -3
  167. package/src/shared/page/page.css +0 -47
  168. package/src/shared/page/page.test.tsx +0 -97
  169. package/src/shared/page/page.tsx +0 -91
  170. package/src/shared/page/pageUiConfig.test.ts +0 -112
  171. package/src/shared/page/pageUiConfig.ts +0 -64
  172. package/src/shared/page/verifiedByIncode.css +0 -5
  173. package/src/shared/page/verifiedByIncode.tsx +0 -75
  174. package/src/shared/spacer/spacer.css +0 -149
  175. package/src/shared/spacer/spacer.test.tsx +0 -143
  176. package/src/shared/spacer/spacer.tsx +0 -88
  177. package/src/shared/spinner/index.ts +0 -2
  178. package/src/shared/spinner/spinner.css +0 -28
  179. package/src/shared/spinner/spinner.test.tsx +0 -82
  180. package/src/shared/spinner/spinner.tsx +0 -65
  181. package/src/shared/title/title.css +0 -7
  182. package/src/shared/title/title.tsx +0 -12
  183. package/src/shared/uiConfig/uiConfig.ts +0 -36
  184. package/src/shared/webComponent/incodeModule.ts +0 -29
  185. package/src/shared/webComponent/registerIncodeElement.ts +0 -15
  186. package/src/styles/__mocks__/fetchTheme.ts +0 -19
  187. package/src/styles/applyTheme.ts +0 -37
  188. package/src/styles/cn.test.tsx +0 -57
  189. package/src/styles/cn.tsx +0 -21
  190. package/src/styles/core.css +0 -12
  191. package/src/styles/fetchTheme.test.ts +0 -390
  192. package/src/styles/fetchTheme.ts +0 -88
  193. package/src/styles/generatePalette.ts +0 -111
  194. package/src/styles/reset.css +0 -65
  195. package/src/styles/resolveCssVariableToHex.ts +0 -28
  196. package/src/styles/tailwind.css +0 -291
  197. package/src/styles/themeTypes.ts +0 -18
  198. package/src/styles/tokens/colors.css +0 -190
  199. package/src/styles/tokens/components.css +0 -174
  200. package/src/styles/tokens/index.css +0 -4
  201. package/src/styles/tokens/primitives.css +0 -129
  202. package/src/styles/tokens/semantic.css +0 -51
  203. package/src/svg.d.ts +0 -4
  204. package/src/types/assets.d.ts +0 -1
  205. package/src/types/custom-elements.d.ts +0 -104
  206. package/tsconfig.json +0 -22
  207. package/vite.config.ts +0 -260
  208. package/vitest.config.ts +0 -40
  209. package/vitest.setup.ts +0 -16
@@ -1,323 +0,0 @@
1
- import '../src/styles/tokens/index.css';
2
- import '../src/selfie/selfie';
3
- import { setup } from '@incodetech/core';
4
- import type { FlowModuleConfig } from '@incodetech/core/flow';
5
- import { createFlowManager } from '@incodetech/core/flow';
6
- import { createSelfieManager } from '@incodetech/core/selfie';
7
- import { render } from 'preact';
8
- import type { FC } from 'preact/compat';
9
- import { useEffect, useState } from 'preact/hooks';
10
- import { useManager } from '../src/hooks';
11
- import { getToken } from './getToken';
12
-
13
- type SelfieModuleProps = {
14
- config: FlowModuleConfig['SELFIE'];
15
- onFinish: () => void;
16
- };
17
-
18
- const SelfieModule: FC<SelfieModuleProps> = ({ config, onFinish }) => {
19
- const [state, selfieManager] = useManager(() =>
20
- createSelfieManager({ config }),
21
- );
22
- const [tutorialLoading, setTutorialLoading] = useState(false);
23
-
24
- useEffect(() => {
25
- if (state.status !== 'tutorial') {
26
- setTutorialLoading(false);
27
- }
28
- }, [state.status]);
29
-
30
- if (state.status === 'loading') {
31
- return <p>Loading...</p>;
32
- }
33
-
34
- if (state.status === 'tutorial') {
35
- return (
36
- <div>
37
- <h2>Selfie Tutorial</h2>
38
- <p>Position your face in the center</p>
39
- <button
40
- type="button"
41
- disabled={tutorialLoading}
42
- onClick={() => {
43
- setTutorialLoading(true);
44
- selfieManager.nextStep();
45
- }}
46
- >
47
- {tutorialLoading ? 'Loading...' : 'Continue'}
48
- </button>
49
- </div>
50
- );
51
- }
52
- if (state.status === 'permissions') {
53
- if (state.permissionStatus === 'idle') {
54
- return (
55
- <div>
56
- <h2>Camera Permission</h2>
57
- <p>We need access to your camera</p>
58
- <button
59
- type="button"
60
- onClick={() => selfieManager.requestPermission()}
61
- >
62
- Allow Camera
63
- </button>
64
- <button type="button" onClick={() => selfieManager.goToLearnMore()}>
65
- Learn More
66
- </button>
67
- </div>
68
- );
69
- }
70
-
71
- if (state.permissionStatus === 'requesting') {
72
- return <p>Requesting camera access...</p>;
73
- }
74
-
75
- if (state.permissionStatus === 'denied') {
76
- return (
77
- <div>
78
- <h2>Permission Denied</h2>
79
- <p>Camera access was denied</p>
80
- <button type="button" onClick={() => window.location.reload()}>
81
- Refresh Browser
82
- </button>
83
- </div>
84
- );
85
- }
86
-
87
- if (state.permissionStatus === 'learnMore') {
88
- return (
89
- <div>
90
- <h2>Why we need camera</h2>
91
- <p>To verify your identity</p>
92
- <button
93
- type="button"
94
- onClick={() => selfieManager.requestPermission()}
95
- >
96
- Allow Camera
97
- </button>
98
- <button type="button" onClick={() => selfieManager.back()}>
99
- Back
100
- </button>
101
- <button type="button" onClick={() => selfieManager.close()}>
102
- Quit
103
- </button>
104
- </div>
105
- );
106
- }
107
- }
108
-
109
- if (state.status === 'capture') {
110
- if (state.captureStatus === 'initializing') {
111
- return (
112
- <div>
113
- <h2>Initializing Camera</h2>
114
- <p>Please wait...</p>
115
- </div>
116
- );
117
- }
118
-
119
- if (state.captureStatus === 'detecting') {
120
- return (
121
- <div>
122
- <h2>Face Detection</h2>
123
- <p>
124
- Status: <strong>{state.detectionStatus}</strong>
125
- </p>
126
- <p>Attempts remaining: {state.attemptsRemaining}</p>
127
- {state.stream ? <Video stream={state.stream} /> : null}
128
- </div>
129
- );
130
- }
131
-
132
- if (state.captureStatus === 'capturing') {
133
- return (
134
- <div>
135
- <h2>Capturing</h2>
136
- <p>Taking photo...</p>
137
- </div>
138
- );
139
- }
140
-
141
- if (state.captureStatus === 'uploading') {
142
- return (
143
- <div>
144
- <h2>Uploading</h2>
145
- <p>Sending selfie to server...</p>
146
- </div>
147
- );
148
- }
149
-
150
- if (state.captureStatus === 'uploadError') {
151
- return (
152
- <div>
153
- <h2>Upload Failed</h2>
154
- <p>Error: {state.uploadError}</p>
155
- <p>Attempts remaining: {state.attemptsRemaining}</p>
156
- {state.attemptsRemaining > 0 ? (
157
- <button type="button" onClick={() => selfieManager.retryCapture()}>
158
- Retry
159
- </button>
160
- ) : (
161
- <>
162
- <p>
163
- <strong style={{ color: 'red' }}>
164
- No more attempts available!
165
- </strong>
166
- </p>
167
- <button type="button" onClick={onFinish}>
168
- Continue
169
- </button>
170
- </>
171
- )}
172
- </div>
173
- );
174
- }
175
-
176
- if (state.captureStatus === 'success') {
177
- return (
178
- <div>
179
- <h2>Success!</h2>
180
- <p>Selfie captured successfully!</p>
181
- </div>
182
- );
183
- }
184
- }
185
-
186
- if (state.status === 'finished') {
187
- onFinish();
188
- return <p>Selfie complete!</p>;
189
- }
190
-
191
- if (state.status === 'error') {
192
- if (state.error === 'PERMISSION_REFRESH') {
193
- window.location.reload();
194
- return null;
195
- }
196
- return (
197
- <div>
198
- <h2>Process Cancelled</h2>
199
- <p>You quit the selfie process</p>
200
- <button type="button" onClick={() => selfieManager.reset()}>
201
- Try Again
202
- </button>
203
- </div>
204
- );
205
- }
206
-
207
- return null;
208
- };
209
-
210
- type VideoProps = {
211
- stream: MediaStream;
212
- };
213
-
214
- const Video: FC<VideoProps> = ({ stream }) => {
215
- const [videoRef, setVideoRef] = useState<HTMLVideoElement | null>(null);
216
-
217
- useEffect(() => {
218
- if (videoRef && stream) {
219
- videoRef.srcObject = stream;
220
- }
221
- }, [videoRef, stream]);
222
-
223
- return (
224
- <video
225
- ref={setVideoRef}
226
- autoplay
227
- playsInline
228
- muted
229
- style={{
230
- width: '320px',
231
- height: '240px',
232
- transform: 'scaleX(-1)',
233
- display: 'block',
234
- marginTop: '16px',
235
- }}
236
- />
237
- );
238
- };
239
-
240
- const App: FC = () => {
241
- const [state, flowManager] = useManager(() => createFlowManager(), {
242
- autoLoad: false,
243
- });
244
-
245
- useEffect(() => {
246
- const init = async () => {
247
- const { token } = await getToken();
248
- setup({
249
- apiURL: 'https://user-service-k8s.stage.incodetest.com/0',
250
- token,
251
- });
252
- flowManager.load();
253
- };
254
- init();
255
- }, [flowManager]);
256
-
257
- if (state.status === 'loading') {
258
- return <p>Loading flow...</p>;
259
- }
260
-
261
- if (state.status === 'ready') {
262
- const { currentStep, config } = state;
263
-
264
- if (!currentStep) {
265
- return <p>No current step</p>;
266
- }
267
-
268
- if (currentStep === 'TUTORIAL_ID' || currentStep === 'ID') {
269
- return (
270
- <div>
271
- <h1>This is {currentStep}</h1>
272
- <p>Hi!</p>
273
- <button type="button" onClick={() => flowManager.nextStep()}>
274
- Continue
275
- </button>
276
- </div>
277
- );
278
- }
279
-
280
- if (currentStep === 'SELFIE') {
281
- const selfieConfig = config as FlowModuleConfig['SELFIE'];
282
- return (
283
- <div>
284
- <h1>Selfie Module</h1>
285
- <SelfieModule
286
- config={selfieConfig}
287
- onFinish={() => flowManager.nextStep()}
288
- />
289
- </div>
290
- );
291
- }
292
-
293
- return (
294
- <div>
295
- <h1>Unknown step</h1>
296
- <p>step: {currentStep}</p>
297
- <button type="button" onClick={() => flowManager.nextStep()}>
298
- Continue
299
- </button>
300
- </div>
301
- );
302
- }
303
-
304
- if (state.status === 'finished') {
305
- return (
306
- <div>
307
- <h1>Finished</h1>
308
- <p>Hi!</p>
309
- </div>
310
- );
311
- }
312
-
313
- if (state.status === 'error') {
314
- return <div>{state.error}</div>;
315
- }
316
-
317
- return null;
318
- };
319
-
320
- const root = document.getElementById('root');
321
- if (root) {
322
- render(<App />, root);
323
- }
@@ -1,123 +0,0 @@
1
- import {
2
- createSession,
3
- initializeWasmUtil,
4
- setup,
5
- setWasmConfig,
6
- type WasmConfig,
7
- } from '@incodetech/core';
8
- import '../src/styles/tokens/index.css';
9
- import '../src/styles/reset.css';
10
- import '../src/flow/flow'; // Registers <incode-flow> web component
11
- import '../src/flow/flowCompleted'; // Registers <incode-flow-completed> web component
12
- import '../src/flow/styles.css';
13
- import '../src/phone/styles.css';
14
- import '../src/types/custom-elements'; // Enables typed DOM access for custom elements
15
- import { getConfigIdFromUrl } from './getToken';
16
-
17
- const API_URL = 'https://user-service-k8s.stage.incodetest.com/0';
18
- const API_KEY = '5fbc0ab5a652b7808fbec42fffd8b4c9ec248413';
19
-
20
- const WASM_CONFIG: WasmConfig = {
21
- wasmPath:
22
- 'https://d3vv997wtl2myz.cloudfront.net/webcamera/onnx-backend-wasm/v2.12.47/webLib.wasm',
23
- wasmSimdPath:
24
- 'https://d3vv997wtl2myz.cloudfront.net/webcamera/onnx-backend-wasm/v2.12.47/webLibSimd.wasm',
25
- glueCodePath:
26
- 'https://d3vv997wtl2myz.cloudfront.net/webcamera/onnx-backend-wasm/v2.12.47/webLib.js',
27
- modelsBasePath:
28
- 'https://d3vv997wtl2myz.cloudfront.net/webcamera/onnx-backend-wasm/v2.12.47/models',
29
- // pipelines will be determined by flow analysis
30
- };
31
-
32
- const root = document.getElementById('root');
33
- if (root) {
34
- const initializeFlow = async () => {
35
- try {
36
- // Setup SDK with API URL first (required before createSession)
37
- await setup({ apiURL: API_URL });
38
-
39
- // Create session externally
40
- const configurationId = getConfigIdFromUrl();
41
- const session = await createSession(API_KEY, {
42
- configurationId,
43
- language: 'en-US',
44
- });
45
-
46
- // Setup WASM
47
- const wasmConfig = {
48
- ...WASM_CONFIG,
49
- pipelines: ['selfie'],
50
- } as WasmConfig;
51
- console.log('WASM_CONFIG', wasmConfig);
52
- setWasmConfig(wasmConfig);
53
- await initializeWasmUtil(wasmConfig);
54
-
55
- // Create element - automatically typed via HTMLElementTagNameMap augmentation
56
- const flowElement = document.createElement('incode-flow');
57
- flowElement.id = 'flow';
58
-
59
- // Set all properties BEFORE appending to DOM
60
- flowElement.apiURL = API_URL;
61
- flowElement.token = session.token;
62
- flowElement.wasmConfig = WASM_CONFIG;
63
- flowElement.lang = 'en-US';
64
-
65
- // Configure the loading spinner (optional customization)
66
- // By default, IncodeFlow shows:
67
- // - Initialization: "Setting Up"
68
- // - Between modules: "Hang On" / "Validating"
69
- // You can override with custom text:
70
- // flowElement.spinnerConfig = {
71
- // title: 'Verifying your identity',
72
- // subtitle: 'This will only take a moment...',
73
- // size: 'medium',
74
- // };
75
-
76
- const startTime = performance.now();
77
-
78
- flowElement.onComplete = (result) => {
79
- const totalTime = performance.now() - startTime;
80
- console.log(
81
- `[Lazy Load] Flow complete in ${totalTime.toFixed(0)}ms`,
82
- result,
83
- );
84
-
85
- // Remove the flow element and show the completed screen
86
- flowElement.remove();
87
-
88
- // Create and show the flow-completed component
89
- const completedElement = document.createElement(
90
- 'incode-flow-completed',
91
- );
92
- completedElement.setAttribute('action', result.action);
93
- completedElement.setAttribute('score-status', result.scoreStatus);
94
- if (result.redirectionUrl) {
95
- completedElement.setAttribute(
96
- 'redirection-url',
97
- result.redirectionUrl,
98
- );
99
- completedElement.setAttribute('redirect-delay', '5000');
100
- }
101
- root.appendChild(completedElement);
102
- };
103
- flowElement.onError = (error) => {
104
- console.error('[Lazy Load] Flow error:', error);
105
- alert(`Flow error: ${error}`);
106
- };
107
-
108
- console.log(
109
- '[Lazy Load] Demo initialized - watch Network tab for chunk loading',
110
- );
111
-
112
- // Now append to DOM - component will mount with all props set
113
- root.appendChild(flowElement);
114
- } catch (error) {
115
- console.error('[Lazy Load] Failed to initialize:', error);
116
- alert(
117
- `Failed to initialize: ${error instanceof Error ? error.message : 'Unknown error'}`,
118
- );
119
- }
120
- };
121
-
122
- initializeFlow();
123
- }
@@ -1,256 +0,0 @@
1
- import '../src/styles/tokens/index.css';
2
- import '../src/selfie/selfie';
3
- import '../src/selfie/styles.css';
4
- import '../src/phone/phone';
5
- import '../src/phone/styles.css';
6
- import '../src/email/email';
7
- import '../src/email/styles.css';
8
- import type { FlowModuleConfig } from '@incodetech/core/flow';
9
- import { createFlowManager } from '@incodetech/core/flow';
10
- import { render } from 'preact';
11
- import type { FC } from 'preact/compat';
12
- import { useEffect, useRef, useState } from 'preact/hooks';
13
- import { useManager } from '../src/hooks';
14
- import { setup } from '../src/setup';
15
- import { getToken } from './getToken';
16
-
17
- declare module 'preact' {
18
- namespace JSX {
19
- interface IntrinsicElements {
20
- 'incode-selfie': preact.JSX.HTMLAttributes<HTMLElement>;
21
- 'incode-phone': preact.JSX.HTMLAttributes<HTMLElement>;
22
- 'incode-email': preact.JSX.HTMLAttributes<HTMLElement>;
23
- }
24
- }
25
- }
26
-
27
- type SelfieElement = HTMLElement & {
28
- config: FlowModuleConfig['SELFIE'];
29
- onFinish: () => void;
30
- onError: (error: string | undefined) => void;
31
- };
32
-
33
- type SelfieWebComponentProps = {
34
- config: FlowModuleConfig['SELFIE'];
35
- onFinish: () => void;
36
- onError: (error: string | undefined) => void;
37
- };
38
-
39
- const SelfieWebComponent: FC<SelfieWebComponentProps> = ({
40
- config,
41
- onFinish,
42
- onError,
43
- }) => {
44
- const ref = useRef<SelfieElement>(null);
45
-
46
- useEffect(() => {
47
- if (ref.current) {
48
- ref.current.config = config;
49
- ref.current.onFinish = onFinish;
50
- ref.current.onError = onError;
51
- }
52
- }, [config, onFinish, onError]);
53
-
54
- return <incode-selfie ref={ref} />;
55
- };
56
-
57
- type PhoneElement = HTMLElement & {
58
- config: FlowModuleConfig['PHONE'];
59
- onFinish: () => void;
60
- onError: (error: string | undefined) => void;
61
- };
62
-
63
- const PhoneWebComponent: FC<{
64
- config: FlowModuleConfig['PHONE'];
65
- onFinish: () => void;
66
- onError: (error: string | undefined) => void;
67
- }> = ({ config, onFinish, onError }) => {
68
- const ref = useRef<PhoneElement>(null);
69
-
70
- useEffect(() => {
71
- if (ref.current) {
72
- ref.current.config = config;
73
- ref.current.onFinish = onFinish;
74
- ref.current.onError = onError;
75
- }
76
- }, [config, onFinish, onError]);
77
-
78
- return <incode-phone ref={ref} />;
79
- };
80
-
81
- type EmailConfig = {
82
- otpVerification: boolean;
83
- otpExpirationInMinutes: number;
84
- prefill: boolean;
85
- maxOtpAttempts?: number;
86
- };
87
-
88
- type EmailElement = HTMLElement & {
89
- config: EmailConfig;
90
- onFinish: () => void;
91
- onError: (error: string | undefined) => void;
92
- };
93
-
94
- const EmailWebComponent: FC<{
95
- config: FlowModuleConfig['EMAIL'];
96
- onFinish: () => void;
97
- onError: (error: string | undefined) => void;
98
- }> = ({ config, onFinish, onError }) => {
99
- const ref = useRef<EmailElement>(null);
100
- const [isReady, setIsReady] = useState(false);
101
-
102
- useEffect(() => {
103
- if (ref.current && !isReady) {
104
- // Map FlowModuleConfig['EMAIL'] to full EmailConfig
105
- ref.current.config = {
106
- ...config,
107
- prefill: false,
108
- maxOtpAttempts: 3,
109
- };
110
- ref.current.onFinish = onFinish;
111
- ref.current.onError = onError;
112
- // Trigger re-render to pick up the config
113
- setIsReady(true);
114
- }
115
- }, [config, onFinish, onError, isReady]);
116
-
117
- return <incode-email ref={ref} />;
118
- };
119
-
120
- const App: FC = () => {
121
- const [state, flowManager] = useManager(() => createFlowManager(), {
122
- autoLoad: false,
123
- });
124
-
125
- useEffect(() => {
126
- const init = async () => {
127
- const { token } = await getToken();
128
- await setup({
129
- apiURL: 'https://user-service-k8s.stage.incodetest.com/0',
130
- token,
131
- wasm: {
132
- wasmPath:
133
- 'https://d3vv997wtl2myz.cloudfront.net/webcamera/onnx-backend-wasm/v2.12.47/webLib.wasm',
134
- wasmSimdPath:
135
- 'https://d3vv997wtl2myz.cloudfront.net/webcamera/onnx-backend-wasm/v2.12.47/webLibSimd.wasm',
136
- glueCodePath:
137
- 'https://d3vv997wtl2myz.cloudfront.net/webcamera/onnx-backend-wasm/v2.12.47/webLib.js',
138
- modelsBasePath:
139
- 'https://d3vv997wtl2myz.cloudfront.net/webcamera/onnx-backend-wasm/v2.12.47/models',
140
- pipelines: ['selfie'],
141
- },
142
- i18n: {
143
- lang: 'en',
144
- },
145
- });
146
- flowManager.load();
147
- };
148
- init();
149
- }, [flowManager]);
150
-
151
- if (state.status === 'loading') {
152
- return <p>Loading flow...</p>;
153
- }
154
-
155
- if (state.status === 'ready') {
156
- const { currentStep, config } = state;
157
-
158
- if (!currentStep) {
159
- return <p>No current step</p>;
160
- }
161
-
162
- if (currentStep === 'TUTORIAL_ID' || currentStep === 'ID') {
163
- return (
164
- <div>
165
- <h1>This is {currentStep}</h1>
166
- <p>Hi!</p>
167
- <button type="button" onClick={() => flowManager.nextStep()}>
168
- Continue
169
- </button>
170
- </div>
171
- );
172
- }
173
-
174
- if (currentStep === 'SELFIE') {
175
- const selfieConfig = config as FlowModuleConfig['SELFIE'];
176
- return (
177
- <div style={{ width: '100%', height: '100%' }}>
178
- <SelfieWebComponent
179
- config={selfieConfig}
180
- onFinish={() => flowManager.nextStep()}
181
- onError={(error) => {
182
- console.error('Selfie error:', error);
183
- if (error === 'PERMISSION_REFRESH') {
184
- window.location.reload();
185
- return;
186
- }
187
- alert(`Selfie error: ${error}`);
188
- }}
189
- />
190
- </div>
191
- );
192
- }
193
-
194
- if (currentStep === 'PHONE') {
195
- const phoneConfig = config as FlowModuleConfig['PHONE'];
196
- return (
197
- <div style={{ width: '100%', height: '100%' }}>
198
- <PhoneWebComponent
199
- config={phoneConfig}
200
- onFinish={() => flowManager.nextStep()}
201
- onError={(error) => {
202
- console.error('Phone error:', error);
203
- alert(`Phone error: ${error}`);
204
- }}
205
- />
206
- </div>
207
- );
208
- }
209
-
210
- if (currentStep === 'EMAIL') {
211
- const emailConfig = config as FlowModuleConfig['EMAIL'];
212
- return (
213
- <div style={{ width: '100%', height: '100%' }}>
214
- <EmailWebComponent
215
- config={emailConfig}
216
- onFinish={() => flowManager.nextStep()}
217
- onError={(error) => {
218
- console.error('Email error:', error);
219
- alert(`Email error: ${error}`);
220
- }}
221
- />
222
- </div>
223
- );
224
- }
225
-
226
- return (
227
- <div>
228
- <h1>Unknown step</h1>
229
- <p>step: {currentStep}</p>
230
- <button type="button" onClick={() => flowManager.nextStep()}>
231
- Continue
232
- </button>
233
- </div>
234
- );
235
- }
236
-
237
- if (state.status === 'finished') {
238
- return (
239
- <div>
240
- <h1>Finished</h1>
241
- <p>Hi!</p>
242
- </div>
243
- );
244
- }
245
-
246
- if (state.status === 'error') {
247
- return <div>{state.error}</div>;
248
- }
249
-
250
- return null;
251
- };
252
-
253
- const root = document.getElementById('root');
254
- if (root) {
255
- render(<App />, root);
256
- }