@incodetech/web 2.0.0-alpha.1 → 2.0.0-alpha.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.
Files changed (212) hide show
  1. package/dist/asset-manifest.json +18 -0
  2. package/dist/browser-ponyfill-B6W6hHVY.js +344 -0
  3. package/dist/button-DeMZ_34N.js +266 -0
  4. package/dist/button.css +335 -0
  5. package/dist/email/email.es.js +145 -0
  6. package/dist/email/styles.css +123 -0
  7. package/dist/flow/flow.es.js +9 -0
  8. package/dist/flow/styles.css +204 -0
  9. package/dist/flow-ZK6OBsa3.js +568 -0
  10. package/dist/incodeModule-BF5MX9GT.js +243 -0
  11. package/dist/incodeModule.css +119 -0
  12. package/dist/index.es.js +101 -0
  13. package/dist/otpInput-BUrV4IAF.js +151 -0
  14. package/dist/otpInput.css +167 -0
  15. package/dist/phone/phone.es.js +3442 -0
  16. package/dist/phone/styles.css +305 -0
  17. package/dist/selfie/selfie.es.js +893 -0
  18. package/dist/selfie/styles.css +1163 -0
  19. package/dist/selfieTutorial-C-u5GufD.js +29 -0
  20. package/dist/styles/core.css +1013 -0
  21. package/dist/styles/tokens.css +543 -0
  22. package/dist/successIcon.css +4 -0
  23. package/dist/title-ng7q7YDh.js +2161 -0
  24. package/dist/title.css +38 -0
  25. package/dist/types/core.d.ts +1 -0
  26. package/dist/types/email/email.d.ts +2 -0
  27. package/dist/types/email.d.ts +50 -0
  28. package/dist/types/flow/flow.d.ts +2 -0
  29. package/dist/types/flow.d.ts +46 -0
  30. package/dist/types/index.d.ts +223 -0
  31. package/dist/types/phone/phone.d.ts +2 -0
  32. package/dist/types/phone.d.ts +51 -0
  33. package/dist/types/selfie/selfie.d.ts +2 -0
  34. package/dist/types/selfie.d.ts +24 -0
  35. package/dist/types/styles/core.d.ts +1 -0
  36. package/dist/vendor-preact-CK0WeTOR.js +584 -0
  37. package/package.json +20 -17
  38. package/dev/README.md +0 -163
  39. package/dev/getToken.ts +0 -36
  40. package/dev/headless.html +0 -875
  41. package/dev/index.html +0 -366
  42. package/dev/main-headless.tsx +0 -1332
  43. package/dev/main-orchestrated-flow.tsx +0 -1158
  44. package/dev/main-preact.tsx +0 -323
  45. package/dev/main-simplified.tsx +0 -123
  46. package/dev/main-web-component.tsx +0 -256
  47. package/dev/main.tsx +0 -332
  48. package/dev/manual.html +0 -27
  49. package/dev/orchestrated-flow.html +0 -64
  50. package/dev/simplified.html +0 -64
  51. package/dev/tiktok-logo.svg +0 -7
  52. package/src/defineCustomElement.tsx +0 -30
  53. package/src/email/email.test.tsx +0 -368
  54. package/src/email/email.tsx +0 -255
  55. package/src/email/emailInput.test.tsx +0 -264
  56. package/src/email/emailInput.tsx +0 -85
  57. package/src/email/styles.css +0 -59
  58. package/src/flow/flow.test.tsx +0 -796
  59. package/src/flow/flow.tsx +0 -292
  60. package/src/flow/flowCompleted.css +0 -30
  61. package/src/flow/flowCompleted.test.tsx +0 -331
  62. package/src/flow/flowCompleted.tsx +0 -121
  63. package/src/flow/flowInit.test.ts +0 -264
  64. package/src/flow/flowInit.ts +0 -94
  65. package/src/flow/flowStart.css +0 -58
  66. package/src/flow/flowStart.test.tsx +0 -49
  67. package/src/flow/flowStart.tsx +0 -41
  68. package/src/flow/incode-logo.svg +0 -8
  69. package/src/flow/index.ts +0 -7
  70. package/src/flow/preloadFlow.test.ts +0 -421
  71. package/src/flow/preloadFlow.ts +0 -171
  72. package/src/flow/styles.css +0 -9
  73. package/src/flow/unsupportedModule.css +0 -21
  74. package/src/flow/unsupportedModule.tsx +0 -39
  75. package/src/flow/useFlowInitialization.test.tsx +0 -292
  76. package/src/flow/useFlowInitialization.ts +0 -128
  77. package/src/flow/useModuleLoader.test.tsx +0 -212
  78. package/src/flow/useModuleLoader.ts +0 -92
  79. package/src/hooks/index.ts +0 -1
  80. package/src/hooks/useManager.test.ts +0 -91
  81. package/src/hooks/useManager.ts +0 -40
  82. package/src/i18n/index.ts +0 -3
  83. package/src/i18n/instance.ts +0 -16
  84. package/src/i18n/setup.ts +0 -184
  85. package/src/i18n/useTranslation.ts +0 -42
  86. package/src/index.ts +0 -27
  87. package/src/permissions/assets/android-dots-icon.svg +0 -7
  88. package/src/permissions/assets/android-settings-icon.svg +0 -16
  89. package/src/permissions/assets/android-toggle-icon.svg +0 -20
  90. package/src/permissions/assets/bank-card-icon.svg +0 -14
  91. package/src/permissions/assets/camera-icon.svg +0 -12
  92. package/src/permissions/assets/camera-ios.svg +0 -53
  93. package/src/permissions/assets/check-icon.svg +0 -8
  94. package/src/permissions/assets/chrome-icon.svg +0 -43
  95. package/src/permissions/assets/password-icon.svg +0 -11
  96. package/src/permissions/assets/permissions-img.svg +0 -51
  97. package/src/permissions/assets/safari-icon.svg +0 -37
  98. package/src/permissions/assets/settings-icon.svg +0 -33
  99. package/src/permissions/assets/toggle-icon.svg +0 -19
  100. package/src/permissions/assets/warning-icon.svg +0 -6
  101. package/src/permissions/boldWithArrow.css +0 -9
  102. package/src/permissions/boldWithArrow.tsx +0 -41
  103. package/src/permissions/denied.css +0 -37
  104. package/src/permissions/denied.tsx +0 -29
  105. package/src/permissions/deniedAndroid.tsx +0 -56
  106. package/src/permissions/deniedDesktop.css +0 -9
  107. package/src/permissions/deniedDesktop.tsx +0 -64
  108. package/src/permissions/deniedIOS.tsx +0 -73
  109. package/src/permissions/deniedInstructions.tsx +0 -19
  110. package/src/permissions/iconWrapper.css +0 -9
  111. package/src/permissions/iconWrapper.tsx +0 -15
  112. package/src/permissions/learnMore.css +0 -37
  113. package/src/permissions/learnMore.tsx +0 -85
  114. package/src/permissions/numberedStep.css +0 -13
  115. package/src/permissions/numberedStep.tsx +0 -14
  116. package/src/permissions/permissions.css +0 -13
  117. package/src/permissions/permissions.tsx +0 -68
  118. package/src/phone/phone.tsx +0 -246
  119. package/src/phone/phoneInput.test.tsx +0 -275
  120. package/src/phone/phoneInput.tsx +0 -249
  121. package/src/phone/styles.css +0 -158
  122. package/src/selfie/cameraButton.css +0 -13
  123. package/src/selfie/cameraButton.tsx +0 -35
  124. package/src/selfie/capture.css +0 -57
  125. package/src/selfie/capture.tsx +0 -232
  126. package/src/selfie/errorModal.tsx +0 -218
  127. package/src/selfie/errorModalContent.css +0 -33
  128. package/src/selfie/errorModalContent.tsx +0 -44
  129. package/src/selfie/faceOutline.css +0 -5
  130. package/src/selfie/faceOutline.tsx +0 -22
  131. package/src/selfie/loadingBorder.css +0 -12
  132. package/src/selfie/loadingBorder.tsx +0 -77
  133. package/src/selfie/manualCaptureButton.css +0 -13
  134. package/src/selfie/manualCaptureButton.tsx +0 -35
  135. package/src/selfie/noMoreAttemptsModal.tsx +0 -44
  136. package/src/selfie/notification.css +0 -9
  137. package/src/selfie/notification.tsx +0 -36
  138. package/src/selfie/retryErrorModal.tsx +0 -56
  139. package/src/selfie/selfie.test.tsx +0 -458
  140. package/src/selfie/selfie.tsx +0 -83
  141. package/src/selfie/selfieTutorial.json +0 -2626
  142. package/src/selfie/styles.css +0 -1
  143. package/src/selfie/tutorial.test.tsx +0 -200
  144. package/src/selfie/tutorial.tsx +0 -43
  145. package/src/setup.ts +0 -33
  146. package/src/shared/baseTutorial/baseTutorial.css +0 -21
  147. package/src/shared/baseTutorial/baseTutorial.test.tsx +0 -184
  148. package/src/shared/baseTutorial/baseTutorial.tsx +0 -55
  149. package/src/shared/baseTutorial/replaceBaseTutorial.test.ts +0 -267
  150. package/src/shared/baseTutorial/replaceBaseTutorial.ts +0 -68
  151. package/src/shared/button/button.css +0 -55
  152. package/src/shared/button/button.test.tsx +0 -101
  153. package/src/shared/button/button.tsx +0 -47
  154. package/src/shared/componentRoot/incodeComponent.tsx +0 -12
  155. package/src/shared/countries/countries.test.ts +0 -75
  156. package/src/shared/countries/countries.ts +0 -139
  157. package/src/shared/countries/index.ts +0 -6
  158. package/src/shared/icons/chevronDown.tsx +0 -22
  159. package/src/shared/icons/index.ts +0 -2
  160. package/src/shared/icons/successIcon.css +0 -5
  161. package/src/shared/icons/successIcon.test.tsx +0 -40
  162. package/src/shared/icons/successIcon.tsx +0 -26
  163. package/src/shared/loader/loadingIcon.css +0 -28
  164. package/src/shared/loader/loadingIcon.tsx +0 -67
  165. package/src/shared/lottie/lottie.tsx +0 -108
  166. package/src/shared/otpInput/otpInput.css +0 -85
  167. package/src/shared/otpInput/otpInput.test.tsx +0 -356
  168. package/src/shared/otpInput/otpInput.tsx +0 -241
  169. package/src/shared/page/incode-logo.svg +0 -3
  170. package/src/shared/page/page.css +0 -47
  171. package/src/shared/page/page.test.tsx +0 -97
  172. package/src/shared/page/page.tsx +0 -91
  173. package/src/shared/page/pageUiConfig.test.ts +0 -112
  174. package/src/shared/page/pageUiConfig.ts +0 -64
  175. package/src/shared/page/verifiedByIncode.css +0 -5
  176. package/src/shared/page/verifiedByIncode.tsx +0 -75
  177. package/src/shared/spacer/spacer.css +0 -149
  178. package/src/shared/spacer/spacer.test.tsx +0 -143
  179. package/src/shared/spacer/spacer.tsx +0 -88
  180. package/src/shared/spinner/index.ts +0 -2
  181. package/src/shared/spinner/spinner.css +0 -28
  182. package/src/shared/spinner/spinner.test.tsx +0 -82
  183. package/src/shared/spinner/spinner.tsx +0 -65
  184. package/src/shared/title/title.css +0 -7
  185. package/src/shared/title/title.tsx +0 -12
  186. package/src/shared/uiConfig/uiConfig.ts +0 -36
  187. package/src/shared/webComponent/incodeModule.ts +0 -29
  188. package/src/shared/webComponent/registerIncodeElement.ts +0 -15
  189. package/src/styles/__mocks__/fetchTheme.ts +0 -19
  190. package/src/styles/applyTheme.ts +0 -37
  191. package/src/styles/cn.test.tsx +0 -57
  192. package/src/styles/cn.tsx +0 -21
  193. package/src/styles/core.css +0 -12
  194. package/src/styles/fetchTheme.test.ts +0 -390
  195. package/src/styles/fetchTheme.ts +0 -88
  196. package/src/styles/generatePalette.ts +0 -111
  197. package/src/styles/reset.css +0 -65
  198. package/src/styles/resolveCssVariableToHex.ts +0 -28
  199. package/src/styles/tailwind.css +0 -291
  200. package/src/styles/themeTypes.ts +0 -18
  201. package/src/styles/tokens/colors.css +0 -190
  202. package/src/styles/tokens/components.css +0 -174
  203. package/src/styles/tokens/index.css +0 -4
  204. package/src/styles/tokens/primitives.css +0 -129
  205. package/src/styles/tokens/semantic.css +0 -51
  206. package/src/svg.d.ts +0 -4
  207. package/src/types/assets.d.ts +0 -1
  208. package/src/types/custom-elements.d.ts +0 -104
  209. package/tsconfig.json +0 -22
  210. package/vite.config.ts +0 -260
  211. package/vitest.config.ts +0 -40
  212. 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
- }