@opexa/portal-components 0.0.231 → 0.0.233

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 (100) hide show
  1. package/dist/client/hooks/useCamera.d.ts +1 -0
  2. package/dist/client/hooks/useCamera.js +12 -7
  3. package/dist/client/hooks/useFeatureFlag.d.ts +1 -1
  4. package/dist/client/hooks/useFeatureFlag.js +1 -19
  5. package/dist/components/CashbackBonus/CashbackBonus.client.d.ts +2 -0
  6. package/dist/components/CashbackBonus/CashbackBonus.client.js +9 -0
  7. package/dist/components/CashbackBonus/CashbackBonus.d.ts +10 -0
  8. package/dist/components/CashbackBonus/CashbackBonus.js +5 -0
  9. package/dist/components/CashbackBonus/index.d.ts +1 -0
  10. package/dist/components/CashbackBonus/index.js +1 -0
  11. package/dist/components/Empty.d.ts +1 -2
  12. package/dist/components/FeatureFlag/FeatureFlag.js +21 -2
  13. package/dist/components/Jackpots/JackpotsCarousel/JackpotsCarouselItem.js +1 -1
  14. package/dist/components/Jackpots/JackpotsList/JackpotsListItemDesktop.js +2 -2
  15. package/dist/components/Jackpots/JackpotsList/JackpotsListItemMobile.js +1 -1
  16. package/dist/components/KYC/Header.js +4 -2
  17. package/dist/components/KYC/Step1.js +3 -2
  18. package/dist/components/KYC/Step2.js +3 -2
  19. package/dist/components/KYC/Step3.js +4 -2
  20. package/dist/components/KYC/Step4.js +3 -2
  21. package/dist/components/KYC/backup/KYCContext.d.ts +5 -1
  22. package/dist/components/KYC/loadModels.d.ts +1 -0
  23. package/dist/components/KYC/loadModels.js +9 -0
  24. package/dist/components/Messages/Message.js +2 -3
  25. package/dist/components/Messages/MessageContext.d.ts +5 -1
  26. package/dist/components/Messages/MessagePopup.js +2 -3
  27. package/dist/components/Promo/PromoContent.d.ts +2 -0
  28. package/dist/components/Promo/PromoContent.js +9 -0
  29. package/dist/components/Promos/PromoCarousel.d.ts +2 -0
  30. package/dist/components/Promos/PromoCarousel.js +41 -0
  31. package/dist/components/Promos/PromoGrid.d.ts +2 -0
  32. package/dist/components/Promos/PromoGrid.js +12 -0
  33. package/dist/components/Promos/PromoItem.d.ts +7 -0
  34. package/dist/components/Promos/PromoItem.js +10 -0
  35. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuest.d.ts +1 -1
  36. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuest.js +10 -5
  37. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuestModal.js +4 -3
  38. package/dist/components/Quests/OnboardingQuest/OnboardingQuest.d.ts +1 -1
  39. package/dist/components/Quests/WageringQuest/WageringQuest.d.ts +1 -1
  40. package/dist/components/Quests/WageringQuest/WageringQuest.js +3 -2
  41. package/dist/components/Quests/WageringQuest/WageringQuestModal.js +4 -3
  42. package/dist/components/SignUp/SignUpForm.js +6 -1
  43. package/dist/components/shared/IdDocumentField.js +117 -48
  44. package/dist/components/shared/SelfieField.js +105 -43
  45. package/dist/constants/BranchCode.d.ts +4 -0
  46. package/dist/constants/BranchCode.js +42 -0
  47. package/dist/constants/endpoints.d.ts +10 -0
  48. package/dist/constants/endpoints.js +41 -0
  49. package/dist/constants/gameProviders.d.ts +1 -2
  50. package/dist/constants/gameProviders.js +6 -0
  51. package/dist/constants/gameTypes.d.ts +1 -2
  52. package/dist/constants/headerKeys.d.ts +1 -0
  53. package/dist/constants/headerKeys.js +1 -0
  54. package/dist/constants/secretQuestions.d.ts +1 -1
  55. package/dist/ui/AlertDialog/AlertDialog.d.ts +88 -88
  56. package/dist/ui/AlertDialog/alertDialog.recipe.d.ts +11 -11
  57. package/dist/ui/Avatar/avatar.recipe.d.ts +3 -3
  58. package/dist/ui/Badge/Badge.d.ts +12 -12
  59. package/dist/ui/Carousel/Carousel.d.ts +45 -45
  60. package/dist/ui/Carousel/carousel.recipe.d.ts +5 -5
  61. package/dist/ui/Checkbox/Checkbox.d.ts +23 -23
  62. package/dist/ui/Checkbox/checkbox.recipe.d.ts +3 -3
  63. package/dist/ui/Clipboard/Clipboard.d.ts +18 -18
  64. package/dist/ui/Collapsible/Collapsible.d.ts +32 -32
  65. package/dist/ui/Collapsible/collapsible.recipe.d.ts +5 -5
  66. package/dist/ui/Combobox/Combobox.d.ts +42 -42
  67. package/dist/ui/Combobox/combobox.recipe.d.ts +3 -3
  68. package/dist/ui/DatePicker/DatePicker.d.ts +72 -72
  69. package/dist/ui/DatePicker/datePicker.recipe.d.ts +3 -3
  70. package/dist/ui/Dialog/Dialog.d.ts +88 -88
  71. package/dist/ui/Dialog/dialog.recipe.d.ts +11 -11
  72. package/dist/ui/Drawer/Drawer.d.ts +33 -33
  73. package/dist/ui/Drawer/drawer.recipe.d.ts +3 -3
  74. package/dist/ui/Menu/Menu.d.ts +144 -144
  75. package/dist/ui/Menu/menu.recipe.d.ts +20 -20
  76. package/dist/ui/PasswordInput/PasswordInput.d.ts +18 -18
  77. package/dist/ui/Popover/Popover.d.ts +55 -55
  78. package/dist/ui/Popover/popover.recipe.d.ts +8 -8
  79. package/dist/ui/Presence.d.ts +1 -1
  80. package/dist/ui/Presence.js +1 -1
  81. package/dist/ui/Progress/Progress.d.ts +27 -27
  82. package/dist/ui/Progress/progress.recipe.d.ts +3 -3
  83. package/dist/ui/QrCode/qrCode.recipe.d.ts +5 -5
  84. package/dist/ui/SegmentGroup/SegmentGroup.d.ts +18 -18
  85. package/dist/ui/SegmentGroup/segmentGroup.recipe.d.ts +3 -3
  86. package/dist/ui/Select/Select.d.ts +45 -45
  87. package/dist/ui/Select/select.recipe.d.ts +3 -3
  88. package/dist/ui/Table/Table.d.ts +21 -21
  89. package/dist/ui/Table/table.anatomy.d.ts +1 -1
  90. package/dist/ui/Table/table.recipe.d.ts +3 -3
  91. package/dist/ui/Tabs/Tabs.d.ts +15 -15
  92. package/dist/ui/Tabs/tabs.recipe.d.ts +3 -3
  93. package/dist/utils/createErrorFromCode.d.ts +2 -0
  94. package/dist/utils/createErrorFromCode.js +11 -0
  95. package/dist/utils/validateFile.js +8 -5
  96. package/package.json +4 -1
  97. package/dist/utils/constants.d.ts +0 -2
  98. package/dist/utils/constants.js +0 -2
  99. package/dist/utils/isBetween3amAnd3pm.d.ts +0 -1
  100. package/dist/utils/isBetween3amAnd3pm.js +0 -5
@@ -2,8 +2,9 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useState } from 'react';
4
4
  import { twMerge } from 'tailwind-merge';
5
- import { ClockStopWatchIcon, InfoCircleIcon } from '../../../icons/index.js';
6
- import { Badge } from '../../../ui/index.js';
5
+ import { ClockStopWatchIcon } from '../../../icons/ClockStopWatchIcon.js';
6
+ import { InfoCircleIcon } from '../../../icons/InfoCircleIcon.js';
7
+ import { Badge } from '../../../ui/Badge/index.js';
7
8
  import CountdownTimer from '../CountdownTimer.js';
8
9
  import { WageringQuestModal } from './WageringQuestModal.js';
9
10
  export function WageringQuest({ quest }) {
@@ -1,8 +1,9 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Portal } from '@ark-ui/react';
4
- import { XIcon } from '../../../icons/index.js';
5
- import { Button, Dialog } from '../../../ui/index.js';
3
+ import { XIcon } from '../../../icons/XIcon.js';
4
+ import { Button } from '../../../ui/Button/index.js';
5
+ import { Dialog } from '../../../ui/Dialog/index.js';
6
+ import { Portal } from '../../../ui/Portal/index.js';
6
7
  export function WageringQuestModal(props) {
7
8
  return (_jsx(Dialog.Root, { lazyMount: true, unmountOnExit: true, open: props.modalState.isOpen, onOpenChange: ({ open }) => props.modalState.setIsOpen(open), closeOnEscape: false, closeOnInteractOutside: false, 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", children: _jsxs(Dialog.Content, { className: "min-h-auto mx-auto max-w-[343px] rounded-xl px-4 pb-0 pt-5", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsxs("div", { className: "flex flex-col space-y-5", children: [_jsx("p", { className: "text-text-primary-900 text-lg font-semibold", children: props.questName }), _jsxs("ul", { className: "text-text-tertiary-600 group list-disc text-wrap pl-4 text-sm font-normal", children: [_jsx("li", { children: "Earn extra rewards just by playing Slots, every bet counts, win or lose!" }), _jsx("li", { children: "Reach the wagering requirement in bets to complete the quest and claim your reward." })] })] }), _jsx("div", { className: "pb-4 pt-6", children: _jsx(Button, { onClick: () => props.modalState.setIsOpen(false), children: "Ok" }) })] }) })] }) }));
8
9
  }
@@ -46,6 +46,9 @@ export function SignUpForm() {
46
46
  itemToValue: (item) => item.code,
47
47
  itemToString: (item) => `${item.code} - ${item.name}`,
48
48
  });
49
+ const globalStore = useGlobalStore(useShallow((ctx) => ({
50
+ kyc: ctx.kyc,
51
+ })));
49
52
  const [step, setStep] = useState(1);
50
53
  const dialog = useDialogContext();
51
54
  const search = useSearchParams();
@@ -192,6 +195,7 @@ export function SignUpForm() {
192
195
  mobileNumber: mobileNumberParser.format(mobileNumber),
193
196
  verificationCode: verificationCode.join(''),
194
197
  referralCode: search.get('referralCode') ?? undefined,
198
+ domain: search.get('domain') ?? undefined,
195
199
  btag: search.get('btag') ?? undefined,
196
200
  });
197
201
  const name = mobileNumberParser.format(mobileNumber);
@@ -238,6 +242,7 @@ export function SignUpForm() {
238
242
  dialog.setOpen(false);
239
243
  step1Form.reset();
240
244
  step2Form.reset();
245
+ globalStore.kyc.setOpen(true);
241
246
  setStep(1);
242
247
  }
243
248
  catch (error) {
@@ -251,7 +256,7 @@ export function SignUpForm() {
251
256
  o.field.onChange(details.value);
252
257
  }, onValueComplete: () => {
253
258
  form2Ref.current?.requestSubmit();
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 () => {
259
+ }, 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 () => {
255
260
  await sendVerificationCodeMutation.mutateAsync({
256
261
  channel: 'SMS',
257
262
  recipient: mobileNumberParser.format(step1Form.getValues('mobileNumber')),
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useFieldContext } from '@ark-ui/react';
4
4
  import Image from 'next/image';
5
- import { useRef } from 'react';
5
+ import { useId, useLayoutEffect, 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';
@@ -10,6 +10,7 @@ import { useControllableState } from '../../client/hooks/useControllableState.js
10
10
  import { useDisclosure } from '../../client/hooks/useDisclosure.js';
11
11
  import { useFileQuery } from '../../client/hooks/useFileQuery.js';
12
12
  import { useUploadImageFileMutation } from '../../client/hooks/useUploadImageFileMutation.js';
13
+ import { createContext } from '../../client/utils/createContext.js';
13
14
  import { toaster } from '../../client/utils/toaster.js';
14
15
  import { Camera01Icon } from '../../icons/Camera01Icon.js';
15
16
  import { CameraOffIcon } from '../../icons/CameraOffIcon.js';
@@ -24,52 +25,9 @@ import { Portal } from '../../ui/Portal/index.js';
24
25
  import { dataAttr } from '../../utils/dataAttr.js';
25
26
  import { validateFile } from '../../utils/validateFile.js';
26
27
  export function IdDocumentField(props) {
27
- const field = useFieldContext();
28
- const [value, setValue] = useControllableState({
29
- value: props.value,
30
- defaultValue: props.defaultValue ?? '',
31
- onChange: props.onChange,
32
- });
33
- const query = useFileQuery(value, {
34
- refetchInterval({ state }) {
35
- return !state.data || state.data.status === 'UPLOADING' ? 1000 : false;
36
- },
37
- });
38
- const mutation = useUploadImageFileMutation({
39
- onSuccess(id) {
40
- setValue(id);
41
- },
42
- onMutate() {
43
- setValue('');
44
- },
45
- onError(error) {
46
- toaster.error({
47
- title: 'Upload Failed',
48
- description: error.message,
49
- });
50
- },
51
- onSettled() {
52
- if (inputRef.current) {
53
- inputRef.current.value = '';
54
- }
55
- },
56
- });
57
- const inputRef = useRef(null);
58
- const guideRef = useRef(null);
59
- const desktop = useMediaQuery('(min-width: 1024px)');
60
- const camera = useCamera({
61
- video: {
62
- facingMode: desktop ? 'user' : 'environment',
63
- },
64
- });
65
- const disclosure = useDisclosure({
66
- onOpenChange(open) {
67
- if (open) {
68
- camera.open();
69
- }
70
- },
71
- });
72
- return (_jsxs(_Fragment, { children: [_jsxs("div", { ref: props.ref, id: props.id, style: props.style, className: twMerge('border-border-primary bg-bg-primary group relative aspect-[352/180] w-full shrink-0 rounded-xl border p-xl', props.className), onDragOver: (e) => e.preventDefault(), onDragEnter: (e) => e.preventDefault(), onDragLeave: (e) => e.preventDefault(), onDrop: (e) => {
28
+ const context = useIdDocumentField(props);
29
+ const { field, setValue, query, mutation, inputRef, guideRef, camera, disclosure, } = context;
30
+ return (_jsxs(IdDocumentFieldProvider, { value: context, children: [_jsxs("div", { ref: props.ref, id: props.id, style: props.style, className: twMerge('border-border-primary bg-bg-primary group relative aspect-[352/180] w-full shrink-0 rounded-xl border p-xl', props.className), onDragOver: (e) => e.preventDefault(), onDragEnter: (e) => e.preventDefault(), onDragLeave: (e) => e.preventDefault(), onDrop: (e) => {
73
31
  e.preventDefault();
74
32
  const file = e.dataTransfer.files?.[0];
75
33
  if (!file)
@@ -109,7 +67,7 @@ export function IdDocumentField(props) {
109
67
  disclosure.setOpen(details.open);
110
68
  }, onExitComplete: 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)] 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: twMerge('border-border-disabled relative w-full overflow-hidden rounded-md border bg-black lg:rounded-lg', !camera.data && !camera.error && !camera.loading
111
69
  ? 'block'
112
- : 'hidden'), children: [_jsx("video", { ...camera.videoProps }), _jsx("div", { ref: guideRef, className: "border-utility-warning-700 absolute left-1/2 top-1/2 aspect-[85.60/53.98] w-[calc(100%-1rem)] -translate-x-1/2 -translate-y-1/2 rounded-md border-2 border-dashed lg:w-[29.688rem]" })] }), 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: camera.error.name }), _jsx("p", { className: "text-text-tertiary-600 mt-0.5 text-center text-xs lg:mt-1 lg:text-sm", children: camera.error.message }), _jsx(Button, { size: "xs", variant: "outline", colorScheme: "gray", fullWidth: false, className: "mt-4 lg:mt-5", onClick: () => {
70
+ : 'hidden'), children: [_jsx("video", { ...camera.videoProps }), _jsx(Mask, {})] }), 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: camera.error.name }), _jsx("p", { className: "text-text-tertiary-600 mt-0.5 text-center text-xs lg:mt-1 lg:text-sm", children: camera.error.message }), _jsx(Button, { size: "xs", variant: "outline", colorScheme: "gray", fullWidth: false, className: "mt-4 lg:mt-5", onClick: () => {
113
71
  camera.reopen();
114
72
  }, children: "Try again" })] })), camera.loading && (_jsx("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(Spinner02Icon, { className: "text-text-placeholder size-8" }) })), camera.data && (_jsx("div", { className: "border-border-disabled h-auto w-full overflow-hidden rounded-md border bg-black lg:rounded-lg", children: _jsx(Image, { src: camera.data.url, alt: "", width: 600, height: 378.08, unoptimized: true, className: "block h-auto w-full" }) }))] }), !camera.data && !camera.error && !camera.loading && (_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 lg:w-auto", onClick: () => {
115
73
  const rect = guideRef.current?.getBoundingClientRect();
@@ -132,3 +90,114 @@ export function IdDocumentField(props) {
132
90
  camera.reset();
133
91
  }, children: [_jsx(RefreshCcw01Icon, { className: "size-5" }), " Retake"] })] }))] }) })] }) })] }));
134
92
  }
93
+ /**
94
+ * -------------------------------------
95
+ * Mask
96
+ * -------------------------------------
97
+ */
98
+ function Mask() {
99
+ const id = useId();
100
+ const { guideRef, maskRef } = useIdDocumentFieldContext();
101
+ const [maskBox, setMaskBox] = useState({
102
+ x: 0,
103
+ y: 0,
104
+ width: 0,
105
+ height: 0,
106
+ });
107
+ useLayoutEffect(() => {
108
+ const update = () => {
109
+ const guide = guideRef.current;
110
+ const mask = maskRef.current;
111
+ if (!guide || !mask)
112
+ return;
113
+ const guideRect = guide.getBoundingClientRect();
114
+ const maskRect = mask.getBoundingClientRect();
115
+ const x = guideRect.left - maskRect.left;
116
+ const y = guideRect.top - maskRect.top;
117
+ const width = guideRect.width;
118
+ const height = guideRect.height;
119
+ if (width && height) {
120
+ setMaskBox({
121
+ x,
122
+ y,
123
+ width,
124
+ height,
125
+ });
126
+ }
127
+ };
128
+ const observer = new ResizeObserver(update);
129
+ if (guideRef.current)
130
+ observer.observe(guideRef.current);
131
+ if (maskRef.current)
132
+ observer.observe(maskRef.current);
133
+ requestAnimationFrame(update);
134
+ return () => observer.disconnect();
135
+ }, [guideRef, maskRef]);
136
+ return (_jsxs(_Fragment, { children: [_jsx("svg", { className: "pointer-events-none absolute h-full w-full", children: _jsx("defs", { children: _jsxs("mask", { id: id, maskUnits: "userSpaceOnUse", children: [_jsx("rect", { x: "0", y: "0", width: "100%", height: "100%", 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: maskRef, className: "absolute inset-0 bg-black/60 backdrop-blur-sm", style: {
137
+ mask: `url(#${id})`,
138
+ WebkitMask: `url(#${id})`,
139
+ maskRepeat: 'no-repeat',
140
+ WebkitMaskRepeat: 'no-repeat',
141
+ } }), _jsx("div", { ref: guideRef, className: "border-utility-warning-700 pointer-events-none absolute left-1/2 top-1/2 z-10 aspect-[85.6/53.98] w-[calc(100%-1rem)] max-w-[24.688rem] -translate-x-1/2 -translate-y-1/2 rounded-md border-2 border-dashed" })] }));
142
+ }
143
+ function useIdDocumentField(props) {
144
+ const field = useFieldContext();
145
+ const [value, setValue] = useControllableState({
146
+ value: props.value,
147
+ defaultValue: props.defaultValue ?? '',
148
+ onChange: props.onChange,
149
+ });
150
+ const query = useFileQuery(value, {
151
+ refetchInterval({ state }) {
152
+ return !state.data || state.data.status === 'UPLOADING' ? 1000 : false;
153
+ },
154
+ });
155
+ const mutation = useUploadImageFileMutation({
156
+ onSuccess(id) {
157
+ setValue(id);
158
+ },
159
+ onMutate() {
160
+ setValue('');
161
+ },
162
+ onError(error) {
163
+ toaster.error({
164
+ title: 'Upload Failed',
165
+ description: error.message,
166
+ });
167
+ },
168
+ onSettled() {
169
+ if (inputRef.current) {
170
+ inputRef.current.value = '';
171
+ }
172
+ },
173
+ });
174
+ const inputRef = useRef(null);
175
+ const maskRef = useRef(null);
176
+ const guideRef = useRef(null);
177
+ const desktop = useMediaQuery('(min-width: 1024px)');
178
+ const camera = useCamera({
179
+ video: {
180
+ facingMode: desktop ? 'user' : 'environment',
181
+ },
182
+ });
183
+ const disclosure = useDisclosure({
184
+ onOpenChange(open) {
185
+ if (open) {
186
+ camera.open();
187
+ }
188
+ },
189
+ });
190
+ return {
191
+ field,
192
+ value,
193
+ setValue,
194
+ query,
195
+ mutation,
196
+ camera,
197
+ disclosure,
198
+ inputRef,
199
+ guideRef,
200
+ maskRef,
201
+ };
202
+ }
203
+ const [IdDocumentFieldProvider, useIdDocumentFieldContext] = createContext();
@@ -2,13 +2,14 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useFieldContext } from '@ark-ui/react';
4
4
  import Image from 'next/image';
5
- import { useRef } from 'react';
5
+ import { useId, useLayoutEffect, useRef, useState, } from 'react';
6
6
  import { twMerge } from 'tailwind-merge';
7
7
  import { useCamera } from '../../client/hooks/useCamera.js';
8
8
  import { useControllableState } from '../../client/hooks/useControllableState.js';
9
9
  import { useDisclosure } from '../../client/hooks/useDisclosure.js';
10
10
  import { useFileQuery } from '../../client/hooks/useFileQuery.js';
11
11
  import { useUploadImageFileMutation } from '../../client/hooks/useUploadImageFileMutation.js';
12
+ import { createContext } from '../../client/utils/createContext.js';
12
13
  import { toaster } from '../../client/utils/toaster.js';
13
14
  import { Camera01Icon } from '../../icons/Camera01Icon.js';
14
15
  import { CameraOffIcon } from '../../icons/CameraOffIcon.js';
@@ -23,47 +24,9 @@ import { Portal } from '../../ui/Portal/index.js';
23
24
  import { dataAttr } from '../../utils/dataAttr.js';
24
25
  import { validateFile } from '../../utils/validateFile.js';
25
26
  export function SelfieField(props) {
26
- const field = useFieldContext();
27
- const [value, setValue] = useControllableState({
28
- value: props.value,
29
- defaultValue: props.defaultValue ?? '',
30
- onChange: props.onChange,
31
- });
32
- const query = useFileQuery(value, {
33
- refetchInterval({ state }) {
34
- return !state.data || state.data.status === 'UPLOADING' ? 1000 : false;
35
- },
36
- });
37
- const mutation = useUploadImageFileMutation({
38
- onSuccess(id) {
39
- setValue(id);
40
- },
41
- onMutate() {
42
- setValue('');
43
- },
44
- onError(error) {
45
- toaster.error({
46
- title: 'Upload Failed',
47
- description: error.message,
48
- });
49
- },
50
- onSettled() {
51
- if (inputRef.current) {
52
- inputRef.current.value = '';
53
- }
54
- },
55
- });
56
- const inputRef = useRef(null);
57
- const guideRef = useRef(null);
58
- const camera = useCamera();
59
- const disclosure = useDisclosure({
60
- onOpenChange(open) {
61
- if (open) {
62
- camera.open();
63
- }
64
- },
65
- });
66
- return (_jsxs(_Fragment, { children: [_jsxs("div", { ref: props.ref, id: props.id, style: props.style, className: twMerge('border-border-primary bg-bg-primary group relative aspect-[352/180] w-full shrink-0 rounded-xl border p-xl', props.className), onDragOver: (e) => e.preventDefault(), onDragEnter: (e) => e.preventDefault(), onDragLeave: (e) => e.preventDefault(), onDrop: (e) => {
27
+ const context = useSelfieField(props);
28
+ const { field, setValue, query, mutation, camera, disclosure, inputRef, guideRef, } = context;
29
+ return (_jsxs(SelfieFieldProvider, { value: context, children: [_jsxs("div", { ref: props.ref, id: props.id, style: props.style, className: twMerge('border-border-primary bg-bg-primary group relative aspect-[352/180] w-full shrink-0 rounded-xl border p-xl', props.className), onDragOver: (e) => e.preventDefault(), onDragEnter: (e) => e.preventDefault(), onDragLeave: (e) => e.preventDefault(), onDrop: (e) => {
67
30
  e.preventDefault();
68
31
  const file = e.dataTransfer.files?.[0];
69
32
  if (!file)
@@ -103,7 +66,7 @@ export function SelfieField(props) {
103
66
  disclosure.setOpen(details.open);
104
67
  }, onExitComplete: 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)] 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 Selfie Holding Your ID" }), _jsx(Dialog.Description, { className: "text-text-tertiary-600 mt-md text-center text-xs lg:text-base", children: "Make sure your face and ID are clearly visible, with no glare\u00A0or\u00A0blur." }), _jsxs("div", { className: "relative mt-5 lg:mt-10 lg:px-3xl", children: [_jsxs("div", { className: twMerge('border-border-disabled relative w-full overflow-hidden rounded-md border bg-black lg:rounded-lg', !camera.data && !camera.error && !camera.loading
105
68
  ? 'block'
106
- : 'hidden'), children: [_jsx("video", { ...camera.videoProps }), _jsx("div", { ref: guideRef, className: "border-utility-warning-700 absolute left-1/2 top-1/2 aspect-square w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-dashed lg:w-[29.688rem]" })] }), 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: camera.error.name }), _jsx("p", { className: "text-text-tertiary-600 mt-0.5 text-center text-xs lg:mt-1 lg:text-sm", children: camera.error.message }), _jsx(Button, { size: "xs", variant: "outline", colorScheme: "gray", fullWidth: false, className: "mt-4 lg:mt-5", onClick: () => {
69
+ : 'hidden'), children: [_jsx("video", { ...camera.videoProps }), _jsx(Mask, {})] }), 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: camera.error.name }), _jsx("p", { className: "text-text-tertiary-600 mt-0.5 text-center text-xs lg:mt-1 lg:text-sm", children: camera.error.message }), _jsx(Button, { size: "xs", variant: "outline", colorScheme: "gray", fullWidth: false, className: "mt-4 lg:mt-5", onClick: () => {
107
70
  camera.reopen();
108
71
  }, children: "Try again" })] })), camera.loading && (_jsx("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(Spinner02Icon, { className: "text-text-placeholder size-8" }) })), camera.data && (_jsx("div", { className: "border-border-disabled h-auto w-full overflow-hidden rounded-md border bg-black lg:rounded-lg", children: _jsx(Image, { src: camera.data.url, alt: "", width: 600, height: 600, unoptimized: true, className: "block h-auto w-full" }) }))] }), !camera.data && !camera.error && !camera.loading && (_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 lg:w-auto", onClick: () => {
109
72
  const rect = guideRef.current?.getBoundingClientRect();
@@ -126,3 +89,102 @@ export function SelfieField(props) {
126
89
  camera.reset();
127
90
  }, children: [_jsx(RefreshCcw01Icon, { className: "size-5" }), " Retake"] })] }))] }) })] }) })] }));
128
91
  }
92
+ /**
93
+ * -------------------------------------
94
+ * Mask
95
+ * -------------------------------------
96
+ */
97
+ function Mask() {
98
+ const id = useId();
99
+ const { guideRef, maskRef } = useSelfieFieldContext();
100
+ const [maskBox, setMaskBox] = useState({
101
+ cx: 0,
102
+ cy: 0,
103
+ r: 0,
104
+ });
105
+ useLayoutEffect(() => {
106
+ const update = () => {
107
+ const guide = guideRef.current;
108
+ const mask = maskRef.current;
109
+ if (!guide || !mask)
110
+ return;
111
+ const guideRect = guide.getBoundingClientRect();
112
+ const maskRect = mask.getBoundingClientRect();
113
+ const cx = guideRect.left + guideRect.width / 2 - maskRect.left;
114
+ const cy = guideRect.top + guideRect.height / 2 - maskRect.top;
115
+ const r = guideRect.width / 2;
116
+ setMaskBox({
117
+ cx,
118
+ cy,
119
+ r,
120
+ });
121
+ };
122
+ update();
123
+ const observer = new ResizeObserver(update);
124
+ if (guideRef.current)
125
+ observer.observe(guideRef.current);
126
+ if (maskRef.current)
127
+ observer.observe(maskRef.current);
128
+ return () => observer.disconnect();
129
+ }, [guideRef, maskRef]);
130
+ return (_jsxs(_Fragment, { children: [_jsx("svg", { className: "absolute h-full w-full", children: _jsxs("mask", { id: id, maskUnits: "userSpaceOnUse", children: [_jsx("rect", { width: "100%", height: "100%", fill: "white" }), _jsx("circle", { cx: maskBox.cx, cy: maskBox.cy, r: maskBox.r, fill: "black" })] }) }), _jsx("div", { ref: maskRef, className: "absolute inset-0 bg-black/60 backdrop-blur-sm", style: {
131
+ mask: `url(#${id})`,
132
+ WebkitMask: `url(#${id})`,
133
+ } }), _jsx("div", { ref: guideRef, className: "border-utility-warning-700 absolute left-1/2 top-1/2 z-20 aspect-square w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-dashed lg:w-[29.688rem]" })] }));
134
+ }
135
+ function useSelfieField(props) {
136
+ const field = useFieldContext();
137
+ const [value, setValue] = useControllableState({
138
+ value: props.value,
139
+ defaultValue: props.defaultValue ?? '',
140
+ onChange: props.onChange,
141
+ });
142
+ const query = useFileQuery(value, {
143
+ refetchInterval({ state }) {
144
+ return !state.data || state.data.status === 'UPLOADING' ? 1000 : false;
145
+ },
146
+ });
147
+ const mutation = useUploadImageFileMutation({
148
+ onSuccess(id) {
149
+ setValue(id);
150
+ },
151
+ onMutate() {
152
+ setValue('');
153
+ },
154
+ onError(error) {
155
+ toaster.error({
156
+ title: 'Upload Failed',
157
+ description: error.message,
158
+ });
159
+ },
160
+ onSettled() {
161
+ if (inputRef.current) {
162
+ inputRef.current.value = '';
163
+ }
164
+ },
165
+ });
166
+ const inputRef = useRef(null);
167
+ const maskRef = useRef(null);
168
+ const guideRef = useRef(null);
169
+ const camera = useCamera();
170
+ const disclosure = useDisclosure({
171
+ onOpenChange(open) {
172
+ if (open) {
173
+ camera.open();
174
+ }
175
+ },
176
+ });
177
+ return {
178
+ field,
179
+ value,
180
+ setValue,
181
+ query,
182
+ mutation,
183
+ camera,
184
+ disclosure,
185
+ inputRef,
186
+ guideRef,
187
+ maskRef,
188
+ };
189
+ }
190
+ const [SelfieFieldProvider, useSelfieFieldContext] = createContext();
@@ -0,0 +1,4 @@
1
+ export declare const BRANCH_CODES: {
2
+ code: string;
3
+ name: string;
4
+ }[];
@@ -0,0 +1,42 @@
1
+ export const BRANCH_CODES = [
2
+ {
3
+ code: 'BRCAL',
4
+ name: 'Bingo Republic 2nd floor Primark Center Deparo St., Caloocan City',
5
+ },
6
+ {
7
+ code: 'BRNAG',
8
+ name: 'Bingo Republic 3rd floor Robinsons Mall, Naga City, Camarines Sur',
9
+ },
10
+ {
11
+ code: 'BRANT',
12
+ name: 'Bingo Republic 2nd floor Robinsons Mall, San Vicente,Antique',
13
+ },
14
+ {
15
+ code: 'BRCLA',
16
+ name: 'Clark',
17
+ },
18
+ {
19
+ code: 'BRLAG',
20
+ name: 'Laguna',
21
+ },
22
+ {
23
+ code: 'BREAS',
24
+ name: 'Eastwood City, Quezon City',
25
+ },
26
+ {
27
+ code: 'BRMAR',
28
+ name: 'Bingo ng Bayan 4th floor Marikina Public Market, Marikina City',
29
+ },
30
+ {
31
+ code: 'BRILO',
32
+ name: 'Iloilo',
33
+ },
34
+ {
35
+ code: 'BRFIM',
36
+ name: 'Fisher Mall,Quezon City',
37
+ },
38
+ {
39
+ code: 'BRCAC',
40
+ name: 'Villa Caceres Hotel, Naga City,Camsur',
41
+ },
42
+ ];
@@ -0,0 +1,10 @@
1
+ export declare const ACCOUNT_GRAPHQL_ENDPOINT: string;
2
+ export declare const FILE_GRAPHQL_ENDPOINT: string;
3
+ export declare const GAME_GRAPHQL_ENDPOINT: string;
4
+ export declare const PORTAL_GRAPHQL_ENDPOINT: string;
5
+ export declare const REPORT_GRAPHQL_ENDPOINT: string;
6
+ export declare const TRIGGER_GRAPHQL_ENDPOINT: string;
7
+ export declare const WALLET_GRAPHQL_ENDPOINT: string;
8
+ export declare const AUTH_ENDPOINT: string;
9
+ export declare const CMS_PORTAL_ENDPOINT: string;
10
+ export declare const STATIC_ENDPOINT: string;
@@ -0,0 +1,41 @@
1
+ import { ENVIRONMENT } from './envVars.js';
2
+ export const ACCOUNT_GRAPHQL_ENDPOINT = {
3
+ development: 'https://account.development.opexa.io/graphql',
4
+ production: 'https://account.opexa.io/graphql',
5
+ }[ENVIRONMENT];
6
+ export const FILE_GRAPHQL_ENDPOINT = {
7
+ development: 'https://file.development.opexa.io/graphql',
8
+ production: 'https://file.opexa.io/graphql',
9
+ }[ENVIRONMENT];
10
+ export const GAME_GRAPHQL_ENDPOINT = {
11
+ development: 'https://game.development.opexa.io/graphql',
12
+ production: 'https://game.opexa.io/graphql',
13
+ }[ENVIRONMENT];
14
+ export const PORTAL_GRAPHQL_ENDPOINT = {
15
+ development: 'https://portal.development.opexa.io/graphql',
16
+ production: 'https://portal.opexa.io/graphql',
17
+ }[ENVIRONMENT];
18
+ export const REPORT_GRAPHQL_ENDPOINT = {
19
+ development: 'https://report.development.opexa.io/graphql',
20
+ production: 'https://report.opexa.io/graphql',
21
+ }[ENVIRONMENT];
22
+ export const TRIGGER_GRAPHQL_ENDPOINT = {
23
+ development: 'https://trigger.development.opexa.io/graphql',
24
+ production: 'https://trigger.opexa.io/graphql',
25
+ }[ENVIRONMENT];
26
+ export const WALLET_GRAPHQL_ENDPOINT = {
27
+ development: 'https://wallet.development.opexa.io/graphql',
28
+ production: 'https://wallet.opexa.io/graphql',
29
+ }[ENVIRONMENT];
30
+ export const AUTH_ENDPOINT = {
31
+ development: 'https://auth.development.opexa.io',
32
+ production: 'https://auth.opexa.io',
33
+ }[ENVIRONMENT];
34
+ export const CMS_PORTAL_ENDPOINT = {
35
+ development: 'https://portal-api.opexacms.io',
36
+ production: 'https://portal-api.opexacms.io',
37
+ }[ENVIRONMENT];
38
+ export const STATIC_ENDPOINT = {
39
+ development: 'https://static.development.atalos.io',
40
+ production: 'https://static.atalos.io',
41
+ }[ENVIRONMENT];
@@ -1,5 +1,4 @@
1
- import type { GameProvider } from '@opexa/portal-sdk-core';
2
- import type { GameProviderData } from '../types';
1
+ import type { GameProvider, GameProviderData } from '../types';
3
2
  export declare const GAME_PROVIDER_DATA: Record<GameProvider, GameProviderData>;
4
3
  export declare const GAME_PROVIDERS: ["ALIZE", "BGAMING", "BOOONGO", "EVOPLAY", "BTI", "CQ9", "DARWIN", "DG", "DRBINGO", "E2E", "ETENGJUE", "EVOLUTION", "EVOLUTION_REDTIGER", "EZUGI", "FACHAI", "HABANERO", "HACKSAW", "HOLLYWOODTV", "JDB", "JILI", "JDBGTF", "JOKER", "JDBSPRIBE", "JILI_BINGO", "KINGMAKER", "KINGMIDAS", "MEGA2SPIN", "MICROGAMING", "MEGABALL", "ONEAPI_EVOLUTION", "PGSOFT", "PLAYTECH", "PRAGMATICPLAY", "RELAXGAMING", "RTG", "SABA", "SPINIX", "SPRIBE", "YELLOWBAT", "EVOLUTIONNETENT", "EVOLUTION_NETENT"];
5
4
  export declare const LEGACY_GAME_PROVIDERS: ["JILI", "PGSOFT", "FACHAI", "BTI", "DG", "PLAYTECH", "E2E", "ONEAPI_EVOLUTION", "CQ9", "JDB", "HABANERO", "SPINIX", "JOKER", "HACKSAW", "EVOLUTIONNETENT", "JDBGTF", "JDBSPRIBE", "MICROGAMING", "RELAXGAMING", "EVOPLAY", "BOOONGO", "BGAMING", "KINGMAKER", "KINGMIDAS", "YELLOWBAT", "ETENGJUE", "SABA", "PRAGMATICPLAY", "SPRIBE", "EZUGI", "ALIZE"];
@@ -283,6 +283,12 @@ export const GAME_PROVIDER_DATA = {
283
283
  slug: 'evolution-netent',
284
284
  logo: evolutionNetent,
285
285
  },
286
+ DIGITAIN: {
287
+ id: 'DIGITAIN',
288
+ name: 'Digitain',
289
+ slug: 'digitain',
290
+ logo: '',
291
+ },
286
292
  };
287
293
  export const GAME_PROVIDERS = [
288
294
  'ALIZE',
@@ -1,4 +1,3 @@
1
- import type { GameType } from '@opexa/portal-sdk-core';
2
- import type { GameTypeData } from '../types';
1
+ import type { GameType, GameTypeData } from '../types';
3
2
  export declare const GAME_TYPE_DATA: Record<GameType, GameTypeData>;
4
3
  export declare const GAME_TYPES: ["ARCADE", "BINGO", "FISHING", "GAMES", "LIVE", "NUMERICAL", "SLOTS", "SPECIALTY", "SPORTS", "TABLE"];
@@ -1 +1,2 @@
1
1
  export declare const RECAPTCHA_HEADER_KEY: string;
2
+ export declare const TEST_PASS_HEADER_KEY: string;
@@ -1 +1,2 @@
1
1
  export const RECAPTCHA_HEADER_KEY = 'Google-Recaptcha-Response';
2
+ export const TEST_PASS_HEADER_KEY = 'Test-Pass';
@@ -1,3 +1,3 @@
1
- import type { SecretQuestion } from '@opexa/portal-sdk-core';
1
+ import type { SecretQuestion } from '../types';
2
2
  export declare const SECRET_QUESTIONS: ["BEST_CHILDHOOD_FRIEND", "BIRTH_PLACE", "FAVORITE_BOOK", "FAVORITE_MOVIE", "FAVORITE_TEACHER", "FIRST_CAR", "FIRST_PET", "FIRST_SCHOOL", "MOTHERS_MAIDEN_NAME", "PARENTS_MET_CITY"];
3
3
  export declare const SECRET_QUESTIONS_MAP: Record<SecretQuestion, string>;