@opexa/portal-components 0.0.116 → 0.0.117

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 (162) hide show
  1. package/dist/components/Bonus/Bonus.client.js +1 -1
  2. package/dist/components/Cashback/Cashback.client.js +1 -1
  3. package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/OnlineBankDepositContext.d.ts +2 -2
  4. package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/useOnlineBankDeposit.d.ts +1 -1
  5. package/dist/components/DepositWithdrawal/Deposit/QRPHDeposit/QRPHDepositContext.d.ts +2 -2
  6. package/dist/components/DepositWithdrawal/Deposit/QRPHDeposit/useQRPHDeposit.d.ts +1 -1
  7. package/dist/components/Disclaimer/DisclaimerV1.js +1 -1
  8. package/dist/components/GameLaunch/GameLaunch.lazy.js +1 -1
  9. package/dist/components/GamesSearch/GamesSearch.js +1 -1
  10. package/dist/components/Jackpots/JackpotsCarousel/JackpotsCarouselItem.module.css +184 -184
  11. package/dist/components/Jackpots/JackpotsList/JackpotsListItem.module.css +184 -184
  12. package/dist/components/News/News.js +1 -1
  13. package/dist/components/Promo/Promo.client.js +1 -1
  14. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuest.d.ts +1 -4
  15. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuest.js +38 -30
  16. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuestRules.d.ts +6 -0
  17. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuestRules.js +15 -0
  18. package/dist/components/Quests/OnboardingQuest/OnboardingQuest.d.ts +1 -4
  19. package/dist/components/Quests/OnboardingQuest/OnboardingQuest.js +27 -3
  20. package/dist/components/Quests/OnboardingQuest/OnboardingQuestRules.d.ts +6 -0
  21. package/dist/components/Quests/OnboardingQuest/OnboardingQuestRules.js +15 -0
  22. package/dist/components/Quests/WageringQuest/WageringQuest.d.ts +1 -4
  23. package/dist/components/Quests/WageringQuest/WageringQuest.js +15 -11
  24. package/dist/components/Quests/WageringQuest/WageringQuestRules.d.ts +7 -0
  25. package/dist/components/Quests/WageringQuest/WageringQuestRules.js +17 -0
  26. package/dist/components/Search/Search.lazy.js +1 -1
  27. package/dist/components/SignIn/MobileNumberSignIn.js +3 -1
  28. package/dist/components/SignUp/SignUpForm.js +100 -10
  29. package/dist/components/Tournaments/TournamentsCarousel/TournamentsCarouselItem.module.css +184 -184
  30. package/dist/components/Tournaments/TournamentsList/TournamentItem.module.css +184 -184
  31. package/dist/constants/BranchCode.d.ts +4 -0
  32. package/dist/constants/BranchCode.js +42 -0
  33. package/dist/constants/index.d.ts +1 -0
  34. package/dist/constants/index.js +1 -0
  35. package/dist/icons/CalendarIcon.js +1 -1
  36. package/dist/services/queries.js +2369 -2369
  37. package/dist/styles/theme.css +699 -699
  38. package/dist/ui/DatePicker/DatePicker.d.ts +1080 -2088
  39. package/dist/ui/DatePicker/datePicker.recipe.d.ts +39 -81
  40. package/dist/ui/DatePicker/datePicker.recipe.js +19 -0
  41. package/dist/ui/Select/Select.d.ts +45 -45
  42. package/dist/ui/Select/select.recipe.d.ts +3 -3
  43. package/dist/ui/Select/select.recipe.js +2 -2
  44. package/package.json +163 -163
  45. package/dist/client/hooks/index.d.ts +0 -65
  46. package/dist/client/hooks/index.js +0 -65
  47. package/dist/client/services/index.d.ts +0 -4
  48. package/dist/client/services/index.js +0 -4
  49. package/dist/client/utils/index.d.ts +0 -3
  50. package/dist/client/utils/index.js +0 -3
  51. package/dist/components/Empty.d.ts +0 -10
  52. package/dist/components/Empty.js +0 -7
  53. package/dist/components/Games/GameContext.d.ts +0 -2
  54. package/dist/components/Games/GameContext.js +0 -2
  55. package/dist/components/InfiniteScroll.d.ts +0 -10
  56. package/dist/components/InfiniteScroll.js +0 -25
  57. package/dist/components/JackpotCounter/JackpotCounter.client.d.ts +0 -2
  58. package/dist/components/JackpotCounter/JackpotCounter.client.js +0 -66
  59. package/dist/components/JackpotCounter/JackpotCounter.d.ts +0 -17
  60. package/dist/components/JackpotCounter/JackpotCounter.js +0 -21
  61. package/dist/components/JackpotCounter/JackpotCounterItem.d.ts +0 -18
  62. package/dist/components/JackpotCounter/JackpotCounterItem.js +0 -109
  63. package/dist/components/JackpotCounter/JackpotCounterItem.module.css +0 -184
  64. package/dist/components/JackpotCounter/index.d.ts +0 -1
  65. package/dist/components/JackpotCounter/index.js +0 -1
  66. package/dist/components/Jackpots/JackpotDesktop.d.ts +0 -1
  67. package/dist/components/Jackpots/JackpotDesktop.js +0 -45
  68. package/dist/components/Jackpots/JackpotGameProviders.d.ts +0 -5
  69. package/dist/components/Jackpots/JackpotGameProviders.js +0 -41
  70. package/dist/components/Jackpots/JackpotItemDesktop.d.ts +0 -9
  71. package/dist/components/Jackpots/JackpotItemDesktop.js +0 -43
  72. package/dist/components/Jackpots/JackpotItemMobile.d.ts +0 -9
  73. package/dist/components/Jackpots/JackpotItemMobile.js +0 -44
  74. package/dist/components/Jackpots/JackpotMobile.d.ts +0 -1
  75. package/dist/components/Jackpots/JackpotMobile.js +0 -46
  76. package/dist/components/Jackpots/JackpotRules.d.ts +0 -5
  77. package/dist/components/Jackpots/JackpotRules.js +0 -11
  78. package/dist/components/Jackpots/Jackpots.client.d.ts +0 -2
  79. package/dist/components/Jackpots/Jackpots.client.js +0 -29
  80. package/dist/components/Jackpots/JackpotsContext.d.ts +0 -4
  81. package/dist/components/Jackpots/JackpotsContext.js +0 -3
  82. package/dist/components/Jackpots/useJackpotData.d.ts +0 -14
  83. package/dist/components/Jackpots/useJackpotData.js +0 -93
  84. package/dist/components/Jackpots/useJackpotItemData.d.ts +0 -20
  85. package/dist/components/Jackpots/useJackpotItemData.js +0 -87
  86. package/dist/components/KYC/Header.d.ts +0 -1
  87. package/dist/components/KYC/Header.js +0 -6
  88. package/dist/components/KYC/Step1.d.ts +0 -1
  89. package/dist/components/KYC/Step1.js +0 -12
  90. package/dist/components/KYC/Step2.d.ts +0 -1
  91. package/dist/components/KYC/Step2.js +0 -12
  92. package/dist/components/KYC/Step3.d.ts +0 -1
  93. package/dist/components/KYC/Step3.js +0 -11
  94. package/dist/components/KYC/Step4.d.ts +0 -1
  95. package/dist/components/KYC/Step4.js +0 -6
  96. package/dist/components/Messages/MessageItem.d.ts +0 -4
  97. package/dist/components/Messages/MessageItem.js +0 -34
  98. package/dist/components/PortalProvider/WebVitals.d.ts +0 -1
  99. package/dist/components/PortalProvider/WebVitals.js +0 -8
  100. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuestModal.d.ts +0 -8
  101. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuestModal.js +0 -8
  102. package/dist/components/Quests/WageringQuest/WageringQuestModal.d.ts +0 -9
  103. package/dist/components/Quests/WageringQuest/WageringQuestModal.js +0 -8
  104. package/dist/components/TournamentCounter/TournamentCounter.client.d.ts +0 -2
  105. package/dist/components/TournamentCounter/TournamentCounter.client.js +0 -50
  106. package/dist/components/TournamentCounter/TournamentCounter.d.ts +0 -8
  107. package/dist/components/TournamentCounter/TournamentCounter.js +0 -21
  108. package/dist/components/TournamentCounter/TournamentCounterItem.d.ts +0 -8
  109. package/dist/components/TournamentCounter/TournamentCounterItem.js +0 -106
  110. package/dist/components/TournamentCounter/index.d.ts +0 -1
  111. package/dist/components/TournamentCounter/index.js +0 -1
  112. package/dist/components/Tournaments/TournamentDesktop.d.ts +0 -1
  113. package/dist/components/Tournaments/TournamentDesktop.js +0 -57
  114. package/dist/components/Tournaments/TournamentGameProviders.d.ts +0 -5
  115. package/dist/components/Tournaments/TournamentGameProviders.js +0 -38
  116. package/dist/components/Tournaments/TournamentItemDesktop.d.ts +0 -7
  117. package/dist/components/Tournaments/TournamentItemDesktop.js +0 -56
  118. package/dist/components/Tournaments/TournamentItemMobile.d.ts +0 -7
  119. package/dist/components/Tournaments/TournamentItemMobile.js +0 -54
  120. package/dist/components/Tournaments/TournamentMobile.d.ts +0 -1
  121. package/dist/components/Tournaments/TournamentMobile.js +0 -55
  122. package/dist/components/Tournaments/TournamentRules.d.ts +0 -5
  123. package/dist/components/Tournaments/TournamentRules.js +0 -11
  124. package/dist/components/Tournaments/Tournaments.client.d.ts +0 -2
  125. package/dist/components/Tournaments/Tournaments.client.js +0 -20
  126. package/dist/components/Tournaments/TournamentsContext.d.ts +0 -4
  127. package/dist/components/Tournaments/TournamentsContext.js +0 -3
  128. package/dist/components/Tournaments/useTournamentData.d.ts +0 -10
  129. package/dist/components/Tournaments/useTournamentData.js +0 -72
  130. package/dist/components/Tournaments/useTournamentItemData.d.ts +0 -16
  131. package/dist/components/Tournaments/useTournamentItemData.js +0 -64
  132. package/dist/components/index.d.ts +0 -33
  133. package/dist/components/index.js +0 -33
  134. package/dist/constants/envVars.d.ts +0 -5
  135. package/dist/constants/envVars.js +0 -28
  136. package/dist/constants/gameProviders.d.ts +0 -5
  137. package/dist/constants/gameProviders.js +0 -362
  138. package/dist/constants/gameTypes.d.ts +0 -4
  139. package/dist/constants/gameTypes.js +0 -64
  140. package/dist/constants/headerKeys.d.ts +0 -1
  141. package/dist/constants/headerKeys.js +0 -1
  142. package/dist/constants/secretQuestions.d.ts +0 -3
  143. package/dist/constants/secretQuestions.js +0 -24
  144. package/dist/constants/storageKeys.d.ts +0 -2
  145. package/dist/constants/storageKeys.js +0 -2
  146. package/dist/icons/index.d.ts +0 -65
  147. package/dist/icons/index.js +0 -65
  148. package/dist/images/hacksaw-gaming.png +0 -0
  149. package/dist/server/services/index.d.ts +0 -4
  150. package/dist/server/services/index.js +0 -4
  151. package/dist/server/utils/index.d.ts +0 -29
  152. package/dist/server/utils/index.js +0 -29
  153. package/dist/ui/Presence.d.ts +0 -2
  154. package/dist/ui/Presence.js +0 -7
  155. package/dist/ui/Prose.d.ts +0 -2
  156. package/dist/ui/Prose.js +0 -5
  157. package/dist/ui/index.d.ts +0 -26
  158. package/dist/ui/index.js +0 -26
  159. package/dist/utils/index.d.ts +0 -17
  160. package/dist/utils/index.js +0 -17
  161. package/dist/utils/isMobile.d.ts +0 -5
  162. package/dist/utils/isMobile.js +0 -9
@@ -2,18 +2,22 @@
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 { useDisclosure } from '../../../client/hooks/useDisclosure.js';
6
+ import { useLocaleInfo } from '../../../client/hooks/useLocaleInfo.js';
7
+ import { ClockStopWatchIcon } from '../../../icons/ClockStopWatchIcon.js';
8
+ import { InfoCircleIcon } from '../../../icons/InfoCircleIcon.js';
9
+ import { Badge } from '../../../ui/Badge/index.js';
10
+ import { parseDecimal } from '../../../utils/parseDecimal.js';
7
11
  import CountdownTimer from '../CountdownTimer.js';
8
- import { WageringQuestModal } from './WageringQuestModal.js';
9
- export function WageringQuest({ quest }) {
10
- const [showRules, setShowRules] = useState(false);
12
+ import { useQuestContext } from '../QuestsContext.js';
13
+ import { WageringQuestModal } from './WageringQuestRules.js';
14
+ export function WageringQuest() {
15
+ const quest = useQuestContext();
16
+ const disclosure = useDisclosure();
17
+ const localeInfo = useLocaleInfo();
11
18
  const [isExpired, setIsExpired] = useState(false);
12
19
  const { progressPercentage, turnover, targetTurnover, name, description, endDateTime, bonus, status, } = quest;
13
- return (_jsxs(_Fragment, { children: [_jsx(WageringQuestModal, { questName: name, modalState: {
14
- isOpen: showRules,
15
- setIsOpen: setShowRules,
16
- } }), _jsxs("div", { className: "border-border-primary bg-bg-tertiary flex h-full w-full flex-col space-y-6 rounded-2xl border px-4 pb-6 pt-5", children: [_jsxs("div", { className: "flex flex-col space-y-2", children: [_jsxs("div", { className: "flex max-h-7.5 items-start justify-between", children: [_jsx(CountdownTimer, { endDateTime: endDateTime, renderAction: (timeLeft) => (_jsxs(Badge.Root, { size: "lg", colorScheme: "brand", round: false, children: [_jsx(Badge.Icon, { children: _jsx(ClockStopWatchIcon, {}) }), _jsxs(Badge.Label, { children: [timeLeft.days, "d:", timeLeft.hours, "h:", timeLeft.minutes, "m:", timeLeft.seconds, "s"] })] })), onEnd: () => setIsExpired(true) }), _jsx("div", { role: "button", className: "bg-bg-primary border-border-secondary flex size-9 cursor-pointer items-center justify-center rounded-md border", onClick: () => setShowRules((prev) => !prev), children: _jsx(InfoCircleIcon, { className: "text-text-disabled size-5" }) })] }), _jsx("p", { className: "text-xl font-semibold", children: name }), _jsx("p", { className: "text-text-secondary-700 text-wrap text-sm font-normal", dangerouslySetInnerHTML: { __html: description } })] }), _jsxs("div", { className: "flex w-full flex-col space-y-2", children: [_jsxs("div", { className: "text-text-primary-brand group flex items-center justify-between", children: [_jsxs("p", { children: ["Progress ", parseInt(progressPercentage).toFixed(2), "%"] }), _jsxs("p", { children: [turnover, _jsxs("span", { className: "text-text-quarterary-brand", children: ["/", targetTurnover, " PHP"] })] })] }), _jsx("div", { className: "bg-bg-primary h-2 w-full overflow-hidden rounded-full", children: _jsx("div", { className: "bg-utility-brand-600 h-full rounded-full transition-all duration-300", style: { width: `${progressPercentage}%` } }) })] }), _jsx("div", { className: "flex h-full items-end", children: _jsx("div", { className: "bg-button-secondary-bg border-bg-primary-hover w-full rounded-md border px-3.5 py-2.5 text-center text-white", children: _jsxs("p", { className: twMerge(isExpired || status === 'COMPLETED' || status === 'FAILED'
17
- ? ['opacity-50 grayscale']
18
- : ''), children: ["Complete to get ", _jsxs("span", { className: "text-brand-400", children: ["\u20B1", bonus] }), ' ', "bonus!"] }) }) })] })] }));
20
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "border-border-primary bg-bg-tertiary flex h-full w-full flex-col space-y-6 rounded-2xl border px-4 pb-6 pt-5", children: [_jsxs("div", { className: "flex flex-col space-y-2", children: [_jsxs("div", { className: "flex max-h-7.5 items-start justify-between", children: [_jsx(CountdownTimer, { endDateTime: endDateTime, renderAction: (timeLeft) => (_jsxs(Badge.Root, { size: "lg", colorScheme: "brand", round: false, children: [_jsx(Badge.Icon, { children: _jsx(ClockStopWatchIcon, {}) }), _jsxs(Badge.Label, { children: [timeLeft.days, "d:", timeLeft.hours, "h:", timeLeft.minutes, "m:", timeLeft.seconds, "s"] })] })), onEnd: () => setIsExpired(true) }), _jsx("div", { role: "button", className: "bg-bg-primary border-border-secondary flex size-9 cursor-pointer items-center justify-center rounded-md border", onClick: () => disclosure.setOpen(true), children: _jsx(InfoCircleIcon, { className: "text-text-disabled size-5" }) })] }), _jsx("p", { className: "text-xl font-semibold", children: name }), _jsx("p", { className: "text-text-secondary-700 text-wrap text-sm font-normal", dangerouslySetInnerHTML: { __html: description } })] }), _jsxs("div", { className: "flex w-full flex-col space-y-2", children: [_jsxs("div", { className: "text-text-primary-brand group flex items-center justify-between", children: [_jsxs("p", { children: ["Progress ", parseDecimal(progressPercentage, 0).toFixed(2), "%"] }), _jsxs("p", { children: [turnover, _jsxs("span", { className: "text-text-quarterary-brand", children: ["/", targetTurnover, " ", localeInfo.currency.code] })] })] }), _jsx("div", { className: "bg-bg-primary h-2 w-full overflow-hidden rounded-full", children: _jsx("div", { className: "bg-utility-brand-600 h-full rounded-full transition-all duration-300", style: { width: `${progressPercentage}%` } }) })] }), _jsx("div", { className: "flex h-full items-end", children: _jsx("div", { className: "bg-button-secondary-bg border-bg-primary-hover w-full rounded-md border px-3.5 py-2.5 text-center text-white", children: _jsxs("p", { className: twMerge(isExpired || status === 'COMPLETED' || status === 'FAILED'
21
+ ? 'opacity-50 grayscale'
22
+ : ''), children: ["Complete to get ", _jsxs("span", { className: "text-brand-400", children: ["\u20B1", bonus] }), ' ', "bonus!"] }) }) })] }), _jsx(WageringQuestModal, { open: disclosure.open, onOpenChange: disclosure.setOpen })] }));
19
23
  }
@@ -0,0 +1,7 @@
1
+ interface WageringQuestModalProps {
2
+ open?: boolean;
3
+ onOpenChange?: (open: boolean) => void;
4
+ defaultOpen?: boolean;
5
+ }
6
+ export declare function WageringQuestModal(props: WageringQuestModalProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,17 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useControllableState } from '../../../client/hooks/useControllableState.js';
4
+ import { XIcon } from '../../../icons/XIcon.js';
5
+ import { Button } from '../../../ui/Button/index.js';
6
+ import { Dialog } from '../../../ui/Dialog/index.js';
7
+ import { Portal } from '../../../ui/Portal/index.js';
8
+ import { useQuestContext } from '../QuestsContext.js';
9
+ export function WageringQuestModal(props) {
10
+ const quest = useQuestContext();
11
+ const [open, setOpen] = useControllableState({
12
+ value: props.open,
13
+ defaultValue: props.defaultOpen ?? false,
14
+ onChange: props.onOpenChange,
15
+ });
16
+ return (_jsx(Dialog.Root, { lazyMount: true, unmountOnExit: true, open: open, onOpenChange: (details) => setOpen(details.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("h2", { className: "text-text-primary-900 text-lg font-semibold", children: quest.name }), _jsxs("ol", { 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: () => setOpen(false), children: "Ok" }) })] }) })] }) }));
17
+ }
@@ -18,7 +18,7 @@ import { Dialog } from '../../ui/Dialog/index.js';
18
18
  import { Field } from '../../ui/Field/index.js';
19
19
  import { IconButton } from '../../ui/IconButton/index.js';
20
20
  import { Portal } from '../../ui/Portal/index.js';
21
- import { Presence } from '../../ui/Presence.js';
21
+ import { Presence } from '../../ui/Presence/index.js';
22
22
  import { callIfFn } from '../../utils/callIfFn.js';
23
23
  import { getGameImageUrl } from '../../utils/getGameImageUrl.js';
24
24
  import { GameLaunchTrigger } from '../GameLaunch/index.js';
@@ -88,7 +88,9 @@ export function MobileNumberSignIn() {
88
88
  : 'Failed to send verification code',
89
89
  });
90
90
  }
91
- }), children: [_jsxs(Field.Root, { invalid: !!step1Form.formState.errors.mobileNumber, children: [_jsx(Field.Label, { children: "Mobile Number" }), _jsxs("div", { className: "relative", children: [_jsx(localeInfo.country.flag, { className: "absolute left-3.5 top-1/2 size-5 shrink-0 -translate-y-1/2" }), _jsx(Field.Input, { className: "pl-11", placeholder: `${localeInfo.mobileNumber.areaCode}${localeInfo.mobileNumber.example}`, ...step1Form.register('mobileNumber') })] }), _jsx(Field.ErrorText, { children: step1Form.formState.errors.mobileNumber?.message })] }), _jsx(Button, { type: "submit", className: "mt-3xl", disabled: step1Form.formState.isSubmitting, children: "Log In" }), _jsx(Controller, { control: step1Form.control, name: "termsAccepted", render: (o) => (_jsxs(Field.Root, { invalid: o.fieldState.invalid, className: "mt-xl", children: [_jsxs(Checkbox.Root, { checked: o.field.value, onCheckedChange: (details) => {
91
+ }), children: [_jsxs(Field.Root, { invalid: !!step1Form.formState.errors.mobileNumber, children: [_jsx(Field.Label, { children: "Mobile Number" }), _jsxs("div", { className: "relative", children: [_jsxs("div", { className: "absolute left-3.5 top-1/2 flex shrink-0 -translate-y-1/2 items-center gap-md", children: [_jsx(localeInfo.country.flag, { className: "size-5" }), _jsx("span", { className: "text-text-placeholder", children: localeInfo.mobileNumber.areaCode })] }), _jsx(Field.Input, { style: {
92
+ paddingLeft: `calc(2.75rem + ${localeInfo.mobileNumber.areaCode.length}ch)`,
93
+ }, ...step1Form.register('mobileNumber') })] }), _jsx(Field.ErrorText, { children: step1Form.formState.errors.mobileNumber?.message })] }), _jsx(Button, { type: "submit", className: "mt-3xl", disabled: step1Form.formState.isSubmitting, children: "Log In" }), _jsx(Controller, { control: step1Form.control, name: "termsAccepted", render: (o) => (_jsxs(Field.Root, { invalid: o.fieldState.invalid, className: "mt-xl", children: [_jsxs(Checkbox.Root, { checked: o.field.value, onCheckedChange: (details) => {
92
94
  o.field.onChange(details.checked);
93
95
  }, children: [_jsx(Checkbox.Control, { children: _jsx(Checkbox.Indicator, { asChild: true, children: _jsx(CheckIcon, {}) }) }), _jsxs(Checkbox.Label, { children: ["I am at least 21 years of age and I accept the", ' ', _jsx("span", { className: "text-brand-400 whitespace-nowrap underline underline-offset-2", children: "Terms and Conditions." })] }), _jsx(Checkbox.HiddenInput, {})] }), _jsx(Field.ErrorText, { className: "ml-6 text-xs", children: o.fieldState.error?.message })] })) })] }), _jsxs("div", { className: "relative mt-6 text-center", children: [_jsx("hr", { className: "-translte-y-1/2 text-text-tertiary-600/50 absolute top-1/2 w-full" }), _jsx("span", { className: "text-text-tertiary-600 bg-bg-primary-alt relative px-md text-center text-sm font-semibold", children: "Log in directly with" })] }), _jsxs("div", { className: "mt-6", children: [_jsxs(Button, { variant: "outline", colorScheme: "gray", onClick: () => {
94
96
  dialog.setOpen(false);
@@ -1,8 +1,11 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { createListCollection, parseDate } from '@ark-ui/react';
3
4
  import { useDialogContext } from '@ark-ui/react/dialog';
4
5
  import { zodResolver } from '@hookform/resolvers/zod';
5
6
  import { ObjectId } from '@opexa/object-id';
7
+ import { differenceInYears, format } from 'date-fns';
8
+ import { noop } from 'lodash-es';
6
9
  import { useSearchParams } from 'next/navigation';
7
10
  import { useRef, useState } from 'react';
8
11
  import { Controller, useForm } from 'react-hook-form';
@@ -15,14 +18,30 @@ import { useMobileNumberParser } from '../../client/hooks/useMobileNumberParser.
15
18
  import { useSendVerificationCodeMutation } from '../../client/hooks/useSendVerificationCodeMutation.js';
16
19
  import { useSignInMutation } from '../../client/hooks/useSignInMutation.js';
17
20
  import { useSignUpMutation } from '../../client/hooks/useSignUpMutation.js';
21
+ import { useUpdateAccountMutation } from '../../client/hooks/useUpdateAccountMutation.js';
18
22
  import { toaster } from '../../client/utils/toaster.js';
23
+ import { BRANCH_CODES } from '../../constants/index.js';
19
24
  import { ArrowLeftIcon } from '../../icons/ArrowLeftIcon.js';
25
+ import { CalendarIcon } from '../../icons/CalendarIcon.js';
20
26
  import { CheckIcon } from '../../icons/CheckIcon.js';
27
+ import { ChevronDownIcon } from '../../icons/ChevronDownIcon.js';
28
+ import { ChevronLeftIcon } from '../../icons/ChevronLeftIcon.js';
29
+ import { ChevronRightIcon } from '../../icons/ChevronRightIcon.js';
30
+ import { FacebookIcon } from '../../icons/FacebookIcon.js';
31
+ import { GoogleIcon } from '../../icons/GoogleIcon.js';
21
32
  import { ObjectType } from '../../services/ObjectType.js';
22
33
  import { Button } from '../../ui/Button/index.js';
23
34
  import { Checkbox } from '../../ui/Checkbox/index.js';
35
+ import { DatePicker } from '../../ui/DatePicker/index.js';
24
36
  import { Field } from '../../ui/Field/index.js';
25
37
  import { PinInput } from '../../ui/PinInput/index.js';
38
+ import { Select } from '../../ui/Select/index.js';
39
+ import { createPoll } from '../../utils/createPoll.js';
40
+ const branchCollection = createListCollection({
41
+ items: BRANCH_CODES,
42
+ itemToValue: (item) => item.code,
43
+ itemToString: (item) => `${item.code} - ${item.name}`,
44
+ });
26
45
  export function SignUpForm() {
27
46
  const [step, setStep] = useState(1);
28
47
  const dialog = useDialogContext();
@@ -30,6 +49,7 @@ export function SignUpForm() {
30
49
  const signInStore = useGlobalStore(useShallow((ctx) => ctx.signIn));
31
50
  const signUpMutation = useSignUpMutation();
32
51
  const signInMutation = useSignInMutation();
52
+ const updateAccountMutation = useUpdateAccountMutation();
33
53
  const sendVerificationCodeMutation = useSendVerificationCodeMutation();
34
54
  const localeInfo = useLocaleInfo();
35
55
  const mobileNumberParser = useMobileNumberParser();
@@ -50,15 +70,39 @@ export function SignUpForm() {
50
70
  });
51
71
  }
52
72
  }),
73
+ realName: z
74
+ .string()
75
+ .min(2, 'Real name must be 2 or more characters')
76
+ .max(50, 'Real name must not be more than 50 characters')
77
+ .trim(),
78
+ birthDay: z
79
+ .date({
80
+ invalid_type_error: 'Date of birth is required',
81
+ required_error: 'Date of birth is required',
82
+ })
83
+ .superRefine((val, ctx) => {
84
+ const now = new Date();
85
+ const age = differenceInYears(now, val);
86
+ if (age < 21) {
87
+ return ctx.addIssue({
88
+ code: z.ZodIssueCode.custom,
89
+ message: 'You must be at least 21 years old',
90
+ });
91
+ }
92
+ }),
93
+ branchCode: z.string().min(1, 'Branch is required').trim(),
53
94
  });
54
95
  const Step2Definition = z.object({
55
96
  verificationCode: z.array(z.string().min(1).max(1).trim()).min(6).max(6),
56
97
  });
57
98
  const step1Form = useForm({
99
+ mode: 'all',
58
100
  resolver: zodResolver(Step1Definition),
59
101
  defaultValues: {
60
102
  mobileNumber: '',
61
103
  termsAccepted: false,
104
+ branchCode: BRANCH_CODES[0].code,
105
+ realName: '',
62
106
  },
63
107
  });
64
108
  const step2Form = useForm({
@@ -72,6 +116,8 @@ export function SignUpForm() {
72
116
  duration: 1000 * 60,
73
117
  });
74
118
  const form2Ref = useRef(null);
119
+ const birthDay = step1Form.watch('birthDay');
120
+ const branchCode = step1Form.watch('branchCode', '');
75
121
  return (_jsxs(_Fragment, { children: [step === 1 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "mt-xl text-center text-lg font-semibold", children: "Create an account" }), _jsx("p", { className: "text-text-secondary-700 mt-xs text-center text-sm", children: "Register instantly and start playing!" }), _jsxs("form", { className: "mt-3xl", onSubmit: step1Form.handleSubmit(async (data) => {
76
122
  try {
77
123
  await sendVerificationCodeMutation.mutateAsync({
@@ -88,9 +134,33 @@ export function SignUpForm() {
88
134
  : 'Failed to send verification code',
89
135
  });
90
136
  }
91
- }), children: [_jsxs(Field.Root, { invalid: !!step1Form.formState.errors.mobileNumber, children: [_jsx(Field.Label, { children: "Mobile Number" }), _jsxs("div", { className: "relative", children: [_jsx(localeInfo.country.flag, { className: "absolute left-3.5 top-1/2 size-5 shrink-0 -translate-y-1/2" }), _jsx(Field.Input, { className: "pl-11", placeholder: `${localeInfo.mobileNumber.areaCode}${localeInfo.mobileNumber.example}`, ...step1Form.register('mobileNumber') })] }), _jsx(Field.ErrorText, { children: step1Form.formState.errors.mobileNumber?.message })] }), _jsx(Button, { type: "submit", className: "mt-3xl", disabled: step1Form.formState.isSubmitting, children: "Create Account" }), _jsx(Controller, { control: step1Form.control, name: "termsAccepted", render: (o) => (_jsxs(Field.Root, { className: "mt-xl", invalid: o.fieldState.invalid, children: [_jsxs(Checkbox.Root, { checked: o.field.value, onCheckedChange: (details) => {
137
+ }), children: [_jsxs(Field.Root, { invalid: !!step1Form.formState.errors.mobileNumber, children: [_jsx(Field.Label, { children: "Mobile Number" }), _jsxs("div", { className: "relative", children: [_jsxs("div", { className: "absolute left-3.5 top-1/2 flex shrink-0 -translate-y-1/2 items-center gap-md", children: [_jsx(localeInfo.country.flag, { className: "size-5" }), _jsx("span", { className: "text-text-placeholder", children: localeInfo.mobileNumber.areaCode })] }), _jsx(Field.Input, { style: {
138
+ paddingLeft: `calc(2.75rem + ${localeInfo.mobileNumber.areaCode.length}ch)`,
139
+ }, ...step1Form.register('mobileNumber') })] }), _jsx(Field.ErrorText, { children: step1Form.formState.errors.mobileNumber?.message })] }), _jsxs(Field.Root, { invalid: !!step1Form.formState.errors.realName, className: "mt-xl", children: [_jsx(Field.Label, { children: "Real Name" }), _jsx(Field.Input, { placeholder: "Enter your real name", ...step1Form.register('realName') }), _jsx(Field.ErrorText, { children: step1Form.formState.errors.realName?.message })] }), _jsxs(Field.Root, { invalid: !!step1Form.formState.errors.birthDay, className: "mt-xl", children: [_jsxs(DatePicker.Root, { size: "md", variant: "outline", placeholder: "MM/DD/YYYY", lazyMount: true, unmountOnExit: true, fixedWeeks: true, selectionMode: "single", value: birthDay ? [parseDate(birthDay)] : [], onValueChange: (details) => {
140
+ const value = details.value.at(0)?.toDate(DEVICE_TIMEZONE);
141
+ if (value) {
142
+ step1Form.setValue('birthDay', value, {
143
+ shouldDirty: true,
144
+ shouldTouch: true,
145
+ shouldValidate: true,
146
+ });
147
+ }
148
+ }, children: [_jsx(DatePicker.Label, { children: "Date of Birth" }), _jsxs(DatePicker.Control, { children: [_jsx(DatePicker.Input, {}), _jsx(DatePicker.Trigger, { children: _jsx(CalendarIcon, {}) })] }), _jsx(DatePicker.Positioner, { children: _jsx(DatePicker.Content, { children: _jsx(DatePicker.View, { view: "day", children: _jsx(DatePicker.Context, { children: (api) => (_jsxs(_Fragment, { children: [_jsxs(DatePicker.ViewControl, { children: [_jsx(DatePicker.PrevTrigger, { children: _jsx(ChevronLeftIcon, {}) }), _jsx(DatePicker.ViewTrigger, { children: _jsx(DatePicker.RangeText, {}) }), _jsx(DatePicker.NextTrigger, { children: _jsx(ChevronRightIcon, {}) })] }), _jsxs(DatePicker.Table, { children: [_jsx(DatePicker.TableHead, { children: _jsx(DatePicker.TableRow, { children: api.weekDays.map((weekDay, id) => (_jsx(DatePicker.TableHeader, { children: weekDay.short.substring(0, 2) }, id))) }) }), _jsx(DatePicker.TableBody, { children: api.weeks.map((week, id) => (_jsx(DatePicker.TableRow, { children: week.map((day, id) => (_jsx(DatePicker.TableCell, { value: day, children: _jsx(DatePicker.TableCellTrigger, { children: day.day }) }, id))) }, id))) })] })] })) }) }) }) })] }), _jsx(Field.ErrorText, { children: step1Form.formState.errors.birthDay?.message })] }), _jsxs(Field.Root, { invalid: !!step1Form.formState.errors.branchCode, className: "mt-xl", children: [_jsxs(Select.Root, { value: [branchCode], onValueChange: (details) => {
149
+ step1Form.setValue('branchCode', details.value.at(0) ?? BRANCH_CODES[0].code, {
150
+ shouldDirty: true,
151
+ shouldTouch: true,
152
+ shouldValidate: true,
153
+ });
154
+ }, collection: branchCollection, positioning: {
155
+ sameWidth: true,
156
+ placement: 'bottom',
157
+ }, lazyMount: true, unmountOnExit: true, children: [_jsx(Select.Label, { children: "Branch" }), _jsxs(Select.Trigger, { children: [_jsx(Select.ValueText, {}), _jsx(Select.Indicator, { asChild: true, children: _jsx(ChevronDownIcon, {}) })] }), _jsx(Select.Positioner, { children: _jsx(Select.Content, { children: branchCollection.items.map((item) => (_jsx(Select.Item, { item: item, children: branchCollection.stringifyItem(item) }, item.code))) }) })] }), _jsx(Field.ErrorText, { children: step1Form.formState.errors.branchCode?.message })] }), _jsx(Controller, { control: step1Form.control, name: "termsAccepted", render: (o) => (_jsxs(Field.Root, { className: "mt-2xl", invalid: o.fieldState.invalid, children: [_jsxs(Checkbox.Root, { checked: o.field.value, onCheckedChange: (details) => {
92
158
  o.field.onChange(details.checked);
93
- }, children: [_jsx(Checkbox.Control, { children: _jsx(Checkbox.Indicator, { asChild: true, children: _jsx(CheckIcon, {}) }) }), _jsxs(Checkbox.Label, { children: ["I am at least 21 years of age and I accept the", ' ', _jsx("span", { className: "text-brand-400 whitespace-nowrap underline underline-offset-2", children: "Terms and Conditions." })] }), ' ', _jsx(Checkbox.HiddenInput, {})] }), _jsx(Field.ErrorText, { className: "ml-6 text-xs", children: o.fieldState.error?.message })] })) })] }), _jsxs("div", { className: "mt-6 flex w-full items-center justify-center gap-xs text-sm", children: [_jsx("span", { className: "text-text-tertiary-600", children: "Don't have an account?" }), _jsx("button", { type: "submit", className: "text-button-tertiary-fg font-semibold", onClick: () => {
159
+ }, children: [_jsx(Checkbox.Control, { children: _jsx(Checkbox.Indicator, { asChild: true, children: _jsx(CheckIcon, {}) }) }), _jsxs(Checkbox.Label, { children: ["I am at least 21 years of age and I accept the", ' ', _jsx("span", { className: "text-brand-400 whitespace-nowrap underline underline-offset-2", children: "Terms and Conditions." })] }), ' ', _jsx(Checkbox.HiddenInput, {})] }), _jsx(Field.ErrorText, { className: "ml-6 text-xs", children: o.fieldState.error?.message })] })) }), _jsx(Button, { type: "submit", className: "mt-3xl", disabled: step1Form.formState.isSubmitting, children: "Create Account" })] }), _jsxs("div", { className: "relative mt-6 text-center", children: [_jsx("hr", { className: "-translte-y-1/2 text-text-tertiary-600/50 absolute top-1/2 w-full" }), _jsx("span", { className: "text-text-tertiary-600 bg-bg-primary-alt relative px-md text-center text-sm font-semibold", children: "Log in directly with" })] }), _jsxs("div", { className: "mt-6", children: [_jsxs(Button, { variant: "outline", colorScheme: "gray", onClick: () => {
160
+ dialog.setOpen(false);
161
+ }, className: "border-border-primary bg-bg-primary text-text-secondary-700", children: [_jsx(GoogleIcon, { className: "size-6" }), "Sign in with Google"] }), _jsxs(Button, { variant: "outline", colorScheme: "gray", onClick: () => {
162
+ dialog.setOpen(false);
163
+ }, className: "border-border-primary bg-bg-primary text-text-secondary-700 mt-lg", children: [_jsx(FacebookIcon, { className: "size-6" }), "Sign in with Facebook"] })] }), _jsxs("div", { className: "mt-6 flex w-full items-center justify-center gap-xs text-sm", children: [_jsx("span", { className: "text-text-tertiary-600", children: "Already have an account?" }), _jsx("button", { type: "submit", className: "text-button-tertiary-fg font-semibold", onClick: () => {
94
164
  dialog.setOpen(false);
95
165
  signInStore.setOpen(true);
96
166
  }, children: "Log In" })] })] })), step === 2 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "mt-xl text-center text-lg font-semibold", children: "Check your Phone" }), _jsxs("p", { className: "text-text-secondary-700 mt-xs text-center text-sm", children: ["We\u2019ve sent a verification code to your mobile number", ' ', _jsx("span", { className: "font-semibold", children: mobileNumberParser.format(step1Form.getValues('mobileNumber')) }), ' ', "via text"] }), _jsxs("form", { ref: form2Ref, className: "mt-5", onSubmit: step2Form.handleSubmit(async ({ verificationCode }) => {
@@ -107,16 +177,35 @@ export function SignUpForm() {
107
177
  });
108
178
  const name = mobileNumberParser.format(mobileNumber);
109
179
  const password = `${name}${id}`;
110
- try {
111
- await signInMutation.mutateAsync({
112
- type: 'NAME_AND_PASSWORD',
113
- name: mobileNumberParser.format(mobileNumber),
114
- password,
115
- });
116
- }
117
- catch {
180
+ const poll = createPoll(async () => {
181
+ try {
182
+ await signInMutation.mutateAsync({
183
+ type: 'NAME_AND_PASSWORD',
184
+ name,
185
+ password,
186
+ });
187
+ return true;
188
+ }
189
+ catch {
190
+ return false;
191
+ }
192
+ }, {
193
+ until: (ok) => ok,
194
+ maxAttempt: 5,
195
+ });
196
+ const ok = await poll();
197
+ if (!ok) {
118
198
  signInStore.setOpen(true);
119
199
  }
200
+ else {
201
+ await updateAccountMutation
202
+ .mutateAsync({
203
+ branchCode: step1Form.getValues('branchCode'),
204
+ realName: step1Form.getValues('realName'),
205
+ birthDay: format(step1Form.getValues('birthDay'), 'yyyy-MM-dd'),
206
+ })
207
+ .catch(noop);
208
+ }
120
209
  dialog.setOpen(false);
121
210
  step1Form.reset();
122
211
  step2Form.reset();
@@ -148,3 +237,4 @@ export function SignUpForm() {
148
237
  cooldown.stop();
149
238
  }, children: [_jsx(ArrowLeftIcon, { className: "size-5" }), "Back"] })] })] }))] }));
150
239
  }
240
+ const DEVICE_TIMEZONE = Intl.DateTimeFormat().resolvedOptions().timeZone;