@opexa/portal-components 0.1.33 → 0.1.35

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 (71) hide show
  1. package/dist/client/hooks/useGlobalStore.d.ts +8 -0
  2. package/dist/client/hooks/useGlobalStore.js +42 -0
  3. package/dist/client/hooks/useMemberWalletAccount.d.ts +3 -0
  4. package/dist/client/hooks/useMemberWalletAccount.js +31 -0
  5. package/dist/client/hooks/useUpdateDailyBetLimit.d.ts +3 -0
  6. package/dist/client/hooks/useUpdateDailyBetLimit.js +20 -0
  7. package/dist/client/hooks/useUpdateDailyDepositLimit.d.ts +3 -0
  8. package/dist/client/hooks/useUpdateDailyDepositLimit.js +20 -0
  9. package/dist/client/hooks/useUpdateMonthlyBetLimit.d.ts +3 -0
  10. package/dist/client/hooks/useUpdateMonthlyBetLimit.js +20 -0
  11. package/dist/client/hooks/useUpdateMonthlyDepositLimit.d.ts +3 -0
  12. package/dist/client/hooks/useUpdateMonthlyDepositLimit.js +20 -0
  13. package/dist/components/BetDepositLimit/BetDepositLimitModal.d.ts +3 -2
  14. package/dist/components/BetDepositLimit/BetDepositLimitModal.js +40 -9
  15. package/dist/components/BetDepositLimit/BetDepositLimitReachedModal.d.ts +5 -0
  16. package/dist/components/BetDepositLimit/BetDepositLimitReachedModal.js +24 -0
  17. package/dist/components/BetDepositLimit/DepositLimitReached.js +2 -2
  18. package/dist/components/DepositWithdrawal/DepositWithdrawal.lazy.js +22 -5
  19. package/dist/components/GameLaunch/GameLaunchTrigger.js +23 -0
  20. package/dist/components/GamesSearch/GamesSearch.js +30 -8
  21. package/dist/components/ResponsibleGamingLimits/ResponsibleGamingLimitsForm.lazy.js +92 -73
  22. package/dist/components/Search/Search.lazy.js +36 -7
  23. package/dist/schemas/forgotPasswordSchema.d.ts +4 -4
  24. package/dist/services/account.d.ts +40 -0
  25. package/dist/services/account.js +41 -1
  26. package/dist/services/queries.d.ts +6 -1
  27. package/dist/services/queries.js +40 -0
  28. package/dist/services/wallet.d.ts +16 -0
  29. package/dist/services/wallet.js +5 -1
  30. package/dist/types/index.d.ts +8 -0
  31. package/dist/ui/AlertDialog/AlertDialog.d.ts +154 -154
  32. package/dist/ui/AlertDialog/alertDialog.recipe.d.ts +14 -14
  33. package/dist/ui/Badge/Badge.d.ts +12 -12
  34. package/dist/ui/Badge/badge.anatomy.d.ts +1 -1
  35. package/dist/ui/Badge/badge.recipe.d.ts +3 -3
  36. package/dist/ui/Carousel/Carousel.d.ts +45 -45
  37. package/dist/ui/Carousel/carousel.recipe.d.ts +5 -5
  38. package/dist/ui/Checkbox/Checkbox.d.ts +23 -23
  39. package/dist/ui/Checkbox/checkbox.recipe.d.ts +3 -3
  40. package/dist/ui/Clipboard/Clipboard.d.ts +18 -18
  41. package/dist/ui/Clipboard/clipboard.recipe.d.ts +3 -3
  42. package/dist/ui/Collapsible/Collapsible.d.ts +20 -20
  43. package/dist/ui/Collapsible/collapsible.recipe.d.ts +5 -5
  44. package/dist/ui/Combobox/Combobox.d.ts +42 -42
  45. package/dist/ui/Combobox/combobox.recipe.d.ts +3 -3
  46. package/dist/ui/DatePicker/DatePicker.d.ts +72 -72
  47. package/dist/ui/DatePicker/datePicker.recipe.d.ts +3 -3
  48. package/dist/ui/Dialog/Dialog.d.ts +33 -33
  49. package/dist/ui/Dialog/dialog.recipe.d.ts +3 -3
  50. package/dist/ui/Drawer/Drawer.d.ts +33 -33
  51. package/dist/ui/Drawer/drawer.recipe.d.ts +3 -3
  52. package/dist/ui/Menu/Menu.d.ts +90 -90
  53. package/dist/ui/Menu/menu.recipe.d.ts +5 -5
  54. package/dist/ui/PasswordInput/PasswordInput.d.ts +18 -18
  55. package/dist/ui/PasswordInput/passwordInput.recipe.d.ts +3 -3
  56. package/dist/ui/Popover/Popover.d.ts +88 -88
  57. package/dist/ui/Popover/popover.recipe.d.ts +8 -8
  58. package/dist/ui/Select/Select.d.ts +45 -45
  59. package/dist/ui/Select/select.recipe.d.ts +3 -3
  60. package/dist/ui/Table/Table.d.ts +21 -21
  61. package/dist/ui/Table/table.anatomy.d.ts +1 -1
  62. package/dist/ui/Table/table.recipe.d.ts +3 -3
  63. package/dist/ui/Tabs/Tabs.d.ts +15 -15
  64. package/dist/ui/Tabs/tabs.recipe.d.ts +3 -3
  65. package/dist/utils/mutationKeys.d.ts +4 -0
  66. package/dist/utils/mutationKeys.js +16 -0
  67. package/dist/utils/queryKeys.d.ts +1 -0
  68. package/dist/utils/queryKeys.js +1 -0
  69. package/dist/utils/sanitizeGamesSearch.d.ts +5 -0
  70. package/dist/utils/sanitizeGamesSearch.js +20 -0
  71. package/package.json +1 -1
@@ -77,6 +77,13 @@ export interface BetDepositLimitStore extends PopupStore {
77
77
  setRequestedLimit: (limit: number) => void;
78
78
  openModal: (type: LimitType, period: LimitPeriod, currentLimit: number, requestedLimit: number) => void;
79
79
  }
80
+ export interface BetDepositLimitReachedStore extends PopupStore {
81
+ type: LimitType;
82
+ setType: (type: LimitType) => void;
83
+ period: LimitPeriod;
84
+ setPeriod: (period: LimitPeriod) => void;
85
+ openModal: (type: LimitType, period: LimitPeriod) => void;
86
+ }
80
87
  export interface GlobalStore {
81
88
  signUp: PopupStore;
82
89
  signIn: PopupStore;
@@ -103,6 +110,7 @@ export interface GlobalStore {
103
110
  responsibleGamingReminder: ResponsibleGamingReminderStore;
104
111
  pendingBonus: HasPendingBonusStore;
105
112
  betDepositLimit: BetDepositLimitStore;
113
+ betDepositLimitReached: BetDepositLimitReachedStore;
106
114
  kycVerificationStatus: PopupStore;
107
115
  kycAccountVerificationRequired: PopupStore;
108
116
  bankInformationDetails: PopupStore;
@@ -566,6 +566,48 @@ export const useGlobalStore = create()(devtools(subscribeWithSelector((set) => (
566
566
  }));
567
567
  },
568
568
  },
569
+ betDepositLimitReached: {
570
+ open: false,
571
+ setOpen(open) {
572
+ set((prev) => ({
573
+ betDepositLimitReached: {
574
+ ...prev.betDepositLimitReached,
575
+ open,
576
+ '~touched': true,
577
+ },
578
+ }));
579
+ },
580
+ '~touched': false,
581
+ type: 'bet',
582
+ setType(type) {
583
+ set((prev) => ({
584
+ betDepositLimitReached: {
585
+ ...prev.betDepositLimitReached,
586
+ type,
587
+ },
588
+ }));
589
+ },
590
+ period: 'daily',
591
+ setPeriod(period) {
592
+ set((prev) => ({
593
+ betDepositLimitReached: {
594
+ ...prev.betDepositLimitReached,
595
+ period,
596
+ },
597
+ }));
598
+ },
599
+ openModal(type, period) {
600
+ set((prev) => ({
601
+ betDepositLimitReached: {
602
+ ...prev.betDepositLimitReached,
603
+ type,
604
+ period,
605
+ open: true,
606
+ '~touched': true,
607
+ },
608
+ }));
609
+ },
610
+ },
569
611
  isNonRegulated: false,
570
612
  setIsNonRegulated: (isNonRegulated) => set((state) => ({
571
613
  ...state,
@@ -0,0 +1,3 @@
1
+ import type { Query } from '../../types';
2
+ import { type MemberWalletAccount } from '../../services/wallet';
3
+ export declare const useMemberWalletQuery: Query<MemberWalletAccount['self'] | null>;
@@ -0,0 +1,31 @@
1
+ import { useQuery } from '@tanstack/react-query';
2
+ import invariant from 'tiny-invariant';
3
+ import { getMemberWalletAccount, } from '../../services/wallet.js';
4
+ import { getQueryClient } from '../../utils/getQueryClient.js';
5
+ import { getMemberWalletAccountQueryKey, getSessionQueryKey, } from '../../utils/queryKeys.js';
6
+ import { getSession } from '../services/getSession.js';
7
+ import { useSessionQuery } from './useSessionQuery.js';
8
+ export const useMemberWalletQuery = (config) => {
9
+ const sessionQuery = useSessionQuery();
10
+ return useQuery({
11
+ ...config,
12
+ enabled: config?.enabled === false
13
+ ? false
14
+ : sessionQuery.data?.status === 'authenticated',
15
+ queryKey: getMemberWalletAccountQueryKey(),
16
+ queryFn: async ({ signal }) => {
17
+ const session = await getQueryClient().fetchQuery({
18
+ queryKey: getSessionQueryKey(),
19
+ queryFn: async () => getSession(),
20
+ });
21
+ invariant(session.status === 'authenticated');
22
+ const memberWallet = await getMemberWalletAccount({
23
+ signal,
24
+ headers: {
25
+ Authorization: `Bearer ${session.token}`,
26
+ },
27
+ });
28
+ return memberWallet ?? null;
29
+ },
30
+ });
31
+ };
@@ -0,0 +1,3 @@
1
+ import { type UpdateDailyBetLimitInput } from '../../services/account';
2
+ import type { Mutation } from '../../types';
3
+ export declare const useUpdateDailyBetLimitMutation: Mutation<void, UpdateDailyBetLimitInput>;
@@ -0,0 +1,20 @@
1
+ import { useMutation } from '@tanstack/react-query';
2
+ import invariant from 'tiny-invariant';
3
+ import { updateDailyBetLimit, } from '../../services/account.js';
4
+ import { getUpdateDailyBetLimitMutationKey } from '../../utils/mutationKeys.js';
5
+ import { getSession } from '../services/getSession.js';
6
+ export const useUpdateDailyBetLimitMutation = (config) => {
7
+ return useMutation({
8
+ ...config,
9
+ mutationKey: getUpdateDailyBetLimitMutationKey(),
10
+ mutationFn: async (input) => {
11
+ const session = await getSession();
12
+ invariant(session.status === 'authenticated');
13
+ await updateDailyBetLimit(input.dailyBetLimit, {
14
+ headers: {
15
+ Authorization: `Bearer ${session.token}`,
16
+ },
17
+ });
18
+ },
19
+ });
20
+ };
@@ -0,0 +1,3 @@
1
+ import { type UpdateDailyDepositLimitInput } from '../../services/account';
2
+ import type { Mutation } from '../../types';
3
+ export declare const useUpdateDailyDepositLimitMutation: Mutation<void, UpdateDailyDepositLimitInput>;
@@ -0,0 +1,20 @@
1
+ import { useMutation } from '@tanstack/react-query';
2
+ import invariant from 'tiny-invariant';
3
+ import { updateDailyDepositLimit, } from '../../services/account.js';
4
+ import { getUpdateDailyDepositLimitMutationKey } from '../../utils/mutationKeys.js';
5
+ import { getSession } from '../services/getSession.js';
6
+ export const useUpdateDailyDepositLimitMutation = (config) => {
7
+ return useMutation({
8
+ ...config,
9
+ mutationKey: getUpdateDailyDepositLimitMutationKey(),
10
+ mutationFn: async (input) => {
11
+ const session = await getSession();
12
+ invariant(session.status === 'authenticated');
13
+ await updateDailyDepositLimit(input.dailyDepositLimit, {
14
+ headers: {
15
+ Authorization: `Bearer ${session.token}`,
16
+ },
17
+ });
18
+ },
19
+ });
20
+ };
@@ -0,0 +1,3 @@
1
+ import { type UpdateMonthlyBetLimitInput } from '../../services/account';
2
+ import type { Mutation } from '../../types';
3
+ export declare const useUpdateMonthlyBetLimitMutation: Mutation<void, UpdateMonthlyBetLimitInput>;
@@ -0,0 +1,20 @@
1
+ import { useMutation } from '@tanstack/react-query';
2
+ import invariant from 'tiny-invariant';
3
+ import { updateMonthlyBetLimit, } from '../../services/account.js';
4
+ import { getUpdateMonthlyBetLimitMutationKey } from '../../utils/mutationKeys.js';
5
+ import { getSession } from '../services/getSession.js';
6
+ export const useUpdateMonthlyBetLimitMutation = (config) => {
7
+ return useMutation({
8
+ ...config,
9
+ mutationKey: getUpdateMonthlyBetLimitMutationKey(),
10
+ mutationFn: async (input) => {
11
+ const session = await getSession();
12
+ invariant(session.status === 'authenticated');
13
+ await updateMonthlyBetLimit(input.monthlyBetLimit, {
14
+ headers: {
15
+ Authorization: `Bearer ${session.token}`,
16
+ },
17
+ });
18
+ },
19
+ });
20
+ };
@@ -0,0 +1,3 @@
1
+ import { type UpdateMonthlyDepositLimitInput } from '../../services/account';
2
+ import type { Mutation } from '../../types';
3
+ export declare const useUpdateMonthlyDepositLimitMutation: Mutation<void, UpdateMonthlyDepositLimitInput>;
@@ -0,0 +1,20 @@
1
+ import { useMutation } from '@tanstack/react-query';
2
+ import invariant from 'tiny-invariant';
3
+ import { updateMonthlyDepositLimit, } from '../../services/account.js';
4
+ import { getUpdateMonthlyDepositLimitMutationKey } from '../../utils/mutationKeys.js';
5
+ import { getSession } from '../services/getSession.js';
6
+ export const useUpdateMonthlyDepositLimitMutation = (config) => {
7
+ return useMutation({
8
+ ...config,
9
+ mutationKey: getUpdateMonthlyDepositLimitMutationKey(),
10
+ mutationFn: async (input) => {
11
+ const session = await getSession();
12
+ invariant(session.status === 'authenticated');
13
+ await updateMonthlyDepositLimit(input.monthlyDepositLimit, {
14
+ headers: {
15
+ Authorization: `Bearer ${session.token}`,
16
+ },
17
+ });
18
+ },
19
+ });
20
+ };
@@ -1,4 +1,5 @@
1
1
  export interface BetDepositLimitModalProps {
2
- onConfirm?: () => void;
2
+ onSuccess?: (type: 'bet' | 'deposit', period: 'daily' | 'monthly', requestedLimit: number) => void;
3
+ onError?: (type: 'bet' | 'deposit', period: 'daily' | 'monthly') => void;
3
4
  }
4
- export declare function BetDepositLimitModal({ onConfirm }: BetDepositLimitModalProps): import("react/jsx-runtime").JSX.Element;
5
+ export declare function BetDepositLimitModal({ onSuccess, onError, }: BetDepositLimitModalProps): import("react/jsx-runtime").JSX.Element;
@@ -1,15 +1,19 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useShallow } from 'zustand/shallow';
4
- import { useFeatureFlag } from '../../client/hooks/useFeatureFlag.js';
4
+ import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
5
+ import { useUpdateDailyBetLimitMutation } from '../../client/hooks/useUpdateDailyBetLimit.js';
6
+ import { useUpdateDailyDepositLimitMutation } from '../../client/hooks/useUpdateDailyDepositLimit.js';
7
+ import { useUpdateMonthlyBetLimitMutation } from '../../client/hooks/useUpdateMonthlyBetLimit.js';
8
+ import { useUpdateMonthlyDepositLimitMutation } from '../../client/hooks/useUpdateMonthlyDepositLimit.js';
5
9
  import { AlertTriangleIcon } from '../../icons/AlertTriangle.js';
6
10
  import { XIcon } from '../../icons/XIcon.js';
7
11
  import { Button } from '../../ui/Button/index.js';
8
12
  import { Dialog } from '../../ui/Dialog/index.js';
9
13
  import { Portal } from '../../ui/Portal/index.js';
10
- import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
11
- export function BetDepositLimitModal({ onConfirm }) {
12
- const { enabled } = useFeatureFlag();
14
+ import { getAccountQueryKey } from '../../utils/queryKeys.js';
15
+ import { getQueryClient } from '../../utils/getQueryClient.js';
16
+ export function BetDepositLimitModal({ onSuccess, onError, }) {
13
17
  const { open, type, period, currentLimit, requestedLimit, setOpen } = useGlobalStore(useShallow((state) => ({
14
18
  open: state.betDepositLimit.open,
15
19
  type: state.betDepositLimit.type,
@@ -18,6 +22,14 @@ export function BetDepositLimitModal({ onConfirm }) {
18
22
  requestedLimit: state.betDepositLimit.requestedLimit,
19
23
  setOpen: state.betDepositLimit.setOpen,
20
24
  })));
25
+ const updateDailyBetLimit = useUpdateDailyBetLimitMutation();
26
+ const updateMonthlyBetLimit = useUpdateMonthlyBetLimitMutation();
27
+ const updateDailyDepositLimit = useUpdateDailyDepositLimitMutation();
28
+ const updateMonthlyDepositLimit = useUpdateMonthlyDepositLimitMutation();
29
+ const isPending = updateDailyBetLimit.isPending ||
30
+ updateMonthlyBetLimit.isPending ||
31
+ updateDailyDepositLimit.isPending ||
32
+ updateMonthlyDepositLimit.isPending;
21
33
  const isIncrease = requestedLimit > currentLimit;
22
34
  const changeAmount = Math.abs(requestedLimit - currentLimit);
23
35
  const formatPeso = (value) => {
@@ -37,13 +49,32 @@ export function BetDepositLimitModal({ onConfirm }) {
37
49
  }
38
50
  return `Your ${period} ${type} limit has been lowered and is now active.`;
39
51
  };
52
+ const mutationOptions = {
53
+ onSuccess: () => {
54
+ getQueryClient().invalidateQueries({ queryKey: getAccountQueryKey() });
55
+ setOpen(false);
56
+ onSuccess?.(type, period, requestedLimit);
57
+ },
58
+ onError: () => {
59
+ setOpen(false);
60
+ onError?.(type, period);
61
+ },
62
+ };
40
63
  const handleConfirm = () => {
41
- setOpen(false);
42
- if (onConfirm) {
43
- onConfirm();
64
+ if (type === 'bet' && period === 'daily') {
65
+ updateDailyBetLimit.mutate({ dailyBetLimit: requestedLimit }, mutationOptions);
66
+ }
67
+ else if (type === 'bet' && period === 'monthly') {
68
+ updateMonthlyBetLimit.mutate({ monthlyBetLimit: requestedLimit }, mutationOptions);
69
+ }
70
+ else if (type === 'deposit' && period === 'daily') {
71
+ updateDailyDepositLimit.mutate({ dailyDepositLimit: requestedLimit }, mutationOptions);
72
+ }
73
+ else if (type === 'deposit' && period === 'monthly') {
74
+ updateMonthlyDepositLimit.mutate({ monthlyDepositLimit: requestedLimit }, mutationOptions);
44
75
  }
45
76
  };
46
- return (_jsx(Dialog.Root, { open: open && enabled, onOpenChange: (details) => {
77
+ return (_jsx(Dialog.Root, { open: open, onOpenChange: (details) => {
47
78
  setOpen(details.open);
48
- }, closeOnInteractOutside: false, lazyMount: true, unmountOnExit: true, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, { className: "!z-[calc(var(--z-dialog)+3)]" }), _jsx(Dialog.Positioner, { className: "!z-[calc(var(--z-dialog)+4)] flex items-center justify-center", children: _jsxs(Dialog.Content, { className: "mx-auto max-h-[90vh] min-w-[21.438rem] max-w-[21.438rem] overflow-y-auto rounded-xl p-3xl lg:min-w-[25rem] lg:max-w-[25rem]", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsxs("div", { className: "flex flex-col items-center", children: [_jsx("div", { className: "mx-auto flex size-12 items-center justify-center rounded-full bg-bg-brand-secondary", children: _jsx(AlertTriangleIcon, { className: "size-6 text-text-brand-700" }) }), _jsx("h2", { className: "mt-lg text-center font-semibold text-lg text-text-primary-900 xl:mt-xl", children: title }), _jsx("p", { className: "mt-xs text-center text-sm text-text-secondary-700 leading-relaxed", children: getDescription() }), _jsxs("div", { className: "mt-lg flex w-full select-none flex-col gap-y-2 rounded-xl border border-border-primary bg-bg-secondary px-5 py-4 text-sm", children: [_jsxs("div", { className: "flex justify-between py-0.5", children: [_jsx("span", { className: "text-text-tertiary-600", children: isIncrease ? 'Current limit:' : 'Previous limit:' }), _jsx("span", { className: "font-semibold text-text-primary-900", children: formatPeso(currentLimit) })] }), _jsxs("div", { className: "flex justify-between py-0.5", children: [_jsx("span", { className: "text-text-tertiary-600", children: isIncrease ? 'Requested limit:' : 'New limit:' }), _jsx("span", { className: "font-semibold text-text-primary-900", children: formatPeso(requestedLimit) })] }), _jsxs("div", { className: "flex justify-between py-0.5", children: [_jsx("span", { className: "text-text-tertiary-600", children: isIncrease ? 'Increase amount:' : 'Decrease amount:' }), _jsx("span", { className: "font-semibold text-text-primary-900", children: formatPeso(changeAmount) })] }), _jsxs("div", { className: "flex justify-between py-0.5", children: [_jsx("span", { className: "text-text-tertiary-600", children: isIncrease ? 'Status:' : 'Effective:' }), _jsx("span", { className: "font-semibold text-text-primary-900", children: isIncrease ? 'Pending Approval' : 'Immediately' })] })] }), _jsx("div", { className: "mt-3xl flex w-full flex-col gap-2 text-center lg:mt-4xl", children: _jsx(Button, { className: "w-full", onClick: handleConfirm, type: "button", children: "Confirm" }) })] })] }) })] }) }));
79
+ }, closeOnInteractOutside: false, lazyMount: true, unmountOnExit: true, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, { className: "!z-[calc(var(--z-dialog)+3)]" }), _jsx(Dialog.Positioner, { className: "!z-[calc(var(--z-dialog)+4)] flex items-center justify-center", children: _jsxs(Dialog.Content, { className: "mx-auto max-h-[90vh] min-w-[21.438rem] max-w-[21.438rem] overflow-y-auto rounded-xl p-3xl lg:min-w-[25rem] lg:max-w-[25rem]", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsxs("div", { className: "flex flex-col items-center", children: [_jsx("div", { className: "mx-auto flex size-12 items-center justify-center rounded-full bg-bg-brand-secondary", children: _jsx(AlertTriangleIcon, { className: "size-6 text-text-brand-700" }) }), _jsx("h2", { className: "mt-lg text-center font-semibold text-lg text-text-primary-900 xl:mt-xl", children: title }), _jsx("p", { className: "mt-xs text-center text-sm text-text-secondary-700 leading-relaxed", children: getDescription() }), _jsxs("div", { className: "mt-lg flex w-full select-none flex-col gap-y-2 rounded-xl border border-border-primary bg-bg-secondary px-5 py-4 text-sm", children: [_jsxs("div", { className: "flex justify-between py-0.5", children: [_jsx("span", { className: "text-text-tertiary-600", children: isIncrease ? 'Current limit:' : 'Previous limit:' }), _jsx("span", { className: "font-semibold text-text-primary-900", children: formatPeso(currentLimit) })] }), _jsxs("div", { className: "flex justify-between py-0.5", children: [_jsx("span", { className: "text-text-tertiary-600", children: isIncrease ? 'Requested limit:' : 'New limit:' }), _jsx("span", { className: "font-semibold text-text-primary-900", children: formatPeso(requestedLimit) })] }), _jsxs("div", { className: "flex justify-between py-0.5", children: [_jsx("span", { className: "text-text-tertiary-600", children: isIncrease ? 'Increase amount:' : 'Decrease amount:' }), _jsx("span", { className: "font-semibold text-text-primary-900", children: formatPeso(changeAmount) })] }), _jsxs("div", { className: "flex justify-between py-0.5", children: [_jsx("span", { className: "text-text-tertiary-600", children: isIncrease ? 'Status:' : 'Effective:' }), _jsx("span", { className: "font-semibold text-text-primary-900", children: isIncrease ? 'Pending Approval' : 'Immediately' })] })] }), _jsx("div", { className: "mt-3xl flex w-full flex-col gap-2 text-center lg:mt-4xl", children: _jsx(Button, { className: "w-full", onClick: handleConfirm, type: "button", disabled: isPending, children: isPending ? 'Saving...' : 'Confirm' }) })] })] }) })] }) }));
49
80
  }
@@ -0,0 +1,5 @@
1
+ export interface BetDepositLimitReachedModalProps {
2
+ type: 'bet' | 'deposit';
3
+ period: 'daily' | 'monthly';
4
+ }
5
+ export declare function BetDepositLimitReachedModal({ type, period, }: BetDepositLimitReachedModalProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,24 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useShallow } from 'zustand/shallow';
4
+ import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
5
+ import { AlertTriangleIcon } from '../../icons/AlertTriangle.js';
6
+ import { XIcon } from '../../icons/XIcon.js';
7
+ import { Dialog } from '../../ui/Dialog/index.js';
8
+ import { Portal } from '../../ui/Portal/index.js';
9
+ export function BetDepositLimitReachedModal({ type, period, }) {
10
+ const globalStore = useGlobalStore(useShallow((state) => ({
11
+ betDepositLimitReached: state.betDepositLimitReached,
12
+ })));
13
+ const title = type === 'bet' ? 'Bet Limit Reached' : 'Deposit Limit Reached';
14
+ const message = type === 'bet'
15
+ ? period === 'daily'
16
+ ? 'You’ve reached your daily bet limit, so this bet can’t be placed right now. You can place bets again once your limit resets tomorrow.'
17
+ : 'You’ve reached your monthly bet limit, so this bet can’t be placed right now. You can place bets again once your limit resets next month.'
18
+ : period === 'daily'
19
+ ? 'You’ve reached your daily bet limit, so this bet can’t be placed right now.\nYour daily limit resets tomorrow at 12:00 AM.'
20
+ : 'You’ve reached your monthly bet limit, so this bet can’t be placed right now.\nYour monthly limit resets on the 1st day of next month.';
21
+ return (_jsx(Dialog.Root, { open: globalStore.betDepositLimitReached.open, onOpenChange: (details) => {
22
+ globalStore.betDepositLimitReached.setOpen(details.open);
23
+ }, closeOnInteractOutside: false, lazyMount: true, unmountOnExit: true, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, { className: "!z-[calc(var(--z-dialog)+3)]" }), _jsx(Dialog.Positioner, { className: "!z-[calc(var(--z-dialog)+4)] flex items-center justify-center", children: _jsxs(Dialog.Content, { className: "mx-auto max-h-[90vh] min-w-[21.438rem] max-w-[21.438rem] overflow-y-auto rounded-xl p-3xl lg:min-w-[25rem] lg:max-w-[25rem]", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsxs("div", { className: "flex flex-col items-center", children: [_jsx("div", { className: "mx-auto flex size-12 items-center justify-center rounded-full bg-bg-brand-secondary", children: _jsx(AlertTriangleIcon, { className: "size-6 text-text-brand-700" }) }), _jsx("h2", { className: "mt-lg text-center font-semibold text-lg text-text-primary-900 xl:mt-xl", children: title }), _jsx("p", { className: "mt-xs text-center text-sm text-text-secondary-700 leading-relaxed", children: message })] })] }) })] }) }));
24
+ }
@@ -6,7 +6,7 @@ export function DepositLimitReached({ type, period, responsibleGamingUrl = '/res
6
6
  const capType = type.charAt(0).toUpperCase() + type.slice(1);
7
7
  const title = `${capPeriod} ${capType} Limit Reached`;
8
8
  const resetMessage = period === 'daily'
9
- ? "You've reached your daily deposit limit, so you can't deposit right now. Your limit will reset tomorrow at midnight."
10
- : "You've reached your monthly deposit limit, so you can't deposit right now. Your limit will reset on the 1st day of next month.";
9
+ ? 'Youve reached your daily deposit limit, so you cant deposit right now. Your limit will reset tomorrow at 12:00 AM.'
10
+ : 'Youve reached your monthly deposit limit, so you cant deposit right now. Your limit will reset on the 1st day of next month.';
11
11
  return (_jsxs("div", { role: "alert", className: "flex items-start gap-md rounded-lg border border-utility-warning-200 bg-utility-warning-50 p-md", children: [_jsx("div", { className: "flex size-8 shrink-0 items-center justify-center rounded-full bg-bg-warning-secondary", children: _jsx(AlertTriangleIcon, { className: "size-4 text-text-featured-icon-light-warning" }) }), _jsxs("div", { className: "flex flex-col gap-xs", children: [_jsx("p", { className: "font-semibold text-sm text-text-primary-900", children: title }), _jsx("p", { className: "text-sm text-text-secondary-700 leading-relaxed", children: resetMessage }), _jsx("a", { href: `${responsibleGamingUrl}`, className: "mt-xs w-fit font-medium text-sm text-text-warning-primary-600 hover:underline", children: "View Limits" })] })] }));
12
12
  }
@@ -3,11 +3,13 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import { useCallback, useEffect, useMemo } from 'react';
4
4
  import { z } from 'zod';
5
5
  import { useShallow } from 'zustand/shallow';
6
+ import { useAccountQuery } from '../../client/hooks/useAccountQuery.js';
6
7
  import { useBonusesQuery } from '../../client/hooks/useBonusesQuery.js';
7
8
  import { useBypassKycChecker, } from '../../client/hooks/useBypassKycChecker.js';
8
9
  import { useFeatureFlag } from '../../client/hooks/useFeatureFlag.js';
9
10
  import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
10
11
  import { useLocaleInfo } from '../../client/hooks/useLocaleInfo.js';
12
+ import { useMemberWalletQuery } from '../../client/hooks/useMemberWalletAccount.js';
11
13
  import { useWalletQuery } from '../../client/hooks/useWalletQuery.js';
12
14
  import { Wallet02Icon } from '../../icons/Wallet02Icon.js';
13
15
  import { XIcon } from '../../icons/XIcon.js';
@@ -24,14 +26,29 @@ export function DepositWithdrawal(props) {
24
26
  const bypassDepositKycCheck = useBypassKycChecker(props.bypassDomains) || props.bypassDepositKycCheck;
25
27
  const featureFlag = useFeatureFlag();
26
28
  const { hasPrivacyPolicyAndTermsOfUse = true, isOfWinSite = false, note = null, ...restProps } = props;
27
- // TODO
28
- // const betDepositLimitQuery = useBetDepositLimitQuery({ enabled: featureFlag.enabled });
29
+ const accountQuery = useAccountQuery({ enabled: featureFlag.enabled });
30
+ const memberWalletQuery = useMemberWalletQuery({
31
+ enabled: featureFlag.enabled,
32
+ });
29
33
  const derivedLimitReached = useMemo(() => {
30
34
  if (!featureFlag.enabled)
31
35
  return undefined;
32
- //TODO Logic
33
- return { type: 'deposit', period: 'daily' }; //temporary
34
- }, [featureFlag.enabled]);
36
+ const account = accountQuery.data;
37
+ const wallet = memberWalletQuery.data;
38
+ const isDailyDepositLimitReached = account?.dailyDepositLimit != null &&
39
+ Number(wallet?.dailyTotalDeposit ?? 0) >=
40
+ Number(account.dailyDepositLimit);
41
+ const isMonthlyDepositLimitReached = account?.monthlyDepositLimit != null &&
42
+ Number(wallet?.monthlyTotalDeposit ?? 0) >=
43
+ Number(account.monthlyDepositLimit);
44
+ if (isDailyDepositLimitReached) {
45
+ return { type: 'deposit', period: 'daily' };
46
+ }
47
+ if (isMonthlyDepositLimitReached) {
48
+ return { type: 'deposit', period: 'monthly' };
49
+ }
50
+ return undefined;
51
+ }, [featureFlag.enabled, accountQuery.data, memberWalletQuery.data]);
35
52
  const mergedProps = {
36
53
  ...restProps,
37
54
  hasPrivacyPolicyAndTermsOfUse,
@@ -4,8 +4,11 @@ import { ark } from '@ark-ui/react/factory';
4
4
  import { Capacitor } from '@capacitor/core';
5
5
  import { BiometricAuthError } from 'capacitor-native-biometric';
6
6
  import { useShallow } from 'zustand/shallow';
7
+ import { useAccountQuery } from '../../client/hooks/useAccountQuery.js';
7
8
  import { useCreateGameSessionMutation } from '../../client/hooks/useCreateGameSessionMutation.js';
9
+ import { useFeatureFlag } from '../../client/hooks/useFeatureFlag.js';
8
10
  import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
11
+ import { useMemberWalletQuery } from '../../client/hooks/useMemberWalletAccount.js';
9
12
  import { useSessionQuery } from '../../client/hooks/useSessionQuery.js';
10
13
  import { getSession } from '../../client/services/getSession.js';
11
14
  import { signIn } from '../../client/services/signIn.js';
@@ -18,12 +21,24 @@ import { getSessionQueryKey } from '../../utils/queryKeys.js';
18
21
  import { LOCALSTORAGE_PUSH_NOTIFICATION_TOKEN_KEY } from '../PortalProvider/PushNotifications.js';
19
22
  export function GameLaunchTrigger(props) {
20
23
  const { game, bypassKycCheck: _bypassKycCheck, ...rest } = props;
24
+ const featureFlag = useFeatureFlag();
21
25
  const sessionQuery = useSessionQuery();
26
+ const accountQuery = useAccountQuery({ enabled: featureFlag.enabled });
27
+ const memberWalletQuery = useMemberWalletQuery({
28
+ enabled: featureFlag.enabled,
29
+ });
30
+ const account = accountQuery.data;
31
+ const wallet = memberWalletQuery.data;
32
+ const isDailyBetLimitReached = account?.dailyBetLimit != null &&
33
+ Number(wallet?.dailyTotalBet ?? 0) >= Number(account.dailyBetLimit);
34
+ const isMonthlyBetLimitReached = account?.monthlyBetLimit != null &&
35
+ Number(wallet?.monthlyTotalBet ?? 0) >= Number(account.monthlyBetLimit);
22
36
  const createGameSessionMutation = useCreateGameSessionMutation();
23
37
  const globalStore = useGlobalStore(useShallow((ctx) => ({
24
38
  signIn: ctx.signIn,
25
39
  gameLaunch: ctx.gameLaunch,
26
40
  isNonRegulated: ctx.isNonRegulated,
41
+ betDepositLimitReached: ctx.betDepositLimitReached,
27
42
  })));
28
43
  const currentHour = new Date().getHours();
29
44
  const between3amAnd3pm = currentHour >= 15 || currentHour < 3;
@@ -139,6 +154,14 @@ export function GameLaunchTrigger(props) {
139
154
  }
140
155
  return props.onClick?.(e);
141
156
  }
157
+ //when member has reached his bet limit,
158
+ if (featureFlag.enabled &&
159
+ (isDailyBetLimitReached || isMonthlyBetLimitReached)) {
160
+ globalStore.betDepositLimitReached.setOpen(true);
161
+ globalStore.betDepositLimitReached.setType('bet');
162
+ globalStore.betDepositLimitReached.setPeriod(isMonthlyBetLimitReached ? 'monthly' : 'daily');
163
+ return;
164
+ }
142
165
  globalStore.gameLaunch.setDetails({
143
166
  game: game,
144
167
  status: 'LOADING',
@@ -5,6 +5,7 @@ import { isString } from 'lodash-es';
5
5
  import Image from 'next/image';
6
6
  import { useState } from 'react';
7
7
  import { twMerge } from 'tailwind-merge';
8
+ import { useDebounceValue } from 'usehooks-ts';
8
9
  import { useBypassKycChecker, } from '../../client/hooks/useBypassKycChecker.js';
9
10
  import { useGamesQuery } from '../../client/hooks/useGamesQuery.js';
10
11
  import { SearchLgIcon } from '../../icons/SearchLgIcon.js';
@@ -14,16 +15,19 @@ import { Combobox } from '../../ui/Combobox/index.js';
14
15
  import { Portal } from '../../ui/Portal/index.js';
15
16
  import { Presence } from '../../ui/Presence/index.js';
16
17
  import { getGameImageUrl } from '../../utils/getGameImageUrl.js';
17
- import { sanitizeGamesSearch } from '../../utils/sanitizeGamesSearch.js';
18
+ import { collapseGamesSearch, mergeUniqueById, normalizeGameName, sanitizeGamesSearch, } from '../../utils/sanitizeGamesSearch.js';
18
19
  import { GameLaunchTrigger } from '../GameLaunch/index.js';
19
20
  export function GamesSearch(props) {
20
21
  const isBypass = useBypassKycChecker(props.bypassDomains);
21
22
  const [searchInput, setSearchInput] = useState('');
22
- const sanitizedSearch = sanitizeGamesSearch(searchInput);
23
+ const [debouncedSearch] = useDebounceValue(searchInput, 300);
24
+ const sanitizedSearch = sanitizeGamesSearch(debouncedSearch);
25
+ const collapsedSearch = collapseGamesSearch(debouncedSearch);
26
+ const hasSpaces = collapsedSearch !== sanitizedSearch;
23
27
  const trimmedInputLength = searchInput.trim().length;
24
28
  const showMinLengthWarning = trimmedInputLength > 0 &&
25
29
  trimmedInputLength < 3 &&
26
- sanitizedSearch.length < 3;
30
+ sanitizeGamesSearch(searchInput).length < 3;
27
31
  const gamesQuery = useGamesQuery({
28
32
  first: props.first ?? 18,
29
33
  filter: props.filter,
@@ -32,9 +36,27 @@ export function GamesSearch(props) {
32
36
  }, {
33
37
  enabled: sanitizedSearch.length >= 3,
34
38
  });
35
- let games = gamesQuery.data?.pages.flatMap((page) => page.edges.map((edge) => edge.node)) ?? [];
39
+ const collapsedGamesQuery = useGamesQuery({
40
+ first: props.first ?? 18,
41
+ filter: props.filter,
42
+ search: collapsedSearch,
43
+ sort: props.sort,
44
+ }, {
45
+ enabled: hasSpaces && collapsedSearch.length >= 3,
46
+ });
47
+ let games = mergeUniqueById(gamesQuery.data?.pages.flatMap((page) => page.edges.map((edge) => edge.node)) ?? [], collapsedGamesQuery.data?.pages.flatMap((page) => page.edges.map((edge) => edge.node)) ?? []);
36
48
  if (props.variant === '88play') {
37
- games = games.filter((game) => game.name.toLowerCase().includes(sanitizedSearch.toLowerCase()));
49
+ const normalizedSearch = normalizeGameName(sanitizedSearch);
50
+ games = games.filter((game) => normalizeGameName(game.name).includes(normalizedSearch));
51
+ }
52
+ const hasNextPage = gamesQuery.hasNextPage || collapsedGamesQuery.hasNextPage;
53
+ function fetchNextPage() {
54
+ if (gamesQuery.hasNextPage) {
55
+ void gamesQuery.fetchNextPage();
56
+ }
57
+ else if (collapsedGamesQuery.hasNextPage) {
58
+ void collapsedGamesQuery.fetchNextPage();
59
+ }
38
60
  }
39
61
  const collection = createListCollection({
40
62
  items: games,
@@ -52,14 +74,14 @@ export function GamesSearch(props) {
52
74
  placement: 'bottom',
53
75
  }, inputValue: searchInput, onInputValueChange: (details) => {
54
76
  setSearchInput(details.inputValue);
55
- }, selectionBehavior: "preserve", allowCustomValue: true, children: [_jsxs(Combobox.Control, { className: "relative z-50", children: [_jsx(Combobox.Input, { placeholder: props.placeholder ?? 'Search' }), _jsx(Combobox.Context, { children: (api) => {
77
+ }, selectionBehavior: "preserve", allowCustomValue: true, children: [_jsxs(Combobox.Control, { className: "relative ui-open:z-popover", children: [_jsx(Combobox.Input, { placeholder: props.placeholder ?? 'Search' }), _jsx(Combobox.Context, { children: (api) => {
56
78
  if (api.inputValue.length <= 0)
57
79
  return null;
58
80
  return (_jsx("span", { className: "cursor-pointer px-3.5 font-semibold text-text-secondary-700", onClick: () => {
59
81
  api.setInputValue('');
60
82
  api.focus();
61
83
  }, children: "Clear" }));
62
- } })] }), _jsx(Portal, { children: _jsx(Combobox.Context, { children: (api) => (_jsxs(_Fragment, { children: [_jsx(Presence, { present: api.open, children: _jsx("div", { className: "fixed inset-0 z-40 bg-black/50 backdrop-blur-sm", onClick: () => api.setOpen(false) }) }), _jsx(Combobox.Positioner, { children: searchInput.trim().length > 0 && (_jsx(Combobox.Content, { className: "z-50 max-h-[33.25rem] overflow-y-auto p-0", children: showMinLengthWarning ? (_jsx(Alert, { message: "Search requires at least 3 characters." })) : (_jsxs(_Fragment, { children: [games.length <= 0 && (_jsx(Alert, { message: "No results found" })), games.length > 0 && (_jsxs("div", { className: "p-xl", children: [_jsx(Combobox.Context, { children: (api) => (_jsx("div", { className: twMerge('grid grid-cols-3 gap-1.5 lg:grid-cols-9 lg:gap-3.5', classNames.gameSearchResult), children: games.map((game) => (_jsxs(GameLaunchTrigger, { bypassKycCheck: isBypass, game: game, onClick: () => {
84
+ } })] }), _jsx(Portal, { children: _jsx(Combobox.Context, { children: (api) => (_jsxs(_Fragment, { children: [_jsx(Presence, { present: api.open, children: _jsx("div", { className: "fixed inset-0 z-backdrop bg-black/50 backdrop-blur-sm", onClick: () => api.setOpen(false) }) }), _jsx(Combobox.Positioner, { className: "!z-popover", children: searchInput.trim().length > 0 && (_jsx(Combobox.Content, { className: "max-h-[33.25rem] overflow-y-auto p-0", children: showMinLengthWarning ? (_jsx(Alert, { message: "Search requires at least 3 characters." })) : (_jsxs(_Fragment, { children: [games.length <= 0 && (_jsx(Alert, { message: "No results found" })), games.length > 0 && (_jsxs("div", { className: "p-xl", children: [_jsx(Combobox.Context, { children: (api) => (_jsx("div", { className: twMerge('grid grid-cols-3 gap-1.5 lg:grid-cols-9 lg:gap-3.5', classNames.gameSearchResult), children: games.map((game) => (_jsxs(GameLaunchTrigger, { bypassKycCheck: isBypass, game: game, onClick: () => {
63
85
  api.setOpen(false);
64
86
  }, className: twMerge('md:hover:-translate-y-1 relative flex h-full w-full flex-col shadow-sm transition-transform duration-200', classNames.thumbnailRoot), children: [_jsx(Image, { src: game.name === 'Rainbow Ball'
65
87
  ? RainbowballImg
@@ -67,7 +89,7 @@ export function GamesSearch(props) {
67
89
  reference: game.reference,
68
90
  provider: game.provider,
69
91
  image: game.image,
70
- }), alt: "", width: 200, height: 200, loading: "lazy", unoptimized: true, className: "aspect-square w-full rounded-t-md object-cover" }), _jsx("span", { className: twMerge('flex w-full flex-1 items-center justify-center break-words rounded-b-md bg-bg-tertiary px-2 py-2.5 text-center font-semibold text-text-primary-brand text-xs', classNames.thumbnailTitle), children: fixMojibake(game.name) })] }, game.id))) })) }), _jsx(Presence, { present: gamesQuery.hasNextPage, children: _jsx(Button, { variant: "outline", className: twMerge('mx-auto mt-4xl w-fit', classNames.loadMoreButton), onClick: () => gamesQuery.fetchNextPage(), children: "Load More" }) })] }))] })) })) })] })) }) })] }) }));
92
+ }), alt: "", width: 200, height: 200, loading: "lazy", unoptimized: true, className: "aspect-square w-full rounded-t-md object-cover" }), _jsx("span", { className: twMerge('flex w-full flex-1 items-center justify-center break-words rounded-b-md bg-bg-tertiary px-2 py-2.5 text-center font-semibold text-text-primary-brand text-xs', classNames.thumbnailTitle), children: fixMojibake(game.name) })] }, game.id))) })) }), _jsx(Presence, { present: hasNextPage, children: _jsx(Button, { variant: "outline", className: twMerge('mx-auto mt-4xl w-fit', classNames.loadMoreButton), onClick: fetchNextPage, children: "Load More" }) })] }))] })) })) })] })) }) })] }) }));
71
93
  }
72
94
  function Alert({ message }) {
73
95
  return (_jsxs("div", { className: "py-lg", role: "alert", "aria-live": "polite", children: [_jsx("div", { className: "mx-auto flex size-12 items-center justify-center rounded-lg border border-border-primary bg-bg-secondary shadow-xs", children: _jsx(SearchLgIcon, { className: "size-6 text-text-secondary-700" }) }), _jsx("p", { className: "mt-4 text-center text-text-secondary-700", children: message })] }));