@opexa/portal-components 0.0.177 → 0.0.180
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/useAuthenticateMutation.js +3 -1
- package/dist/client/hooks/useCreateDigitainGameSessionMutatio.js +3 -1
- package/dist/client/hooks/useCreateGCashDepositMutation.js +3 -1
- package/dist/client/hooks/useCreateGCashWithdrawalMutation.js +3 -1
- package/dist/client/hooks/useCreateGameSessionMutation.js +6 -2
- package/dist/client/hooks/useCreateInstapayWithdrawalMutation.js +3 -1
- package/dist/client/hooks/useCreateMayaAppDepositMutation.js +3 -1
- package/dist/client/hooks/useCreateMayaAppWithdrawalMutation.js +3 -1
- package/dist/client/hooks/useCreateMayaDepositMutation.js +3 -1
- package/dist/client/hooks/useCreateMayaWithdrawalMutation.js +3 -1
- package/dist/client/hooks/useCreateOnlineBankDepositMutation.js +3 -1
- package/dist/client/hooks/useCreateQRPHDepositMutation.js +3 -1
- package/dist/client/hooks/useSignInMutation.js +3 -1
- package/dist/client/hooks/useSignUpMutation.js +3 -1
- package/dist/client/services/getSession.js +1 -3
- package/dist/client/services/updateSession.js +11 -6
- package/dist/components/KYC/CaptureIdDocument.js +18 -8
- package/dist/components/KYC/CaptureSelfie.js +55 -28
- package/dist/components/KYC/NoCameraError.d.ts +7 -0
- package/dist/components/KYC/NoCameraError.js +6 -0
- package/dist/components/KYC/utils.d.ts +1 -0
- package/dist/components/KYC/utils.js +22 -0
- package/dist/components/PortalProvider/SetupDomain.js +8 -2
- package/dist/handlers.js +1 -1
- package/dist/next.config.js +0 -3
- package/dist/server/services/getSession.js +2 -6
- package/dist/types/index.d.ts +2 -2
- package/package.json +1 -1
|
@@ -13,7 +13,9 @@ export const useAuthenticateMutation = (config) => {
|
|
|
13
13
|
const session = await getSession();
|
|
14
14
|
await authenticate(input, {
|
|
15
15
|
headers: {
|
|
16
|
-
|
|
16
|
+
...(session.domain && {
|
|
17
|
+
Domain: session.domain,
|
|
18
|
+
}),
|
|
17
19
|
},
|
|
18
20
|
});
|
|
19
21
|
await queryClient.invalidateQueries({
|
|
@@ -20,7 +20,9 @@ export const useCreateDigitainGameSessionMutatio = (config) => {
|
|
|
20
20
|
}, {
|
|
21
21
|
headers: {
|
|
22
22
|
Authorization: `Bearer ${session.token}`,
|
|
23
|
-
|
|
23
|
+
...(session.domain && {
|
|
24
|
+
Domain: session.domain,
|
|
25
|
+
}),
|
|
24
26
|
},
|
|
25
27
|
});
|
|
26
28
|
const data = await createPoll(async () => {
|
|
@@ -22,7 +22,9 @@ export const useCreateGCashDepositMutation = (config) => {
|
|
|
22
22
|
await createGCashDeposit({ ...input, id }, {
|
|
23
23
|
headers: {
|
|
24
24
|
Authorization: `Bearer ${session.token}`,
|
|
25
|
-
|
|
25
|
+
...(session.domain && {
|
|
26
|
+
Domain: session.domain,
|
|
27
|
+
}),
|
|
26
28
|
},
|
|
27
29
|
});
|
|
28
30
|
const poll = createPoll(async () => {
|
|
@@ -16,7 +16,9 @@ export const useCreateGCashWithdrawalMutation = (config) => {
|
|
|
16
16
|
await createGCashWithdrawal({ ...input, id }, {
|
|
17
17
|
headers: {
|
|
18
18
|
Authorization: `Bearer ${session.token}`,
|
|
19
|
-
|
|
19
|
+
...(session.domain && {
|
|
20
|
+
Domain: session.domain,
|
|
21
|
+
}),
|
|
20
22
|
},
|
|
21
23
|
});
|
|
22
24
|
return id;
|
|
@@ -22,8 +22,10 @@ export const useCreateGameSessionMutation = (config) => {
|
|
|
22
22
|
game: 'reference' in game ? game.reference : game.id,
|
|
23
23
|
}, {
|
|
24
24
|
headers: {
|
|
25
|
-
Domain: session.domain,
|
|
26
25
|
Authorization: `Bearer ${session.token}`,
|
|
26
|
+
...(session.domain && {
|
|
27
|
+
Domain: session.domain,
|
|
28
|
+
}),
|
|
27
29
|
},
|
|
28
30
|
});
|
|
29
31
|
const data = await createPoll(async () => {
|
|
@@ -54,7 +56,9 @@ export const useCreateGameSessionMutation = (config) => {
|
|
|
54
56
|
}, {
|
|
55
57
|
headers: {
|
|
56
58
|
Authorization: `Bearer ${session.token}`,
|
|
57
|
-
|
|
59
|
+
...(session.domain && {
|
|
60
|
+
Domain: session.domain,
|
|
61
|
+
}),
|
|
58
62
|
},
|
|
59
63
|
});
|
|
60
64
|
const data = await createPoll(async () => {
|
|
@@ -16,7 +16,9 @@ export const useCreateInstapayWithdrawalMutation = (config) => {
|
|
|
16
16
|
await createAIOInstapayWithdrawal({ ...input, id }, {
|
|
17
17
|
headers: {
|
|
18
18
|
Authorization: `Bearer ${session.token}`,
|
|
19
|
-
|
|
19
|
+
...(session.domain && {
|
|
20
|
+
Domain: session.domain,
|
|
21
|
+
}),
|
|
20
22
|
},
|
|
21
23
|
});
|
|
22
24
|
return id;
|
|
@@ -22,6 +22,9 @@ export const useCreateMayaAppDepositMutation = (config) => {
|
|
|
22
22
|
await createMayaAppDeposit({ ...input, id }, {
|
|
23
23
|
headers: {
|
|
24
24
|
Authorization: `Bearer ${session.token}`,
|
|
25
|
+
...(session.domain && {
|
|
26
|
+
Domain: session.domain,
|
|
27
|
+
}),
|
|
25
28
|
},
|
|
26
29
|
});
|
|
27
30
|
const poll = createPoll(async () => {
|
|
@@ -30,7 +33,6 @@ export const useCreateMayaAppDepositMutation = (config) => {
|
|
|
30
33
|
return await getDeposit(id, {
|
|
31
34
|
headers: {
|
|
32
35
|
Authorization: `Bearer ${session.token}`,
|
|
33
|
-
Domain: session.domain,
|
|
34
36
|
},
|
|
35
37
|
});
|
|
36
38
|
}, {
|
|
@@ -16,7 +16,9 @@ export const useCreateMayaAppWithdrawalMutation = (config) => {
|
|
|
16
16
|
await createMayaAppWithdrawal({ ...input, id }, {
|
|
17
17
|
headers: {
|
|
18
18
|
Authorization: `Bearer ${session.token}`,
|
|
19
|
-
|
|
19
|
+
...(session.domain && {
|
|
20
|
+
Domain: session.domain,
|
|
21
|
+
}),
|
|
20
22
|
},
|
|
21
23
|
});
|
|
22
24
|
return id;
|
|
@@ -22,7 +22,9 @@ export const useCreateMayaDepositMutation = (config) => {
|
|
|
22
22
|
await createMayaDeposit({ ...input, id }, {
|
|
23
23
|
headers: {
|
|
24
24
|
Authorization: `Bearer ${session.token}`,
|
|
25
|
-
|
|
25
|
+
...(session.domain && {
|
|
26
|
+
Domain: session.domain,
|
|
27
|
+
}),
|
|
26
28
|
},
|
|
27
29
|
});
|
|
28
30
|
const poll = createPoll(async () => {
|
|
@@ -16,7 +16,9 @@ export const useCreateMayaWithdrawalMutation = (config) => {
|
|
|
16
16
|
await createMayaWithdrawal({ ...input, id }, {
|
|
17
17
|
headers: {
|
|
18
18
|
Authorization: `Bearer ${session.token}`,
|
|
19
|
-
|
|
19
|
+
...(session.domain && {
|
|
20
|
+
Domain: session.domain,
|
|
21
|
+
}),
|
|
20
22
|
},
|
|
21
23
|
});
|
|
22
24
|
return id;
|
|
@@ -22,7 +22,9 @@ export const useCreateOnlineBankDepositMutation = (config) => {
|
|
|
22
22
|
await createAIOOnlineBankDeposit({ ...input, id }, {
|
|
23
23
|
headers: {
|
|
24
24
|
Authorization: `Bearer ${session.token}`,
|
|
25
|
-
|
|
25
|
+
...(session.domain && {
|
|
26
|
+
Domain: session.domain,
|
|
27
|
+
}),
|
|
26
28
|
},
|
|
27
29
|
});
|
|
28
30
|
const poll = createPoll(async () => {
|
|
@@ -22,7 +22,9 @@ export const useCreateQRPHDepositMutation = (config) => {
|
|
|
22
22
|
await createAIOQRPHDeposit({ ...input, id }, {
|
|
23
23
|
headers: {
|
|
24
24
|
Authorization: `Bearer ${session.token}`,
|
|
25
|
-
|
|
25
|
+
...(session.domain && {
|
|
26
|
+
Domain: session.domain,
|
|
27
|
+
}),
|
|
26
28
|
},
|
|
27
29
|
});
|
|
28
30
|
const poll = createPoll(async () => {
|
|
@@ -13,7 +13,9 @@ export const useSignInMutation = (config) => {
|
|
|
13
13
|
const session = await getSession();
|
|
14
14
|
const authenticator = await signIn(input, {
|
|
15
15
|
headers: {
|
|
16
|
-
|
|
16
|
+
...(session.domain && {
|
|
17
|
+
Domain: session.domain,
|
|
18
|
+
}),
|
|
17
19
|
},
|
|
18
20
|
});
|
|
19
21
|
if (!authenticator) {
|
|
@@ -10,7 +10,9 @@ export const useSignUpMutation = (config) => {
|
|
|
10
10
|
const session = await getSession();
|
|
11
11
|
return await registerMemberAccountViaMobile(input, {
|
|
12
12
|
headers: {
|
|
13
|
-
|
|
13
|
+
...(session.domain && {
|
|
14
|
+
Domain: session.domain,
|
|
15
|
+
}),
|
|
14
16
|
},
|
|
15
17
|
});
|
|
16
18
|
},
|
|
@@ -2,7 +2,5 @@ import { cache } from 'react';
|
|
|
2
2
|
import { httpRequest, } from '../../services/httpRequest.js';
|
|
3
3
|
export const getSession = cache(async (options) => {
|
|
4
4
|
const res = await httpRequest.json('/api/sessions', options);
|
|
5
|
-
return res.ok
|
|
6
|
-
? res.data
|
|
7
|
-
: { status: 'unauthenticated', domain: window.location.origin };
|
|
5
|
+
return res.ok ? res.data : { status: 'unauthenticated', domain: null };
|
|
8
6
|
});
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { cache } from 'react';
|
|
2
2
|
import { httpRequest, } from '../../services/httpRequest.js';
|
|
3
3
|
export const updateSession = cache(async (input, options) => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
try {
|
|
5
|
+
const { ok } = await httpRequest.json('/api/sessions', {
|
|
6
|
+
...options,
|
|
7
|
+
method: 'PATCH',
|
|
8
|
+
body: JSON.stringify(input),
|
|
9
|
+
});
|
|
10
|
+
return ok;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
10
15
|
});
|
|
@@ -10,7 +10,8 @@ import { XIcon } from '../../icons/XIcon.js';
|
|
|
10
10
|
import { Button } from '../../ui/Button/index.js';
|
|
11
11
|
import { Dialog } from '../../ui/Dialog/index.js';
|
|
12
12
|
import { useKYCContext } from './KYCContext.js';
|
|
13
|
-
import
|
|
13
|
+
import NoCameraError from './NoCameraError.js';
|
|
14
|
+
import { dataURLtoBlob, resizeFile, showPermissionInstructions } from './utils.js';
|
|
14
15
|
export function CaptureIdDocument() {
|
|
15
16
|
const kyc = useKYCContext();
|
|
16
17
|
const { mutate, isPending } = useUploadImageFileMutation();
|
|
@@ -89,7 +90,7 @@ export function CaptureIdDocument() {
|
|
|
89
90
|
setIsLoading(false);
|
|
90
91
|
if (error instanceof DOMException) {
|
|
91
92
|
console.error('Error accessing camera:', error.message);
|
|
92
|
-
setCameraError(error.
|
|
93
|
+
setCameraError(error.name);
|
|
93
94
|
}
|
|
94
95
|
else {
|
|
95
96
|
console.error('Unknown error accessing camera:', error);
|
|
@@ -149,12 +150,12 @@ export function CaptureIdDocument() {
|
|
|
149
150
|
};
|
|
150
151
|
newImg.onerror = () => {
|
|
151
152
|
console.error('Error loading image');
|
|
152
|
-
setCameraError('
|
|
153
|
+
setCameraError('NoIdDetectedError');
|
|
153
154
|
};
|
|
154
155
|
}
|
|
155
156
|
catch (error) {
|
|
156
157
|
console.error('Error capturing image:', error);
|
|
157
|
-
setCameraError('
|
|
158
|
+
setCameraError('NoIdDetectedError');
|
|
158
159
|
setCaptureInProgress(false);
|
|
159
160
|
}
|
|
160
161
|
}
|
|
@@ -194,11 +195,20 @@ export function CaptureIdDocument() {
|
|
|
194
195
|
}
|
|
195
196
|
startCamera();
|
|
196
197
|
}
|
|
198
|
+
function checkCameraPermission() {
|
|
199
|
+
const constraints = { video: true };
|
|
200
|
+
navigator.mediaDevices
|
|
201
|
+
.getUserMedia(constraints)
|
|
202
|
+
.then(() => {
|
|
203
|
+
setCameraError(null);
|
|
204
|
+
startCamera();
|
|
205
|
+
})
|
|
206
|
+
.catch(() => {
|
|
207
|
+
showPermissionInstructions();
|
|
208
|
+
});
|
|
209
|
+
}
|
|
197
210
|
return (_jsx(_Fragment, { children: _jsxs("div", { className: "w-full p-4 lg:w-[640px] lg:px-12 lg:py-4xl", children: [_jsxs("button", { type: "button", className: "flex items-center gap-lg lg:absolute lg:right-5 lg:top-5 lg:p-md", onClick: () => {
|
|
198
211
|
stopCamera();
|
|
199
212
|
kyc.setCapturing(null);
|
|
200
|
-
}, children: [_jsx(XIcon, { className: "text-text-senary-300 hidden size-5 lg:block" }), _jsx(ArrowLeftIcon, { className: "text-text-senary-300 size-5 lg:hidden" }), _jsx("span", { className: "text-lg font-semibold lg:hidden", children: "Back" })] }), _jsx(Dialog.Title, { className: "mt-6 text-center text-lg font-semibold lg:mt-0", children: "Take a Picture of Your Front ID" }), _jsxs(Dialog.Description, { className: "lg:max-w-auto text-text-tertiary-600 mx-auto mt-sm max-w-[19rem] text-center text-sm lg:max-w-full", 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 the frame."] }), _jsx("div", { id: "parent", className: "border-border-disabled mt-6 aspect-video rounded-xl border bg-black lg:mt-8", children: cameraError ? (_jsx(
|
|
201
|
-
setCameraError(null);
|
|
202
|
-
startCamera();
|
|
203
|
-
}, children: "Try Again" }) })) : captureInProgress ? (_jsxs(Button, { className: "disabled:bg-bg-disabled disabled:text-text-disabled mx-auto mt-6 px-xl disabled:opacity-100 lg:mt-8 lg:w-fit", onClick: captureAndProcessImage, children: ["Capture Image", _jsx(Camera01Icon, { className: "size-5" })] })) : selectedImage && selectedImage.src ? (_jsxs("div", { className: "mt-4 flex flex-col items-center justify-center gap-2 md:flex-row", children: [_jsxs(Button, { className: "lg:w-fit", type: "button", onClick: retakePhoto, children: ["Retake Photo ", _jsx(Camera01Icon, { className: "ml-1" })] }), _jsxs(Button, { className: "lg:w-fit", type: "button", onClick: uploadPhoto, disabled: isPending, children: ["Use Photo ", _jsx(CheckCircleIcon, { className: "ml-1" })] })] })) : (_jsxs(Button, { className: "disabled:bg-bg-disabled disabled:text-text-disabled mx-auto mt-6 px-xl disabled:opacity-100 lg:mt-8 lg:w-fit", onClick: startCamera, disabled: isLoading || !!videoStream, children: [isLoading ? 'Starting Camera...' : 'Start Camera', _jsx(Camera01Icon, { className: "size-5" })] }))] }) }));
|
|
213
|
+
}, children: [_jsx(XIcon, { className: "text-text-senary-300 hidden size-5 lg:block" }), _jsx(ArrowLeftIcon, { className: "text-text-senary-300 size-5 lg:hidden" }), _jsx("span", { className: "text-lg font-semibold lg:hidden", children: "Back" })] }), _jsx(Dialog.Title, { className: "mt-6 text-center text-lg font-semibold lg:mt-0", children: "Take a Picture of Your Front ID" }), _jsxs(Dialog.Description, { className: "lg:max-w-auto text-text-tertiary-600 mx-auto mt-sm max-w-[19rem] text-center text-sm lg:max-w-full", 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 the frame."] }), _jsx("div", { id: "parent", className: "border-border-disabled mt-6 aspect-video rounded-xl border bg-black lg:mt-8", children: ['NotAllowedError', 'NotReadableError', 'NotFoundError'].includes(cameraError) ? (_jsx(NoCameraError, { onRetry: checkCameraPermission, title: "Camera Access Required", description: "We were unable to detect a camera on your device. Please ensure it is properly connected and\r\n accessible to this application." })) : captureInProgress ? (_jsxs("div", { className: "relative flex h-fit w-full flex-col items-center justify-center", children: [_jsx("video", { ref: videoElement, autoPlay: true, muted: true, playsInline: true, className: "relative h-[60vh] w-full rounded-lg object-cover md:aspect-video md:max-h-[333px]", width: "100%", height: "100%" }), _jsxs("div", { className: "pointer-events-none absolute inset-0 z-50", children: [_jsx("div", { className: twMerge('absolute inset-0 w-full bg-black/60 backdrop-blur-sm [clip-path:polygon(0%_0%,0%_100%,calc(50%-158px)_100%,calc(50%-158px)_calc(50%-100px),calc(50%+158px)_calc(50%-100px),calc(50%+158px)_calc(50%+100px),calc(50%-158px)_calc(50%+100px),calc(50%-158px)_100%,100%_100%,100%_0%)] md:[clip-path:polygon(0%_0%,0%_100%,calc(50%-225px)_100%,calc(50%-225px)_calc(50%-142px),calc(50%+225px)_calc(50%-142px),calc(50%+225px)_calc(50%+142px),calc(50%-225px)_calc(50%+142px),calc(50%-225px)_100%,100%_100%,100%_0%)]') }), _jsx("div", { className: "absolute inset-0 z-[60] mx-auto flex items-center justify-center", children: _jsx("div", { className: "relative aspect-[1011/638] h-[200px] md:h-[295px] md:w-[450px]", children: _jsx("div", { className: "h-full w-full rounded-lg border-4 border-dashed border-[#B54708]" }) }) })] })] })) : (_jsx("div", { ref: containerRef, className: "relative grid h-full w-full place-items-center rounded-lg object-contain md:max-h-[333px]" })) }), captureInProgress ? (_jsxs(Button, { className: "disabled:bg-bg-disabled disabled:text-text-disabled mx-auto mt-6 px-xl disabled:opacity-100 lg:mt-8 lg:w-fit", onClick: captureAndProcessImage, children: ["Capture Image", _jsx(Camera01Icon, { className: "size-5" })] })) : selectedImage && selectedImage.src ? (_jsxs("div", { className: "mt-4 flex flex-col items-center justify-center gap-2 md:flex-row", children: [_jsxs(Button, { className: "lg:w-fit", type: "button", onClick: retakePhoto, children: ["Retake Photo ", _jsx(Camera01Icon, { className: "ml-1" })] }), _jsxs(Button, { className: "lg:w-fit", type: "button", onClick: uploadPhoto, disabled: isPending, children: ["Use Photo ", _jsx(CheckCircleIcon, { className: "ml-1" })] })] })) : (_jsxs(Button, { className: twMerge('disabled:bg-bg-disabled disabled:text-text-disabled mx-auto mt-6 px-xl disabled:opacity-100 lg:mt-8 lg:w-fit', cameraError && 'hidden'), onClick: startCamera, disabled: isLoading || !!videoStream, children: [isLoading ? 'Starting Camera...' : 'Start Camera', _jsx(Camera01Icon, { className: "size-5" })] }))] }) }));
|
|
204
214
|
}
|
|
@@ -11,8 +11,9 @@ import { Button } from '../../ui/Button/index.js';
|
|
|
11
11
|
import { Dialog } from '../../ui/Dialog/index.js';
|
|
12
12
|
import { onMobileDevice } from '../../utils/onMobileDevice.js';
|
|
13
13
|
import { useKYCContext } from './KYCContext.js';
|
|
14
|
+
import NoCameraError from './NoCameraError.js';
|
|
14
15
|
import PersonOverlayDesktop from './PersonOverlayDesktop.js';
|
|
15
|
-
import { dataURLtoBlob, loadFaceApiModels, resizeFile } from './utils.js';
|
|
16
|
+
import { dataURLtoBlob, loadFaceApiModels, resizeFile, showPermissionInstructions, } from './utils.js';
|
|
16
17
|
export function CaptureSelfie() {
|
|
17
18
|
const kyc = useKYCContext();
|
|
18
19
|
const { mutate, isPending } = useUploadImageFileMutation();
|
|
@@ -40,32 +41,46 @@ export function CaptureSelfie() {
|
|
|
40
41
|
}
|
|
41
42
|
}, [captureInProgress]);
|
|
42
43
|
async function startCamera() {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
videoRef.current
|
|
56
|
-
|
|
57
|
-
videoRef.current
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
44
|
+
try {
|
|
45
|
+
setCaptureInProgress(true);
|
|
46
|
+
const stream = await navigator.mediaDevices.getUserMedia({
|
|
47
|
+
video: {
|
|
48
|
+
facingMode: mobileDevice ? 'user' : 'environment',
|
|
49
|
+
aspectRatio: mobileDevice ? 9 / 16 : 16 / 9,
|
|
50
|
+
width: { ideal: 1920 },
|
|
51
|
+
height: { ideal: 1080 },
|
|
52
|
+
},
|
|
53
|
+
audio: false,
|
|
54
|
+
});
|
|
55
|
+
setVideoStream(stream);
|
|
56
|
+
if (videoRef.current) {
|
|
57
|
+
videoRef.current.srcObject = stream;
|
|
58
|
+
videoRef.current.onloadedmetadata = () => {
|
|
59
|
+
videoRef.current
|
|
60
|
+
?.play()
|
|
61
|
+
.then(() => {
|
|
62
|
+
if (modelsLoaded) {
|
|
63
|
+
startFaceDetection();
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
.catch((error) => {
|
|
67
|
+
console.error('Error playing video:', error);
|
|
68
|
+
setCameraError('Failed to play video stream. Please check your camera settings.');
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (error instanceof DOMException) {
|
|
75
|
+
console.error('Error accessing camera:', error.message);
|
|
76
|
+
setCameraError(error.name);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
console.error('Unknown error accessing camera:', error);
|
|
80
|
+
setCameraError('An unknown error occurred. Please check permissions and try again.');
|
|
81
|
+
}
|
|
82
|
+
setCaptureInProgress(false);
|
|
83
|
+
stopCamera();
|
|
69
84
|
}
|
|
70
85
|
}
|
|
71
86
|
function startFaceDetection() {
|
|
@@ -241,6 +256,18 @@ export function CaptureSelfie() {
|
|
|
241
256
|
});
|
|
242
257
|
}
|
|
243
258
|
}
|
|
259
|
+
function checkCameraPermission() {
|
|
260
|
+
const constraints = { video: true };
|
|
261
|
+
navigator.mediaDevices
|
|
262
|
+
.getUserMedia(constraints)
|
|
263
|
+
.then(() => {
|
|
264
|
+
setCameraError(null);
|
|
265
|
+
startCamera();
|
|
266
|
+
})
|
|
267
|
+
.catch(() => {
|
|
268
|
+
showPermissionInstructions();
|
|
269
|
+
});
|
|
270
|
+
}
|
|
244
271
|
useEffect(() => {
|
|
245
272
|
return () => {
|
|
246
273
|
if (detectionIntervalRef.current) {
|
|
@@ -254,5 +281,5 @@ export function CaptureSelfie() {
|
|
|
254
281
|
return (_jsxs("div", { className: "w-full p-4 lg:w-[640px] lg:px-12 lg:py-4xl", children: [_jsxs("button", { type: "button", className: "flex items-center gap-lg lg:absolute lg:right-5 lg:top-5 lg:p-md", onClick: () => {
|
|
255
282
|
stopCamera();
|
|
256
283
|
kyc.setCapturing(null);
|
|
257
|
-
}, children: [_jsx(XIcon, { className: "text-text-senary-300 hidden size-5 lg:block" }), _jsx(ArrowLeftIcon, { className: "text-text-senary-300 size-5 lg:hidden" }), _jsx("span", { className: "text-lg font-semibold lg:hidden", children: "Back" })] }), _jsx(Dialog.Title, { className: "mt-6 text-center text-lg font-semibold lg:mt-0", children: "Take a Selfie Holding Your ID" }), _jsx(Dialog.Description, { className: "text-text-tertiary-600 mx-auto mt-sm max-w-[19rem] text-center text-sm lg:max-w-full", children: "Make sure your face and ID are clearly visible, with no glare or blur." }), _jsx("div", { id: "parent", className: "border-border-disabled mt-6 aspect-video rounded-xl border bg-black lg:mt-8", children: captureInProgress ? (_jsxs("div", { className: "relative flex h-fit w-full flex-col items-center justify-center", children: [_jsx("video", { ref: videoRef, autoPlay: true, muted: true, className: "h-[60vh] w-full rounded-lg object-cover md:aspect-video md:h-[333px]", width: "100%", height: "100%" }), _jsx("canvas", { ref: faceCanvasRef, className: "absolute inset-0 h-[60vh] w-full object-cover md:aspect-video md:h-[333px] md:object-contain", width: "100%", height: "100%" }), isCapturing && (_jsx("span", { className: "absolute inset-x-0 bottom-8 flex items-center justify-center text-5xl font-bold text-[#713B12CC] md:bottom-4", children: countdown })), !isFaceCentered && (_jsx("span", { className: "absolute inset-x-0 bottom-12 mx-auto w-1/2 text-center text-xs text-white md:bottom-3", children: "Please center your face in the camera view. Make sure your ID is clearly visible next to your face." })), _jsx(PersonOverlayDesktop, { isFaceCentered: isFaceCentered, width: videoRef.current?.clientWidth || 543, height: videoRef.current?.clientHeight || 333 })] })) : (selectedImage && (_jsx("img", { src: selectedImage, alt: "Captured Photo", className: "h-full w-full rounded-lg object-cover md:aspect-video md:h-[333px]" }))) }), selectedImage && (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 md:flex-row", children: [_jsxs(Button, { className: "disabled:bg-bg-disabled disabled:text-text-disabled mx-auto mt-4 px-xl disabled:opacity-100", size: "sm", onClick: retakePhoto, type: "button", children: ["Rekate Photo", _jsx(Camera01Icon, { className: "size-5" })] }), _jsxs(Button, { className: "disabled:bg-bg-disabled disabled:text-text-disabled mx-auto mt-4 px-xl disabled:opacity-100", size: "sm", onClick: usePhoto, type: "button", disabled: isPending, children: ["Use Photo", _jsx(Camera01Icon, { className: "size-5" })] })] })), !captureInProgress && (_jsxs(Button, { className: twMerge('mx-auto mt-6 px-xl lg:mt-8', selectedImage && 'hidden'), onClick: startCamera, disabled: !modelsLoaded, type: "button", children: ["Start Camera", _jsx(Camera01Icon, { className: "size-5" })] }))] }));
|
|
284
|
+
}, children: [_jsx(XIcon, { className: "text-text-senary-300 hidden size-5 lg:block" }), _jsx(ArrowLeftIcon, { className: "text-text-senary-300 size-5 lg:hidden" }), _jsx("span", { className: "text-lg font-semibold lg:hidden", children: "Back" })] }), _jsx(Dialog.Title, { className: "mt-6 text-center text-lg font-semibold lg:mt-0", children: "Take a Selfie Holding Your ID" }), _jsx(Dialog.Description, { className: "text-text-tertiary-600 mx-auto mt-sm max-w-[19rem] text-center text-sm lg:max-w-full", children: "Make sure your face and ID are clearly visible, with no glare or blur." }), _jsx("div", { id: "parent", className: "border-border-disabled mt-6 aspect-video rounded-xl border bg-black lg:mt-8", children: ['NotAllowedError', 'NotReadableError', 'NotFoundError'].includes(cameraError) ? (_jsx(NoCameraError, { onRetry: checkCameraPermission, title: "Camera Access Required", description: "We were unable to detect a camera on your device. Please ensure it is properly connected and accessible to this application." })) : captureInProgress && !cameraError ? (_jsxs("div", { className: "relative flex h-fit w-full flex-col items-center justify-center", children: [_jsx("video", { ref: videoRef, autoPlay: true, muted: true, className: "h-[60vh] w-full rounded-lg object-cover md:aspect-video md:h-[333px]", width: "100%", height: "100%" }), _jsx("canvas", { ref: faceCanvasRef, className: "absolute inset-0 h-[60vh] w-full object-cover md:aspect-video md:h-[333px] md:object-contain", width: "100%", height: "100%" }), isCapturing && (_jsx("span", { className: "absolute inset-x-0 bottom-8 flex items-center justify-center text-5xl font-bold text-[#713B12CC] md:bottom-4", children: countdown })), !isFaceCentered && (_jsx("span", { className: "absolute inset-x-0 bottom-12 mx-auto w-1/2 text-center text-xs text-white md:bottom-3", children: "Please center your face in the camera view. Make sure your ID is clearly visible next to your face." })), _jsx(PersonOverlayDesktop, { isFaceCentered: isFaceCentered, width: videoRef.current?.clientWidth || 543, height: videoRef.current?.clientHeight || 333 })] })) : (selectedImage && (_jsx("img", { src: selectedImage, alt: "Captured Photo", className: "h-full w-full rounded-lg object-cover md:aspect-video md:h-[333px]" }))) }), selectedImage && (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 md:flex-row", children: [_jsxs(Button, { className: "disabled:bg-bg-disabled disabled:text-text-disabled mx-auto mt-4 px-xl disabled:opacity-100", size: "sm", onClick: retakePhoto, type: "button", children: ["Rekate Photo", _jsx(Camera01Icon, { className: "size-5" })] }), _jsxs(Button, { className: "disabled:bg-bg-disabled disabled:text-text-disabled mx-auto mt-4 px-xl disabled:opacity-100", size: "sm", onClick: usePhoto, type: "button", disabled: isPending, children: ["Use Photo", _jsx(Camera01Icon, { className: "size-5" })] })] })), !captureInProgress && !cameraError && (_jsxs(Button, { className: twMerge('mx-auto mt-6 px-xl lg:mt-8', selectedImage && 'hidden'), onClick: startCamera, disabled: !modelsLoaded, type: "button", children: ["Start Camera", _jsx(Camera01Icon, { className: "size-5" })] }))] }));
|
|
258
285
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from '../../ui/Button/index.js';
|
|
3
|
+
function NoCameraError({ onRetry, title, description }) {
|
|
4
|
+
return (_jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-2 p-4", children: [_jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-red-500 mb-2", children: title }), _jsx("p", { className: "mb-2 text-sm", children: description })] }), _jsx(Button, { className: "mx-auto px-xl lg:w-fit", onClick: onRetry, size: "sm", children: "Try Again" })] }));
|
|
5
|
+
}
|
|
6
|
+
export default NoCameraError;
|
|
@@ -5,3 +5,4 @@ export declare const MAX_FILE_SIZE = 10;
|
|
|
5
5
|
export declare const MAX_NAME_LENGTH = 52;
|
|
6
6
|
export declare const SUPPORTED_FILES: string[];
|
|
7
7
|
export declare function validateFile(file: File): "File too large" | "File name too long" | "Unsupported file" | undefined;
|
|
8
|
+
export declare function showPermissionInstructions(): void;
|
|
@@ -48,3 +48,25 @@ export function validateFile(file) {
|
|
|
48
48
|
if (!SUPPORTED_FILES.includes(fileType))
|
|
49
49
|
return 'Unsupported file';
|
|
50
50
|
}
|
|
51
|
+
export function showPermissionInstructions() {
|
|
52
|
+
const instructions = `
|
|
53
|
+
Camera access is blocked. To enable camera access:
|
|
54
|
+
|
|
55
|
+
Chrome/Edge:
|
|
56
|
+
1. Click the camera icon in the address bar
|
|
57
|
+
2. Select "Always allow" and click "Done"
|
|
58
|
+
3. Or go to Settings > Privacy and security > Site settings > Camera
|
|
59
|
+
|
|
60
|
+
Firefox:
|
|
61
|
+
1. Click the shield icon in the address bar
|
|
62
|
+
2. Click on "Camera blocked"
|
|
63
|
+
3. Select "Allow" and refresh the page
|
|
64
|
+
|
|
65
|
+
Safari:
|
|
66
|
+
1. Go to Safari > Settings > Websites > Camera
|
|
67
|
+
2. Find this website and change to "Allow"
|
|
68
|
+
|
|
69
|
+
After changing permissions, please refresh the page and try again.
|
|
70
|
+
`;
|
|
71
|
+
alert(instructions);
|
|
72
|
+
}
|
|
@@ -9,10 +9,16 @@ export function SetupDomain() {
|
|
|
9
9
|
const updateSessionMutation = useUpdateSessionMutation();
|
|
10
10
|
useTimeout(() => {
|
|
11
11
|
const market = searchParams.get('m');
|
|
12
|
-
const domain =
|
|
12
|
+
const domain = market
|
|
13
|
+
? `${window.location.host}/${market}`
|
|
14
|
+
: `${window.location.host}`;
|
|
15
|
+
console.log({
|
|
16
|
+
market,
|
|
17
|
+
domain,
|
|
18
|
+
});
|
|
13
19
|
if (domain === sessionQuery.data?.domain)
|
|
14
20
|
return;
|
|
15
21
|
updateSessionMutation.mutate({ domain });
|
|
16
|
-
}, sessionQuery.isPending ? null :
|
|
22
|
+
}, sessionQuery.isPending ? null : 1000);
|
|
17
23
|
return null;
|
|
18
24
|
}
|
package/dist/handlers.js
CHANGED
|
@@ -62,7 +62,7 @@ export const GET = async (request, { params }) => {
|
|
|
62
62
|
if (path === 'sessions') {
|
|
63
63
|
const accessToken = request.cookies.get(ACCESS_TOKEN_COOKIE_NAME)?.value;
|
|
64
64
|
const refreshToken = request.cookies.get(REFRESH_TOKEN_COOKIE_NAME)?.value;
|
|
65
|
-
const domain = request.cookies.get(DOMAIN_COOKIE_NAME)?.value
|
|
65
|
+
const domain = request.cookies.get(DOMAIN_COOKIE_NAME)?.value;
|
|
66
66
|
if (!refreshToken) {
|
|
67
67
|
const response = NextResponse.json({
|
|
68
68
|
ok: true,
|
package/dist/next.config.js
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import { cookies
|
|
1
|
+
import { cookies } from 'next/headers';
|
|
2
2
|
import { cache } from 'react';
|
|
3
3
|
import { ACCESS_TOKEN_COOKIE_NAME, DOMAIN_COOKIE_NAME } from '../../constants/index.js';
|
|
4
4
|
export const getSession = cache(async () => {
|
|
5
5
|
const Cookies = await cookies();
|
|
6
|
-
const Headers = await headers();
|
|
7
6
|
const token = Cookies.get(ACCESS_TOKEN_COOKIE_NAME)?.value;
|
|
8
|
-
const domain = Cookies.get(DOMAIN_COOKIE_NAME)?.value
|
|
9
|
-
Headers.get('host') ??
|
|
10
|
-
Headers.get('x-forwarded-host') ??
|
|
11
|
-
'localhost';
|
|
7
|
+
const domain = Cookies.get(DOMAIN_COOKIE_NAME)?.value;
|
|
12
8
|
return token
|
|
13
9
|
? {
|
|
14
10
|
status: 'authenticated',
|
package/dist/types/index.d.ts
CHANGED
|
@@ -7,11 +7,11 @@ import type { ImageProps } from 'next/image';
|
|
|
7
7
|
*/
|
|
8
8
|
export type Session = {
|
|
9
9
|
status: 'authenticated';
|
|
10
|
-
domain
|
|
10
|
+
domain?: string | null;
|
|
11
11
|
token: string;
|
|
12
12
|
} | {
|
|
13
13
|
status: 'unauthenticated';
|
|
14
|
-
domain
|
|
14
|
+
domain?: string | null;
|
|
15
15
|
token?: null;
|
|
16
16
|
};
|
|
17
17
|
/**
|