@opexa/portal-components 0.0.242 → 0.0.244
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/hooks/useCamera.d.ts +6 -1
- package/dist/client/hooks/useCamera.js +70 -16
- package/dist/client/hooks/useFeatureFlag.d.ts +18 -5
- package/dist/client/hooks/useFeatureFlag.js +44 -11
- package/dist/components/KYC/AutoOpen.js +8 -3
- package/dist/components/PortalProvider/FeatureFlag.d.ts +1 -0
- package/dist/components/PortalProvider/FeatureFlag.js +34 -0
- package/dist/components/PortalProvider/PortalProvider.js +2 -1
- package/dist/components/SignIn/MobileNumberSignIn.js +4 -2
- package/dist/components/SignIn/NameAndPasswordSignIn.js +3 -2
- package/dist/components/SignUp/SignUpForm.js +1 -2
- package/dist/components/shared/IdDocumentField.js +18 -27
- package/dist/components/shared/SelfieField.d.ts +1 -3
- package/dist/components/shared/SelfieField.js +119 -123
- package/dist/constants/StorageKey.d.ts +1 -0
- package/dist/constants/StorageKey.js +1 -0
- package/dist/services/httpRequest.js +25 -4
- package/dist/ui/DatePicker/DatePicker.d.ts +72 -72
- package/dist/ui/DatePicker/datePicker.recipe.d.ts +3 -3
- package/package.json +9 -13
- package/dist/components/KYC/backup/Header.d.ts +0 -1
- package/dist/components/KYC/backup/Header.js +0 -8
- package/dist/components/KYC/backup/Indicator.d.ts +0 -1
- package/dist/components/KYC/backup/Indicator.js +0 -9
- package/dist/components/KYC/backup/KYC.d.ts +0 -1
- package/dist/components/KYC/backup/KYC.js +0 -14
- package/dist/components/KYC/backup/KYC.lazy.d.ts +0 -1
- package/dist/components/KYC/backup/KYC.lazy.js +0 -26
- package/dist/components/KYC/backup/KYCContext.d.ts +0 -6
- package/dist/components/KYC/backup/KYCContext.js +0 -2
- package/dist/components/KYC/backup/Step1.d.ts +0 -1
- package/dist/components/KYC/backup/Step1.js +0 -13
- package/dist/components/KYC/backup/Step2.d.ts +0 -1
- package/dist/components/KYC/backup/Step2.js +0 -13
- package/dist/components/KYC/backup/Step3.d.ts +0 -1
- package/dist/components/KYC/backup/Step3.js +0 -13
- package/dist/components/KYC/backup/Step4.d.ts +0 -1
- package/dist/components/KYC/backup/Step4.js +0 -7
- package/dist/components/KYC/backup/useKYC.d.ts +0 -10
- package/dist/components/KYC/backup/useKYC.js +0 -8
- package/dist/components/KYC/loadModels.d.ts +0 -1
- package/dist/components/KYC/loadModels.js +0 -9
- package/dist/components/Messages/Message.d.ts +0 -1
- package/dist/components/Messages/Message.js +0 -35
- package/dist/components/Messages/MessageContext.d.ts +0 -6
- package/dist/components/Messages/MessageContext.js +0 -2
- package/dist/components/Messages/MessagePopup.d.ts +0 -1
- package/dist/components/Messages/MessagePopup.js +0 -20
- package/dist/components/Messages/MessageTrigger.d.ts +0 -8
- package/dist/components/Messages/MessageTrigger.js +0 -19
- package/dist/components/Quests/CountdownTimer.d.ts +0 -15
- package/dist/components/Quests/CountdownTimer.js +0 -33
- package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuest.d.ts +0 -4
- package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuest.js +0 -78
- package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuestModal.d.ts +0 -8
- package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuestModal.js +0 -9
- package/dist/components/Quests/OnboardingQuest/OnboardingQuest.d.ts +0 -4
- package/dist/components/Quests/OnboardingQuest/OnboardingQuest.js +0 -4
- package/dist/components/Quests/WageringQuest/WageringQuest.d.ts +0 -4
- package/dist/components/Quests/WageringQuest/WageringQuest.js +0 -20
- package/dist/components/Quests/WageringQuest/WageringQuestModal.d.ts +0 -9
- package/dist/components/Quests/WageringQuest/WageringQuestModal.js +0 -9
- package/dist/constants/BranchCode.d.ts +0 -4
- package/dist/constants/BranchCode.js +0 -42
- package/dist/icons/BellRingIcon.d.ts +0 -2
- package/dist/icons/BellRingIcon.js +0 -4
- package/dist/utils/dataUrlToBlob.d.ts +0 -1
- package/dist/utils/dataUrlToBlob.js +0 -11
- package/dist/utils/resizeImageSize.d.ts +0 -2
- package/dist/utils/resizeImageSize.js +0 -11
|
@@ -7,6 +7,7 @@ export interface CameraError<T extends string = never> {
|
|
|
7
7
|
export interface CameraData {
|
|
8
8
|
url: string;
|
|
9
9
|
file: File;
|
|
10
|
+
image: HTMLImageElement;
|
|
10
11
|
}
|
|
11
12
|
export interface CameraCropPoints {
|
|
12
13
|
x: number;
|
|
@@ -29,11 +30,15 @@ export interface UseCameraReturn<T extends string = never> {
|
|
|
29
30
|
data: CameraData | null;
|
|
30
31
|
error: CameraError<T> | null;
|
|
31
32
|
loading: boolean;
|
|
33
|
+
snapping: boolean;
|
|
32
34
|
videoRef: React.RefObject<HTMLVideoElement | null>;
|
|
33
35
|
videoProps: ComponentPropsWithRef<'video'>;
|
|
34
36
|
}
|
|
37
|
+
export interface CameraTransformData extends CameraData {
|
|
38
|
+
canvas: HTMLCanvasElement;
|
|
39
|
+
}
|
|
35
40
|
export interface UseCameraOptions<T extends string = never> extends MediaStreamConstraints {
|
|
36
|
-
transform?(data:
|
|
41
|
+
transform?(data: CameraTransformData): CameraData | Promise<CameraData>;
|
|
37
42
|
validate?(data: CameraData): CameraError<T> | void | null | undefined | Promise<CameraError<T> | void | null | undefined>;
|
|
38
43
|
}
|
|
39
44
|
export declare function useCamera<T extends string = never>(options?: UseCameraOptions<T>): UseCameraReturn<T>;
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { isBoolean, isFunction, isObject } from 'lodash-es';
|
|
2
|
-
import { useCallback, useMemo, useRef, useState, } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
|
|
3
3
|
import invariant from 'tiny-invariant';
|
|
4
|
+
import { useMediaQuery } from 'usehooks-ts';
|
|
4
5
|
export function useCamera(options = {}) {
|
|
5
6
|
const { transform, validate, ...constraints } = options;
|
|
6
7
|
const videoRef = useRef(null);
|
|
7
|
-
const
|
|
8
|
+
const streamRef = useRef(null);
|
|
8
9
|
const [data, setData] = useState(null);
|
|
9
10
|
const [error, setError] = useState(null);
|
|
10
11
|
const [loading, setLoading] = useState(false);
|
|
12
|
+
const [snapping, setSnapping] = useState(false);
|
|
13
|
+
const desktop = useMediaQuery('(min-width: 1024px)');
|
|
11
14
|
const [mirror, setMirror] = useState(false);
|
|
12
15
|
const open = useCallback(async () => {
|
|
13
16
|
setData(null);
|
|
@@ -31,16 +34,24 @@ export function useCamera(options = {}) {
|
|
|
31
34
|
video: {
|
|
32
35
|
facingMode: 'user',
|
|
33
36
|
noiseSuppression: true,
|
|
37
|
+
width: {
|
|
38
|
+
ideal: 9999,
|
|
39
|
+
},
|
|
40
|
+
height: {
|
|
41
|
+
ideal: 9999,
|
|
42
|
+
},
|
|
43
|
+
aspectRatio: {
|
|
44
|
+
exact: desktop ? 16 / 9 : 4 / 3,
|
|
45
|
+
},
|
|
34
46
|
frameRate: {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
ideal: 30,
|
|
47
|
+
max: 120,
|
|
48
|
+
ideal: 90,
|
|
38
49
|
},
|
|
39
50
|
...(isBoolean(constraints.video) ? {} : constraints.video),
|
|
40
51
|
},
|
|
41
52
|
});
|
|
42
53
|
node.srcObject = result;
|
|
43
|
-
|
|
54
|
+
streamRef.current = result;
|
|
44
55
|
setMirror(!isObject(constraints.video)
|
|
45
56
|
? true
|
|
46
57
|
: constraints.video.facingMode === 'environment'
|
|
@@ -74,12 +85,14 @@ export function useCamera(options = {}) {
|
|
|
74
85
|
finally {
|
|
75
86
|
setLoading(false);
|
|
76
87
|
}
|
|
77
|
-
}, [constraints,
|
|
88
|
+
}, [constraints, desktop]);
|
|
78
89
|
const close = useCallback(() => {
|
|
79
90
|
setData(null);
|
|
80
91
|
setError(null);
|
|
92
|
+
setLoading(false);
|
|
93
|
+
setSnapping(false);
|
|
81
94
|
return new Promise((resolve) => {
|
|
82
|
-
|
|
95
|
+
streamRef.current?.getTracks().forEach((track) => track.stop());
|
|
83
96
|
videoRef.current?.pause();
|
|
84
97
|
resolve();
|
|
85
98
|
});
|
|
@@ -87,6 +100,7 @@ export function useCamera(options = {}) {
|
|
|
87
100
|
const snap = useCallback(async (opts = {}) => {
|
|
88
101
|
setData(null);
|
|
89
102
|
setError(null);
|
|
103
|
+
setSnapping(true);
|
|
90
104
|
const video = videoRef.current;
|
|
91
105
|
const canvas = document.createElement('canvas');
|
|
92
106
|
const context = canvas.getContext('2d');
|
|
@@ -98,12 +112,18 @@ export function useCamera(options = {}) {
|
|
|
98
112
|
const hdResolution = video.videoWidth >= 1280 && video.videoHeight >= 720;
|
|
99
113
|
const highResolution = video.videoWidth >= 1920 && video.videoHeight >= 1080;
|
|
100
114
|
const scaleFactor = lowResolution
|
|
101
|
-
? (opts.scale ?? 2)
|
|
115
|
+
? (opts.scale ?? (opts.crop ? 2.15 : 2))
|
|
102
116
|
: highResolution
|
|
103
|
-
?
|
|
117
|
+
? opts.crop
|
|
118
|
+
? 1.25
|
|
119
|
+
: 1.15
|
|
104
120
|
: hdResolution
|
|
105
|
-
?
|
|
106
|
-
|
|
121
|
+
? opts.crop
|
|
122
|
+
? 1.5
|
|
123
|
+
: 1.25
|
|
124
|
+
: opts.crop
|
|
125
|
+
? 1.5
|
|
126
|
+
: 2;
|
|
107
127
|
let x = 0;
|
|
108
128
|
let y = 0;
|
|
109
129
|
let w = video.videoWidth;
|
|
@@ -127,6 +147,7 @@ export function useCamera(options = {}) {
|
|
|
127
147
|
context.drawImage(video, x, y, w, h, 0, 0, w * scaleFactor, h * scaleFactor);
|
|
128
148
|
canvas.toBlob(async (blob) => {
|
|
129
149
|
if (!blob) {
|
|
150
|
+
setSnapping(false);
|
|
130
151
|
return setError({
|
|
131
152
|
name: 'CameraError',
|
|
132
153
|
message: "'canvas.toBlob' failed to create blob",
|
|
@@ -138,21 +159,46 @@ export function useCamera(options = {}) {
|
|
|
138
159
|
endings: 'native',
|
|
139
160
|
lastModified: Date.now(),
|
|
140
161
|
});
|
|
141
|
-
const
|
|
162
|
+
const image = new Image();
|
|
163
|
+
image.src = url;
|
|
164
|
+
image.alt = '';
|
|
165
|
+
image.width = canvas.width;
|
|
166
|
+
image.height = canvas.height;
|
|
167
|
+
if (!image.complete || image.naturalWidth === 0) {
|
|
168
|
+
await new Promise((resolve, reject) => {
|
|
169
|
+
image.onload = () => resolve();
|
|
170
|
+
image.onerror = () => reject();
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
const data = isFunction(transform)
|
|
174
|
+
? await transform({
|
|
175
|
+
url,
|
|
176
|
+
file,
|
|
177
|
+
image,
|
|
178
|
+
canvas,
|
|
179
|
+
})
|
|
180
|
+
: {
|
|
181
|
+
url,
|
|
182
|
+
file,
|
|
183
|
+
image,
|
|
184
|
+
};
|
|
142
185
|
const error = await validate?.(data);
|
|
143
186
|
if (error)
|
|
144
187
|
setError(error);
|
|
145
188
|
else
|
|
146
|
-
setData(
|
|
189
|
+
setData(data);
|
|
190
|
+
setSnapping(false);
|
|
147
191
|
}, 'image/jpeg', 1);
|
|
148
192
|
}, [mirror, transform, validate]);
|
|
149
193
|
const reset = useCallback(() => {
|
|
150
194
|
setData(null);
|
|
151
195
|
setError(null);
|
|
152
196
|
setLoading(false);
|
|
197
|
+
setSnapping(false);
|
|
153
198
|
return Promise.resolve();
|
|
154
199
|
}, [setData, setError]);
|
|
155
200
|
const reopen = useCallback(async () => {
|
|
201
|
+
setSnapping(false);
|
|
156
202
|
setLoading(true);
|
|
157
203
|
close();
|
|
158
204
|
await sleep();
|
|
@@ -171,11 +217,18 @@ export function useCamera(options = {}) {
|
|
|
171
217
|
position: 'relative',
|
|
172
218
|
boxSizing: 'border-box',
|
|
173
219
|
background: 'transparent',
|
|
174
|
-
objectFit: 'cover',
|
|
175
|
-
objectPosition: 'center',
|
|
176
220
|
transform: mirror ? 'scaleX(-1)' : 'none',
|
|
221
|
+
pointerEvents: 'none',
|
|
177
222
|
},
|
|
178
223
|
}), [mirror]);
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
return () => {
|
|
226
|
+
setData(null);
|
|
227
|
+
setError(null);
|
|
228
|
+
setLoading(false);
|
|
229
|
+
setSnapping(false);
|
|
230
|
+
};
|
|
231
|
+
}, []);
|
|
179
232
|
return {
|
|
180
233
|
snap,
|
|
181
234
|
open,
|
|
@@ -185,6 +238,7 @@ export function useCamera(options = {}) {
|
|
|
185
238
|
data,
|
|
186
239
|
error,
|
|
187
240
|
loading,
|
|
241
|
+
snapping,
|
|
188
242
|
videoRef,
|
|
189
243
|
videoProps,
|
|
190
244
|
};
|
|
@@ -1,5 +1,18 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
1
|
+
export interface UseFeatureFlagReturn {
|
|
2
|
+
enabled: boolean;
|
|
3
|
+
enable(): Promise<void>;
|
|
4
|
+
disable(): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export declare function useFeatureFlag(): UseFeatureFlagReturn;
|
|
7
|
+
interface EventsMap {
|
|
8
|
+
'web-portal::feature-flag-enabled': CustomEvent;
|
|
9
|
+
'web-portal::feature-flag-disabled': CustomEvent;
|
|
10
|
+
}
|
|
11
|
+
type Listener<K extends keyof EventsMap> = (this: Window, event: EventsMap[K]) => void;
|
|
12
|
+
declare global {
|
|
13
|
+
interface Window {
|
|
14
|
+
addEventListener<T extends keyof EventsMap>(type: T, listener: Listener<T>): void;
|
|
15
|
+
removeEventListener<K extends keyof EventsMap>(type: K, listener: Listener<K>): void;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
@@ -1,16 +1,49 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
const
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { FEATURE_FLAG_LOCAL_STORAGE_KEY } from '../../constants/index.js';
|
|
3
|
+
export function useFeatureFlag() {
|
|
4
|
+
const [enabled, setEnabled] = useState(false);
|
|
5
|
+
const enable = useCallback(() => {
|
|
6
|
+
return new Promise((resolve) => {
|
|
7
|
+
localStorage.setItem(FEATURE_FLAG_LOCAL_STORAGE_KEY, '');
|
|
8
|
+
window.dispatchEvent(FEATURE_FLAG_ENABLED_EVENT);
|
|
9
|
+
resolve();
|
|
10
|
+
});
|
|
11
|
+
}, []);
|
|
12
|
+
const disable = useCallback(() => {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
localStorage.removeItem(FEATURE_FLAG_LOCAL_STORAGE_KEY);
|
|
15
|
+
window.dispatchEvent(FEATURE_FLAG_DISABLED_EVENT);
|
|
16
|
+
resolve();
|
|
17
|
+
});
|
|
18
|
+
}, []);
|
|
6
19
|
useEffect(() => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
20
|
+
setEnabled(localStorage.getItem(FEATURE_FLAG_LOCAL_STORAGE_KEY) != null);
|
|
21
|
+
}, []);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
function handleEnabled() {
|
|
24
|
+
setEnabled(true);
|
|
25
|
+
}
|
|
26
|
+
function handleDisabled() {
|
|
27
|
+
setEnabled(false);
|
|
10
28
|
}
|
|
29
|
+
window.addEventListener('web-portal::feature-flag-enabled', handleEnabled);
|
|
30
|
+
window.addEventListener('web-portal::feature-flag-disabled', handleDisabled);
|
|
31
|
+
return () => {
|
|
32
|
+
window.removeEventListener('web-portal::feature-flag-enabled', handleEnabled);
|
|
33
|
+
window.removeEventListener('web-portal::feature-flag-disabled', handleDisabled);
|
|
34
|
+
};
|
|
11
35
|
}, []);
|
|
12
36
|
return {
|
|
13
|
-
|
|
14
|
-
|
|
37
|
+
enabled,
|
|
38
|
+
enable,
|
|
39
|
+
disable,
|
|
15
40
|
};
|
|
16
|
-
}
|
|
41
|
+
}
|
|
42
|
+
const FEATURE_FLAG_DISABLED_EVENT = new CustomEvent('web-portal::feature-flag-disabled', {
|
|
43
|
+
bubbles: true,
|
|
44
|
+
cancelable: false,
|
|
45
|
+
});
|
|
46
|
+
const FEATURE_FLAG_ENABLED_EVENT = new CustomEvent('web-portal::feature-flag-enabled', {
|
|
47
|
+
bubbles: true,
|
|
48
|
+
cancelable: false,
|
|
49
|
+
});
|
|
@@ -22,12 +22,17 @@ export function AutoOpen() {
|
|
|
22
22
|
: isUploadCompleted
|
|
23
23
|
? 3
|
|
24
24
|
: 2;
|
|
25
|
-
const shouldOpen = !
|
|
25
|
+
const shouldOpen = !account?.realName ||
|
|
26
|
+
!account?.birthDay ||
|
|
27
|
+
!verification ||
|
|
28
|
+
verification.status === 'REJECTED' ||
|
|
29
|
+
verification.status === 'UNVERIFIED';
|
|
26
30
|
useEffect(() => {
|
|
27
31
|
if (session?.status == 'authenticated' &&
|
|
32
|
+
!kycStore['~touched'] &&
|
|
28
33
|
shouldOpen &&
|
|
29
|
-
localStorage.getItem(KYC_PROMPT_LOCALSTORAGE_KEY)
|
|
30
|
-
kycStore.
|
|
34
|
+
localStorage.getItem(KYC_PROMPT_LOCALSTORAGE_KEY) == null) {
|
|
35
|
+
kycStore.setOpen(true);
|
|
31
36
|
return;
|
|
32
37
|
}
|
|
33
38
|
}, [kycStore, session?.status, shouldOpen]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function FeatureFlag(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
|
4
|
+
import { useCallback, useEffect } from 'react';
|
|
5
|
+
import { useFeatureFlag } from '../../client/hooks/useFeatureFlag.js';
|
|
6
|
+
import { Portal } from '../../ui/Portal/index.js';
|
|
7
|
+
import { Presence } from '../../ui/Presence/index.js';
|
|
8
|
+
export function FeatureFlag() {
|
|
9
|
+
const router = useRouter();
|
|
10
|
+
const pathname = usePathname();
|
|
11
|
+
const searchParams = useSearchParams();
|
|
12
|
+
const featureFlag = useFeatureFlag();
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (searchParams.has('future')) {
|
|
15
|
+
featureFlag.enable();
|
|
16
|
+
}
|
|
17
|
+
}, [featureFlag, searchParams]);
|
|
18
|
+
const removeFutureParam = useCallback(() => {
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
if (!searchParams.has('future'))
|
|
21
|
+
return resolve();
|
|
22
|
+
const newSearchParams = new URLSearchParams(searchParams);
|
|
23
|
+
newSearchParams.delete('future');
|
|
24
|
+
router.replace(`${pathname}?${newSearchParams.toString()}`, {
|
|
25
|
+
scroll: false,
|
|
26
|
+
});
|
|
27
|
+
setTimeout(resolve, 250);
|
|
28
|
+
});
|
|
29
|
+
}, [pathname, router, searchParams]);
|
|
30
|
+
return (_jsx(Portal, { children: _jsx(Presence, { present: featureFlag.enabled, asChild: true, children: _jsx("div", { className: "fixed bottom-3 flex w-full flex-col items-center justify-center", children: _jsxs("div", { className: "rounded-full bg-black/50 px-2 py-1 text-sm leading-none backdrop-blur-md", children: ["Experimental features are enabled.", ' ', _jsx("button", { type: "button", className: "cursor-pointer underline underline-offset-2", onClick: async () => {
|
|
31
|
+
await removeFutureParam();
|
|
32
|
+
await featureFlag.disable();
|
|
33
|
+
}, children: "Disable" })] }) }) }) }));
|
|
34
|
+
}
|
|
@@ -9,6 +9,7 @@ import { prefetchSessionQuery } from '../../server/utils/prefetchSessionQuery.js
|
|
|
9
9
|
import { prefetchWalletQuery } from '../../server/utils/prefetchWalletQuery.js';
|
|
10
10
|
import { FacebookPixel, GoogleRecaptcha } from '../../third-parties/index.js';
|
|
11
11
|
import { getQueryClient } from '../../utils/getQueryClient.js';
|
|
12
|
+
import { FeatureFlag } from './FeatureFlag.js';
|
|
12
13
|
import { Providers } from './Providers.js';
|
|
13
14
|
import { SetupDomain } from './SetupDomain.js';
|
|
14
15
|
import { Snackbar } from './Snackbar.js';
|
|
@@ -21,5 +22,5 @@ export async function PortalProvider({ children, facebookPixelId, googleAnalytic
|
|
|
21
22
|
prefetchAccountQuery(),
|
|
22
23
|
prefetchWalletQuery(),
|
|
23
24
|
]);
|
|
24
|
-
return (_jsxs(_Fragment, { children: [INTERNALS__REPORT_WEB_VITALS && _jsx(WebVitals, {}), _jsx(Providers, { children: _jsxs(HydrationBoundary, { state: dehydrate(queryClient), children: [children, _jsx(Suspense, { fallback: null, children: _jsx(SetupDomain, {}) })] }) }), _jsx(Snackbar, {}), facebookPixelId && _jsx(FacebookPixel, { fbId: facebookPixelId }), googleAnalyticsId && _jsx(GoogleAnalytics, { gaId: googleAnalyticsId }), googleTagManagerId && _jsx(GoogleTagManager, { gtmId: googleTagManagerId }), googleRecaptchaSiteKey && (_jsx(GoogleRecaptcha, { siteKey: googleRecaptchaSiteKey }))] }));
|
|
25
|
+
return (_jsxs(_Fragment, { children: [INTERNALS__REPORT_WEB_VITALS && _jsx(WebVitals, {}), _jsx(Providers, { children: _jsxs(HydrationBoundary, { state: dehydrate(queryClient), children: [children, _jsx(Suspense, { fallback: null, children: _jsx(SetupDomain, {}) })] }) }), _jsx(Snackbar, {}), _jsx(Suspense, { fallback: null, children: _jsx(FeatureFlag, {}) }), facebookPixelId && _jsx(FacebookPixel, { fbId: facebookPixelId }), googleAnalyticsId && _jsx(GoogleAnalytics, { gaId: googleAnalyticsId }), googleTagManagerId && _jsx(GoogleTagManager, { gtmId: googleTagManagerId }), googleRecaptchaSiteKey && (_jsx(GoogleRecaptcha, { siteKey: googleRecaptchaSiteKey }))] }));
|
|
25
26
|
}
|
|
@@ -121,9 +121,11 @@ export function MobileNumberSignIn() {
|
|
|
121
121
|
globalStore.signIn.setOpen(false);
|
|
122
122
|
globalStore.kycReminder.setOpen(true);
|
|
123
123
|
}
|
|
124
|
-
catch {
|
|
124
|
+
catch (err) {
|
|
125
125
|
toaster.error({
|
|
126
|
-
description:
|
|
126
|
+
description: err instanceof Error
|
|
127
|
+
? err.message
|
|
128
|
+
: 'Invalid Verification Code',
|
|
127
129
|
});
|
|
128
130
|
}
|
|
129
131
|
}), children: [_jsx(Controller, { name: "verificationCode", control: step2Form.control, render: (o) => (_jsxs(Field.Root, { invalid: o.fieldState.invalid, children: [_jsxs(PinInput.Root, { placeholder: "0", value: o.field.value, onValueChange: (details) => {
|
|
@@ -41,9 +41,10 @@ export function NameAndPasswordSignIn() {
|
|
|
41
41
|
form.reset();
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
|
-
onError() {
|
|
44
|
+
onError(err) {
|
|
45
45
|
toaster.error({
|
|
46
|
-
description:
|
|
46
|
+
description: err.message ||
|
|
47
|
+
'An error occurred while signing in. Please try again.',
|
|
47
48
|
});
|
|
48
49
|
},
|
|
49
50
|
});
|
|
@@ -192,7 +192,6 @@ export function SignUpForm() {
|
|
|
192
192
|
mobileNumber: mobileNumberParser.format(mobileNumber),
|
|
193
193
|
verificationCode: verificationCode.join(''),
|
|
194
194
|
referralCode: search.get('referralCode') ?? undefined,
|
|
195
|
-
domain: search.get('domain') ?? undefined,
|
|
196
195
|
btag: search.get('btag') ?? undefined,
|
|
197
196
|
});
|
|
198
197
|
const name = mobileNumberParser.format(mobileNumber);
|
|
@@ -252,7 +251,7 @@ export function SignUpForm() {
|
|
|
252
251
|
o.field.onChange(details.value);
|
|
253
252
|
}, onValueComplete: () => {
|
|
254
253
|
form2Ref.current?.requestSubmit();
|
|
255
|
-
}, children: [_jsxs(PinInput.Control, { className: "grid-cols-[1fr_1fr_1fr_auto_1fr_1fr_1fr] items-center gap-md", children: [_jsx(PinInput.Input, { index: 0 }), _jsx(PinInput.Input, { index: 1 }), _jsx(PinInput.Input, { index: 2 }), _jsx("span", { className: "text-text-placeholder-subtle text-2xl font-medium", children: "\u2013" }), _jsx(PinInput.Input, { index: 3 }), _jsx(PinInput.Input, { index: 4 }), _jsx(PinInput.Input, { index: 5 })] }), _jsx(PinInput.HiddenInput, {})] }), _jsx(Field.ErrorText, { children: o.formState.errors.verificationCode?.message })] })) }), _jsx(Button, { type: "submit", className: "mt-4xl", disabled: step2Form.formState.isSubmitting, children: "Verify" }), _jsxs("div", { className: "mt-3 flex w-full items-center justify-center gap-xs text-sm", children: [_jsx("span", { className: "text-text-secondary-700", children: "Didn't recieve the code?" }), _jsx("button", { type: "button", className: "text-button-secondary-fg font-semibold disabled:cursor-not-allowed disabled:opacity-75", disabled: cooldown.cooling, onClick: async () => {
|
|
254
|
+
}, blurOnComplete: true, readOnly: step2Form.formState.isSubmitting, type: "numeric", children: [_jsxs(PinInput.Control, { className: "grid-cols-[1fr_1fr_1fr_auto_1fr_1fr_1fr] items-center gap-md", children: [_jsx(PinInput.Input, { index: 0 }), _jsx(PinInput.Input, { index: 1 }), _jsx(PinInput.Input, { index: 2 }), _jsx("span", { className: "text-text-placeholder-subtle text-2xl font-medium", children: "\u2013" }), _jsx(PinInput.Input, { index: 3 }), _jsx(PinInput.Input, { index: 4 }), _jsx(PinInput.Input, { index: 5 })] }), _jsx(PinInput.HiddenInput, {})] }), _jsx(Field.ErrorText, { children: o.formState.errors.verificationCode?.message })] })) }), _jsx(Button, { type: "submit", className: "mt-4xl", disabled: step2Form.formState.isSubmitting, children: "Verify" }), _jsxs("div", { className: "mt-3 flex w-full items-center justify-center gap-xs text-sm", children: [_jsx("span", { className: "text-text-secondary-700", children: "Didn't recieve the code?" }), _jsx("button", { type: "button", className: "text-button-secondary-fg font-semibold disabled:cursor-not-allowed disabled:opacity-75", disabled: cooldown.cooling, onClick: async () => {
|
|
256
255
|
await sendVerificationCodeMutation.mutateAsync({
|
|
257
256
|
channel: 'SMS',
|
|
258
257
|
recipient: mobileNumberParser.format(step1Form.getValues('mobileNumber')),
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useFieldContext } from '@ark-ui/react';
|
|
4
4
|
import Image from 'next/image';
|
|
5
|
-
import {
|
|
5
|
+
import { useEffect, useId, useRef, useState, } from 'react';
|
|
6
6
|
import { twMerge } from 'tailwind-merge';
|
|
7
7
|
import { useMediaQuery } from 'usehooks-ts';
|
|
8
8
|
import { useCamera } from '../../client/hooks/useCamera.js';
|
|
@@ -72,41 +72,30 @@ function Camera() {
|
|
|
72
72
|
const context = useIdDocumentFieldContext();
|
|
73
73
|
return (_jsx(Dialog.Root, { open: context.disclosure.open, onOpenChange: (details) => {
|
|
74
74
|
context.disclosure.setOpen(details.open);
|
|
75
|
-
}, onExitComplete: context.camera.close, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, { className: "!z-[calc(var(--z-dialog)+1)]" }), _jsx(Dialog.Positioner, { className: "!z-[calc(var(--z-dialog)+2)] flex items-center justify-center overflow-y-auto py-4", children: _jsxs(Dialog.Content, { className: "bg-bg-primary-alt mx-auto w-[calc(100dvw-1rem)] max-w-[calc(100dvw-1rem)] overflow-y-auto rounded-lg px-4 py-5 lg:w-[747px] lg:max-w-[747px] lg:px-3xl lg:py-4xl", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsx(Dialog.Title, { className: "text-center font-semibold lg:text-xl", children: "Take a Picture of Your Front ID" }), _jsxs(Dialog.Description, { className: "text-text-tertiary-600 mt-md text-center text-xs lg:text-base", children: ["Make sure your ID is clearly visible, well-lit, and not blurry.", ' ', _jsx("br", { className: "hidden lg:block" }), "Avoid glare or reflections, and ensure all corners are within\u00A0the\u00A0frame."] }), _jsxs("div", { className: "relative mt-5 lg:mt-10 lg:px-3xl", children: [_jsxs("div", { className:
|
|
76
|
-
!context.camera.error &&
|
|
77
|
-
!context.camera.loading
|
|
78
|
-
? 'block'
|
|
79
|
-
: 'hidden'), children: [_jsx("video", { ...context.camera.videoProps }), _jsx(Mask, {})] }), context.camera.error && (_jsxs("div", { className: "border-border-disabled flex aspect-[85.60/53.98] flex-col items-center justify-center rounded-md border bg-black px-4 lg:rounded-lg", children: [_jsx(CameraOffIcon, { className: "text-text-placeholder-subtle size-10 text-center lg:size-12" }), _jsx("h2", { className: "mt-3 text-sm font-semibold lg:mt-4 lg:text-base", children: context.camera.error.name }), _jsx("p", { className: "text-text-tertiary-600 mt-0.5 text-center text-xs lg:mt-1 lg:text-sm", children: context.camera.error.message }), _jsx(Button, { size: "xs", variant: "outline", colorScheme: "gray", fullWidth: false, className: "mt-4 lg:mt-5", onClick: () => {
|
|
75
|
+
}, closeOnEscape: false, closeOnInteractOutside: false, onExitComplete: context.camera.close, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, { className: "!z-[calc(var(--z-dialog)+1)]" }), _jsx(Dialog.Positioner, { className: "!z-[calc(var(--z-dialog)+2)] flex items-center justify-center overflow-y-auto py-4", children: _jsxs(Dialog.Content, { className: "bg-bg-primary-alt mx-auto w-[calc(100dvw-1rem)] max-w-[calc(100dvw-1rem)] overflow-y-auto rounded-lg px-4 py-5 lg:w-[747px] lg:max-w-[747px] lg:px-3xl lg:py-4xl", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsx(Dialog.Title, { className: "text-center font-semibold lg:text-xl", children: "Take a Picture of Your Front ID" }), _jsxs(Dialog.Description, { className: "text-text-tertiary-600 mt-md text-center text-xs lg:text-base", children: ["Make sure your ID is clearly visible, well-lit, and not blurry.", ' ', _jsx("br", { className: "hidden lg:block" }), "Avoid glare or reflections, and ensure all corners are within\u00A0the\u00A0frame."] }), _jsxs("div", { className: "relative mt-5 lg:mt-10 lg:px-3xl", children: [_jsx(Video, {}), context.camera.error && (_jsxs("div", { className: "border-border-disabled flex aspect-[4/3] flex-col items-center justify-center rounded-md border bg-black px-4 lg:aspect-video", children: [_jsx(CameraOffIcon, { className: "text-text-placeholder-subtle size-10 text-center lg:size-12" }), _jsx("h2", { className: "mt-3 text-sm font-semibold lg:mt-4 lg:text-base", children: context.camera.error.name }), _jsx("p", { className: "text-text-tertiary-600 mt-0.5 text-center text-xs lg:mt-1 lg:text-sm", children: context.camera.error.message }), _jsx(Button, { size: "xs", variant: "outline", colorScheme: "gray", fullWidth: false, className: "mt-4 lg:mt-5", onClick: () => {
|
|
80
76
|
context.camera.reopen();
|
|
81
|
-
}, children: "Try again" })] })), context.camera.loading && (_jsx("div", { className: "border-border-disabled flex aspect-[
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
y: rect.y,
|
|
89
|
-
x: rect.x,
|
|
90
|
-
width: rect.width,
|
|
91
|
-
height: rect.height,
|
|
92
|
-
};
|
|
93
|
-
context.camera.snap({ crop });
|
|
94
|
-
}, children: [_jsx(Camera01Icon, { className: "size-5" }), "Capture"] }) })), context.camera.data && (_jsxs("div", { className: "mt-5 flex gap-3 lg:mt-10", children: [_jsxs(Button, { onClick: () => {
|
|
77
|
+
}, children: "Try again" })] })), context.camera.loading && (_jsx("div", { className: "border-border-disabled flex aspect-[4/3] flex-col items-center justify-center rounded-md border bg-black px-4 lg:aspect-video", children: _jsx(Spinner02Icon, { className: "text-text-placeholder size-8" }) })), context.camera.data && (_jsx("div", { className: "border-border-disabled aspect-[4/3] w-full overflow-hidden rounded-md border bg-black lg:aspect-video", children: _jsx(Image, { src: context.camera.data.url, alt: "", width: 600, height: 378.08, unoptimized: true, className: "mx-auto mt-2 block h-[calc(100%-1rem)] w-auto" }) }))] }), !context.camera.data && (_jsx("div", { className: "mt-5 lg:mt-10", children: _jsxs(Button, { className: "disabled:bg-bg-disabled disabled:text-text-disabled mx-auto w-full px-xl py-lg lg:w-[10rem]", onClick: () => {
|
|
78
|
+
context.camera.snap({
|
|
79
|
+
crop: context.guideRef.current?.getBoundingClientRect(),
|
|
80
|
+
});
|
|
81
|
+
}, disabled: context.camera.snapping ||
|
|
82
|
+
context.camera.loading ||
|
|
83
|
+
!!context.camera.error, children: [context.camera.snapping ? (_jsx(Spinner02Icon, { className: "size-5" })) : (_jsx(Camera01Icon, { className: "size-5" })), "Capture"] }) })), context.camera.data && (_jsxs("div", { className: "mt-5 flex gap-3 lg:mt-10 lg:justify-center", children: [_jsxs(Button, { onClick: () => {
|
|
95
84
|
const file = context.camera.data?.file;
|
|
96
85
|
if (!file)
|
|
97
86
|
return;
|
|
98
87
|
context.mutation.mutate({ file });
|
|
99
88
|
context.disclosure.setOpen(false);
|
|
100
|
-
}, children: [_jsx(CheckCircleIcon, { className: "size-5" }), "Use Photo"] }), _jsxs(Button, { variant: "outline", colorScheme: "gray", onClick: () => {
|
|
89
|
+
}, className: "w-full lg:w-[10rem]", children: [_jsx(CheckCircleIcon, { className: "size-5" }), "Use Photo"] }), _jsxs(Button, { variant: "outline", colorScheme: "gray", onClick: () => {
|
|
101
90
|
context.camera.reset();
|
|
102
|
-
}, children: [_jsx(RefreshCcw01Icon, { className: "size-5" }), " Retake"] })] }))] }) })] }) }));
|
|
91
|
+
}, className: "w-full lg:w-[10rem]", children: [_jsx(RefreshCcw01Icon, { className: "size-5" }), " Retake"] })] }))] }) })] }) }));
|
|
103
92
|
}
|
|
104
93
|
/**
|
|
105
94
|
* -------------------------------------
|
|
106
|
-
*
|
|
95
|
+
* Video
|
|
107
96
|
* -------------------------------------
|
|
108
97
|
*/
|
|
109
|
-
function
|
|
98
|
+
function Video() {
|
|
110
99
|
const id = useId();
|
|
111
100
|
const context = useIdDocumentFieldContext();
|
|
112
101
|
const [maskBox, setMaskBox] = useState({
|
|
@@ -115,7 +104,7 @@ function Mask() {
|
|
|
115
104
|
width: 0,
|
|
116
105
|
height: 0,
|
|
117
106
|
});
|
|
118
|
-
|
|
107
|
+
useEffect(() => {
|
|
119
108
|
const update = () => {
|
|
120
109
|
const guide = context.guideRef.current;
|
|
121
110
|
const mask = context.maskRef.current;
|
|
@@ -144,7 +133,9 @@ function Mask() {
|
|
|
144
133
|
requestAnimationFrame(update);
|
|
145
134
|
return () => observer.disconnect();
|
|
146
135
|
}, [context.guideRef, context.maskRef]);
|
|
147
|
-
return (_jsxs(
|
|
136
|
+
return (_jsxs("div", { className: twMerge('relative h-auto w-full overflow-hidden', !context.camera.data && !context.camera.error && !context.camera.loading
|
|
137
|
+
? 'block'
|
|
138
|
+
: 'hidden'), children: [_jsx("video", { ...context.camera.videoProps }), _jsx("svg", { className: "pointer-events-none absolute -inset-4 size-[200%]", children: _jsx("defs", { children: _jsxs("mask", { id: id, maskUnits: "userSpaceOnUse", children: [_jsx("rect", { x: "0", y: "0", width: "200%", height: "200%", fill: "white" }), _jsx("rect", { x: maskBox.x, y: maskBox.y, width: maskBox.width, height: maskBox.height, fill: "black", rx: "8", ry: "8" })] }) }) }), _jsx("div", { ref: context.maskRef, className: "absolute -inset-4 size-[200%] bg-black/60 backdrop-blur-sm", style: {
|
|
148
139
|
mask: `url(#${id})`,
|
|
149
140
|
WebkitMask: `url(#${id})`,
|
|
150
141
|
maskRepeat: 'no-repeat',
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import '@mediapipe/face_detection';
|
|
2
|
-
import '@tensorflow/tfjs-backend-webgl';
|
|
3
|
-
import '@tensorflow/tfjs-core';
|
|
4
1
|
import { type CSSProperties, type RefObject } from 'react';
|
|
5
2
|
import { type ValidateFileError } from '../../utils/validateFile';
|
|
6
3
|
export interface SelfieFieldProps extends UseSelfieFieldProps {
|
|
@@ -20,4 +17,5 @@ interface UseSelfieFieldProps {
|
|
|
20
17
|
onChange?: (value: string) => void;
|
|
21
18
|
defaultValue?: string;
|
|
22
19
|
}
|
|
20
|
+
export declare function validateFaceFromImage(img: HTMLImageElement): Promise<boolean>;
|
|
23
21
|
export {};
|