@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.
Files changed (28) hide show
  1. package/dist/client/hooks/useAuthenticateMutation.js +3 -1
  2. package/dist/client/hooks/useCreateDigitainGameSessionMutatio.js +3 -1
  3. package/dist/client/hooks/useCreateGCashDepositMutation.js +3 -1
  4. package/dist/client/hooks/useCreateGCashWithdrawalMutation.js +3 -1
  5. package/dist/client/hooks/useCreateGameSessionMutation.js +6 -2
  6. package/dist/client/hooks/useCreateInstapayWithdrawalMutation.js +3 -1
  7. package/dist/client/hooks/useCreateMayaAppDepositMutation.js +3 -1
  8. package/dist/client/hooks/useCreateMayaAppWithdrawalMutation.js +3 -1
  9. package/dist/client/hooks/useCreateMayaDepositMutation.js +3 -1
  10. package/dist/client/hooks/useCreateMayaWithdrawalMutation.js +3 -1
  11. package/dist/client/hooks/useCreateOnlineBankDepositMutation.js +3 -1
  12. package/dist/client/hooks/useCreateQRPHDepositMutation.js +3 -1
  13. package/dist/client/hooks/useSignInMutation.js +3 -1
  14. package/dist/client/hooks/useSignUpMutation.js +3 -1
  15. package/dist/client/services/getSession.js +1 -3
  16. package/dist/client/services/updateSession.js +11 -6
  17. package/dist/components/KYC/CaptureIdDocument.js +18 -8
  18. package/dist/components/KYC/CaptureSelfie.js +55 -28
  19. package/dist/components/KYC/NoCameraError.d.ts +7 -0
  20. package/dist/components/KYC/NoCameraError.js +6 -0
  21. package/dist/components/KYC/utils.d.ts +1 -0
  22. package/dist/components/KYC/utils.js +22 -0
  23. package/dist/components/PortalProvider/SetupDomain.js +8 -2
  24. package/dist/handlers.js +1 -1
  25. package/dist/next.config.js +0 -3
  26. package/dist/server/services/getSession.js +2 -6
  27. package/dist/types/index.d.ts +2 -2
  28. 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
- Domain: session.domain,
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
- Domain: session.domain,
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
- Domain: session.domain,
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
- Domain: session.domain,
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
- Domain: session.domain,
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
- Domain: session.domain,
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
- Domain: session.domain,
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
- Domain: session.domain,
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
- Domain: session.domain,
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
- Domain: session.domain,
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
- Domain: session.domain,
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
- Domain: session.domain,
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
- Domain: session.domain,
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
- const { ok } = await httpRequest.json('/api/sessions', {
5
- ...options,
6
- method: 'PATCH',
7
- body: JSON.stringify(input),
8
- });
9
- return ok;
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 { dataURLtoBlob, resizeFile } from './utils.js';
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.message);
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('Failed to load image. Please try again.');
153
+ setCameraError('NoIdDetectedError');
153
154
  };
154
155
  }
155
156
  catch (error) {
156
157
  console.error('Error capturing image:', error);
157
- setCameraError('Failed to capture image. Please try again.');
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("div", { className: "flex h-full items-center justify-center p-4", children: _jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-red-500 mb-2 text-sm", children: "Camera Error" }), _jsx("p", { className: "text-gray-400 text-xs", children: cameraError })] }) })) : 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]" })) }), cameraError ? (_jsx("div", { className: "mt-4 text-center", children: _jsx(Button, { className: "mx-auto px-xl lg:w-fit", onClick: () => {
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
- setCaptureInProgress(true);
44
- const stream = await navigator.mediaDevices.getUserMedia({
45
- video: {
46
- facingMode: mobileDevice ? 'user' : 'environment',
47
- aspectRatio: mobileDevice ? 9 / 16 : 16 / 9,
48
- width: { ideal: 1920 },
49
- height: { ideal: 1080 },
50
- },
51
- audio: false,
52
- });
53
- setVideoStream(stream);
54
- if (videoRef.current) {
55
- videoRef.current.srcObject = stream;
56
- videoRef.current.onloadedmetadata = () => {
57
- videoRef.current
58
- ?.play()
59
- .then(() => {
60
- if (modelsLoaded) {
61
- startFaceDetection();
62
- }
63
- })
64
- .catch((error) => {
65
- console.error('Error playing video:', error);
66
- setCameraError('Failed to play video stream. Please check your camera settings.');
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,7 @@
1
+ interface Props {
2
+ onRetry: () => void;
3
+ title: string;
4
+ description: string;
5
+ }
6
+ declare function NoCameraError({ onRetry, title, description }: Props): import("react/jsx-runtime").JSX.Element;
7
+ export default NoCameraError;
@@ -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 = `${window.location.host}/${market}`;
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 : searchParams.has('m') ? 1000 : 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 ?? request.nextUrl.host;
65
+ const domain = request.cookies.get(DOMAIN_COOKIE_NAME)?.value;
66
66
  if (!refreshToken) {
67
67
  const response = NextResponse.json({
68
68
  ok: true,
@@ -45,9 +45,6 @@ export const config = {
45
45
  nodeMiddleware: true,
46
46
  },
47
47
  poweredByHeader: false,
48
- compiler: {
49
- removeConsole: process.env.NODE_ENV === 'production',
50
- },
51
48
  };
52
49
  export function extendConfig(userConfig) {
53
50
  return {
@@ -1,14 +1,10 @@
1
- import { cookies, headers } from 'next/headers';
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',
@@ -7,11 +7,11 @@ import type { ImageProps } from 'next/image';
7
7
  */
8
8
  export type Session = {
9
9
  status: 'authenticated';
10
- domain: string;
10
+ domain?: string | null;
11
11
  token: string;
12
12
  } | {
13
13
  status: 'unauthenticated';
14
- domain: string;
14
+ domain?: string | null;
15
15
  token?: null;
16
16
  };
17
17
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opexa/portal-components",
3
- "version": "0.0.177",
3
+ "version": "0.0.180",
4
4
  "exports": {
5
5
  "./ui/*": {
6
6
  "types": "./dist/ui/*/index.d.ts",