@opexa/portal-components 0.0.116 → 0.0.118

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 (176) 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/CustomPromo/CustomPromo.d.ts +7 -0
  4. package/dist/components/CustomPromo/CustomPromo.js +11 -0
  5. package/dist/components/CustomPromo/index.d.ts +1 -0
  6. package/dist/components/CustomPromo/index.js +1 -0
  7. package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/OnlineBankDepositContext.d.ts +2 -2
  8. package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/useOnlineBankDeposit.d.ts +1 -1
  9. package/dist/components/DepositWithdrawal/Deposit/QRPHDeposit/QRPHDepositContext.d.ts +2 -2
  10. package/dist/components/DepositWithdrawal/Deposit/QRPHDeposit/useQRPHDeposit.d.ts +1 -1
  11. package/dist/components/Disclaimer/DisclaimerV1.js +1 -1
  12. package/dist/components/GameLaunch/GameLaunch.lazy.js +1 -1
  13. package/dist/components/GamesSearch/GamesSearch.js +1 -1
  14. package/dist/components/Jackpots/JackpotsCarousel/JackpotsCarouselItem.module.css +184 -184
  15. package/dist/components/Jackpots/JackpotsList/JackpotsListItem.module.css +184 -184
  16. package/dist/components/News/News.js +1 -1
  17. package/dist/components/Promo/Promo.client.js +1 -1
  18. package/dist/components/Promos/Cashback.d.ts +1 -1
  19. package/dist/components/Promos/Cashback.js +1 -1
  20. package/dist/components/Promos/CustomPromo.d.ts +7 -0
  21. package/dist/components/Promos/CustomPromo.js +7 -0
  22. package/dist/components/Promos/Promo.js +1 -1
  23. package/dist/components/Promos/PromosCarousel.d.ts +12 -0
  24. package/dist/components/Promos/PromosCarousel.js +7 -4
  25. package/dist/components/Promos/PromosGrid.d.ts +3 -0
  26. package/dist/components/Promos/PromosGrid.js +7 -4
  27. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuest.d.ts +1 -4
  28. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuest.js +38 -30
  29. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuestRules.d.ts +6 -0
  30. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuestRules.js +15 -0
  31. package/dist/components/Quests/OnboardingQuest/OnboardingQuest.d.ts +1 -4
  32. package/dist/components/Quests/OnboardingQuest/OnboardingQuest.js +27 -3
  33. package/dist/components/Quests/OnboardingQuest/OnboardingQuestRules.d.ts +6 -0
  34. package/dist/components/Quests/OnboardingQuest/OnboardingQuestRules.js +15 -0
  35. package/dist/components/Quests/WageringQuest/WageringQuest.d.ts +1 -4
  36. package/dist/components/Quests/WageringQuest/WageringQuest.js +15 -11
  37. package/dist/components/Quests/WageringQuest/WageringQuestRules.d.ts +7 -0
  38. package/dist/components/Quests/WageringQuest/WageringQuestRules.js +17 -0
  39. package/dist/components/Search/Search.lazy.js +1 -1
  40. package/dist/components/SignIn/MobileNumberSignIn.js +3 -1
  41. package/dist/components/SignUp/SignUpForm.js +100 -10
  42. package/dist/components/Tournaments/TournamentsCarousel/TournamentsCarouselItem.module.css +184 -184
  43. package/dist/components/Tournaments/TournamentsList/TournamentItem.module.css +184 -184
  44. package/dist/constants/BranchCode.d.ts +4 -0
  45. package/dist/constants/BranchCode.js +42 -0
  46. package/dist/constants/index.d.ts +1 -0
  47. package/dist/constants/index.js +1 -0
  48. package/dist/icons/CalendarIcon.js +1 -1
  49. package/dist/services/queries.js +2369 -2369
  50. package/dist/styles/theme.css +699 -699
  51. package/dist/types/index.d.ts +7 -0
  52. package/dist/ui/DatePicker/DatePicker.d.ts +1080 -2088
  53. package/dist/ui/DatePicker/datePicker.recipe.d.ts +39 -81
  54. package/dist/ui/DatePicker/datePicker.recipe.js +19 -0
  55. package/dist/ui/Select/Select.d.ts +45 -45
  56. package/dist/ui/Select/select.recipe.d.ts +3 -3
  57. package/dist/ui/Select/select.recipe.js +2 -2
  58. package/package.json +163 -163
  59. package/dist/client/hooks/index.d.ts +0 -65
  60. package/dist/client/hooks/index.js +0 -65
  61. package/dist/client/services/index.d.ts +0 -4
  62. package/dist/client/services/index.js +0 -4
  63. package/dist/client/utils/index.d.ts +0 -3
  64. package/dist/client/utils/index.js +0 -3
  65. package/dist/components/Empty.d.ts +0 -10
  66. package/dist/components/Empty.js +0 -7
  67. package/dist/components/Games/GameContext.d.ts +0 -2
  68. package/dist/components/Games/GameContext.js +0 -2
  69. package/dist/components/InfiniteScroll.d.ts +0 -10
  70. package/dist/components/InfiniteScroll.js +0 -25
  71. package/dist/components/JackpotCounter/JackpotCounter.client.d.ts +0 -2
  72. package/dist/components/JackpotCounter/JackpotCounter.client.js +0 -66
  73. package/dist/components/JackpotCounter/JackpotCounter.d.ts +0 -17
  74. package/dist/components/JackpotCounter/JackpotCounter.js +0 -21
  75. package/dist/components/JackpotCounter/JackpotCounterItem.d.ts +0 -18
  76. package/dist/components/JackpotCounter/JackpotCounterItem.js +0 -109
  77. package/dist/components/JackpotCounter/JackpotCounterItem.module.css +0 -184
  78. package/dist/components/JackpotCounter/index.d.ts +0 -1
  79. package/dist/components/JackpotCounter/index.js +0 -1
  80. package/dist/components/Jackpots/JackpotDesktop.d.ts +0 -1
  81. package/dist/components/Jackpots/JackpotDesktop.js +0 -45
  82. package/dist/components/Jackpots/JackpotGameProviders.d.ts +0 -5
  83. package/dist/components/Jackpots/JackpotGameProviders.js +0 -41
  84. package/dist/components/Jackpots/JackpotItemDesktop.d.ts +0 -9
  85. package/dist/components/Jackpots/JackpotItemDesktop.js +0 -43
  86. package/dist/components/Jackpots/JackpotItemMobile.d.ts +0 -9
  87. package/dist/components/Jackpots/JackpotItemMobile.js +0 -44
  88. package/dist/components/Jackpots/JackpotMobile.d.ts +0 -1
  89. package/dist/components/Jackpots/JackpotMobile.js +0 -46
  90. package/dist/components/Jackpots/JackpotRules.d.ts +0 -5
  91. package/dist/components/Jackpots/JackpotRules.js +0 -11
  92. package/dist/components/Jackpots/Jackpots.client.d.ts +0 -2
  93. package/dist/components/Jackpots/Jackpots.client.js +0 -29
  94. package/dist/components/Jackpots/JackpotsContext.d.ts +0 -4
  95. package/dist/components/Jackpots/JackpotsContext.js +0 -3
  96. package/dist/components/Jackpots/useJackpotData.d.ts +0 -14
  97. package/dist/components/Jackpots/useJackpotData.js +0 -93
  98. package/dist/components/Jackpots/useJackpotItemData.d.ts +0 -20
  99. package/dist/components/Jackpots/useJackpotItemData.js +0 -87
  100. package/dist/components/KYC/Header.d.ts +0 -1
  101. package/dist/components/KYC/Header.js +0 -6
  102. package/dist/components/KYC/Step1.d.ts +0 -1
  103. package/dist/components/KYC/Step1.js +0 -12
  104. package/dist/components/KYC/Step2.d.ts +0 -1
  105. package/dist/components/KYC/Step2.js +0 -12
  106. package/dist/components/KYC/Step3.d.ts +0 -1
  107. package/dist/components/KYC/Step3.js +0 -11
  108. package/dist/components/KYC/Step4.d.ts +0 -1
  109. package/dist/components/KYC/Step4.js +0 -6
  110. package/dist/components/Messages/MessageItem.d.ts +0 -4
  111. package/dist/components/Messages/MessageItem.js +0 -34
  112. package/dist/components/PortalProvider/WebVitals.d.ts +0 -1
  113. package/dist/components/PortalProvider/WebVitals.js +0 -8
  114. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuestModal.d.ts +0 -8
  115. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuestModal.js +0 -8
  116. package/dist/components/Quests/WageringQuest/WageringQuestModal.d.ts +0 -9
  117. package/dist/components/Quests/WageringQuest/WageringQuestModal.js +0 -8
  118. package/dist/components/TournamentCounter/TournamentCounter.client.d.ts +0 -2
  119. package/dist/components/TournamentCounter/TournamentCounter.client.js +0 -50
  120. package/dist/components/TournamentCounter/TournamentCounter.d.ts +0 -8
  121. package/dist/components/TournamentCounter/TournamentCounter.js +0 -21
  122. package/dist/components/TournamentCounter/TournamentCounterItem.d.ts +0 -8
  123. package/dist/components/TournamentCounter/TournamentCounterItem.js +0 -106
  124. package/dist/components/TournamentCounter/index.d.ts +0 -1
  125. package/dist/components/TournamentCounter/index.js +0 -1
  126. package/dist/components/Tournaments/TournamentDesktop.d.ts +0 -1
  127. package/dist/components/Tournaments/TournamentDesktop.js +0 -57
  128. package/dist/components/Tournaments/TournamentGameProviders.d.ts +0 -5
  129. package/dist/components/Tournaments/TournamentGameProviders.js +0 -38
  130. package/dist/components/Tournaments/TournamentItemDesktop.d.ts +0 -7
  131. package/dist/components/Tournaments/TournamentItemDesktop.js +0 -56
  132. package/dist/components/Tournaments/TournamentItemMobile.d.ts +0 -7
  133. package/dist/components/Tournaments/TournamentItemMobile.js +0 -54
  134. package/dist/components/Tournaments/TournamentMobile.d.ts +0 -1
  135. package/dist/components/Tournaments/TournamentMobile.js +0 -55
  136. package/dist/components/Tournaments/TournamentRules.d.ts +0 -5
  137. package/dist/components/Tournaments/TournamentRules.js +0 -11
  138. package/dist/components/Tournaments/Tournaments.client.d.ts +0 -2
  139. package/dist/components/Tournaments/Tournaments.client.js +0 -20
  140. package/dist/components/Tournaments/TournamentsContext.d.ts +0 -4
  141. package/dist/components/Tournaments/TournamentsContext.js +0 -3
  142. package/dist/components/Tournaments/useTournamentData.d.ts +0 -10
  143. package/dist/components/Tournaments/useTournamentData.js +0 -72
  144. package/dist/components/Tournaments/useTournamentItemData.d.ts +0 -16
  145. package/dist/components/Tournaments/useTournamentItemData.js +0 -64
  146. package/dist/components/index.d.ts +0 -33
  147. package/dist/components/index.js +0 -33
  148. package/dist/constants/envVars.d.ts +0 -5
  149. package/dist/constants/envVars.js +0 -28
  150. package/dist/constants/gameProviders.d.ts +0 -5
  151. package/dist/constants/gameProviders.js +0 -362
  152. package/dist/constants/gameTypes.d.ts +0 -4
  153. package/dist/constants/gameTypes.js +0 -64
  154. package/dist/constants/headerKeys.d.ts +0 -1
  155. package/dist/constants/headerKeys.js +0 -1
  156. package/dist/constants/secretQuestions.d.ts +0 -3
  157. package/dist/constants/secretQuestions.js +0 -24
  158. package/dist/constants/storageKeys.d.ts +0 -2
  159. package/dist/constants/storageKeys.js +0 -2
  160. package/dist/icons/index.d.ts +0 -65
  161. package/dist/icons/index.js +0 -65
  162. package/dist/images/hacksaw-gaming.png +0 -0
  163. package/dist/server/services/index.d.ts +0 -4
  164. package/dist/server/services/index.js +0 -4
  165. package/dist/server/utils/index.d.ts +0 -29
  166. package/dist/server/utils/index.js +0 -29
  167. package/dist/ui/Presence.d.ts +0 -2
  168. package/dist/ui/Presence.js +0 -7
  169. package/dist/ui/Prose.d.ts +0 -2
  170. package/dist/ui/Prose.js +0 -5
  171. package/dist/ui/index.d.ts +0 -26
  172. package/dist/ui/index.js +0 -26
  173. package/dist/utils/index.d.ts +0 -17
  174. package/dist/utils/index.js +0 -17
  175. package/dist/utils/isMobile.d.ts +0 -5
  176. package/dist/utils/isMobile.js +0 -9
@@ -3,16 +3,29 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import { addDays, isEqual, startOfDay } from 'date-fns';
4
4
  import { useState } from 'react';
5
5
  import { twMerge } from 'tailwind-merge';
6
- import { useCheckInDailyCheckInQuestMutation } from '../../../client/hooks/index.js';
7
- import { toaster } from '../../../client/utils/index.js';
8
- import { CalendarIcon, CheckIcon, ClockStopWatchIcon, InfoCircleIcon, } from '../../../icons/index.js';
9
- import { Badge, Button } from '../../../ui/index.js';
10
- import { getAvailableQuestsQueryKey, getQueryClient } from '../../../utils/index.js';
6
+ import { useCheckInDailyCheckInQuestMutation } from '../../../client/hooks/useCheckInDailyCheckInQuestMutation.js';
7
+ import { useDisclosure } from '../../../client/hooks/useDisclosure.js';
8
+ import { useLocaleInfo } from '../../../client/hooks/useLocaleInfo.js';
9
+ import { toaster } from '../../../client/utils/toaster.js';
10
+ import { CalendarIcon } from '../../../icons/CalendarIcon.js';
11
+ import { CheckIcon } from '../../../icons/CheckIcon.js';
12
+ import { ClockStopWatchIcon } from '../../../icons/ClockStopWatchIcon.js';
13
+ import { InfoCircleIcon } from '../../../icons/InfoCircleIcon.js';
14
+ import { Badge } from '../../../ui/Badge/index.js';
15
+ import { Button } from '../../../ui/Button/index.js';
16
+ import { dataAttr } from '../../../utils/dataAttr.js';
17
+ import { formatNumber } from '../../../utils/formatNumber.js';
18
+ import { getQueryClient } from '../../../utils/getQueryClient.js';
19
+ import { parseDecimal } from '../../../utils/parseDecimal.js';
20
+ import { getAvailableQuestsQueryKey } from '../../../utils/queryKeys.js';
11
21
  import CountdownTimer from '../CountdownTimer.js';
12
- import { DailyCheckInQuestModal } from './DailyCheckInQuestModal.js';
13
- export function DailyCheckInQuest({ quest }) {
22
+ import { useQuestContext } from '../QuestsContext.js';
23
+ import { DailyCheckInQuestRules } from './DailyCheckInQuestRules.js';
24
+ export function DailyCheckInQuest() {
25
+ const quest = useQuestContext();
14
26
  const queryClient = getQueryClient();
15
- const [showRules, setShowRules] = useState(false);
27
+ const disclosure = useDisclosure();
28
+ const localeInfo = useLocaleInfo();
16
29
  const [isExpired, setIsExpired] = useState(false);
17
30
  const { name, description, status, lastCheckInDate, progressPercentage, checkInStreak, thirdDayBonusAmount, sixthDayBonusAmount, seventhDayBonusAmount, endDateTime, id, } = quest;
18
31
  const today = startOfDay(new Date());
@@ -20,26 +33,23 @@ export function DailyCheckInQuest({ quest }) {
20
33
  ? isEqual(today, startOfDay(new Date(lastCheckInDate)))
21
34
  : false;
22
35
  const checkedInRewards = {
23
- 3: thirdDayBonusAmount,
24
- 6: sixthDayBonusAmount,
25
- 7: seventhDayBonusAmount,
36
+ 3: parseDecimal(thirdDayBonusAmount, 0),
37
+ 6: parseDecimal(sixthDayBonusAmount, 0),
38
+ 7: parseDecimal(seventhDayBonusAmount, 0),
26
39
  };
27
40
  const dailyCheckedInData = Array.from({ length: 7 }, (_, i) => {
28
41
  const day = i + 1;
29
42
  return {
30
43
  day,
31
- reward: checkedInRewards[day] ?? 0,
44
+ reward: checkedInRewards[day] ? checkedInRewards[day] : null,
32
45
  };
33
46
  });
34
- const { mutate } = useCheckInDailyCheckInQuestMutation({
47
+ const checkInDailyQuestMutation = useCheckInDailyCheckInQuestMutation({
35
48
  onSuccess() {
36
49
  toaster.success({
37
50
  title: 'Check-in successful 🎉',
38
51
  description: 'You’ve successfully checked in for today! Keep it up to maintain your streak!',
39
52
  });
40
- queryClient.invalidateQueries({
41
- queryKey: getAvailableQuestsQueryKey(),
42
- });
43
53
  },
44
54
  onError(e) {
45
55
  toaster.error({
@@ -48,26 +58,24 @@ export function DailyCheckInQuest({ quest }) {
48
58
  });
49
59
  },
50
60
  });
51
- const handleCheckIn = async () => mutate(id);
52
- return (_jsxs(_Fragment, { children: [_jsx(DailyCheckInQuestModal, { modalState: {
53
- isOpen: showRules,
54
- setIsOpen: setShowRules,
55
- } }), _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: [_jsx("div", { className: "grid grid-cols-7", children: dailyCheckedInData.map((item) => {
56
- const reward = item.reward ? `+₱${item.reward}` : '-';
61
+ 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: [_jsx("div", { className: "grid grid-cols-7", children: dailyCheckedInData.map((item) => {
62
+ const reward = item.reward
63
+ ? `+${formatNumber(item.reward, {
64
+ currency: localeInfo.currency.code,
65
+ minDecimalPlaces: 0,
66
+ maxDecimalPlaces: 0,
67
+ })}`
68
+ : '-';
57
69
  return (_jsx("div", { className: twMerge('flex items-center justify-center', item.day <= (checkInStreak || 0)
58
70
  ? 'text-brand-400'
59
71
  : 'text-text-secondary-700'), children: _jsx("p", { children: reward }) }, item.day));
60
- }) }), _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: "grid grid-cols-7", children: dailyCheckedInData.map((item) => (_jsx("div", { className: "flex items-center justify-center", children: _jsx(CalendarWithDayNumber, { day: item.day, currentCheckedInDays: checkInStreak || 0 }, item.day) }, item.day))) })] }), _jsx(Button, { onClick: handleCheckIn, className: "disabled:bg-bg-primary disabled:text-text-disabled", disabled: isExpired ||
72
+ }) }), _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: "grid grid-cols-7 place-items-center", children: dailyCheckedInData.map((item) => (_jsxs("div", { className: "text-text-secondary-700 ui-active:text-brand-400 group relative size-fit", "data-active": dataAttr(item.day <= (checkInStreak ?? 0)), children: [_jsx(CalendarIcon, { className: "h-4.5 w-auto" }), _jsx("p", { className: "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-2xs leading-none", children: item.day })] }, item.day))) })] }), _jsx(Button, { onClick: () => checkInDailyQuestMutation.mutate(id), className: "disabled:bg-bg-primary disabled:text-text-disabled", disabled: isExpired ||
61
73
  status === 'COMPLETED' ||
62
74
  status === 'FAILED' ||
63
- hasCheckedInToday, children: hasCheckedInToday && status === 'IN_PROGRESS' ? (_jsx(CountdownTimer, { endDateTime: startOfDay(addDays(new Date(), 1)).toISOString(), renderAction: (timeLeft) => (_jsxs("div", { className: "flex items-center space-x-0.5", children: [_jsx(CheckIcon, {}), _jsxs("p", { children: [timeLeft.hours, "h:", timeLeft.minutes, "m:", timeLeft.seconds, "s"] })] })), onEnd: () => {
75
+ hasCheckedInToday ||
76
+ checkInDailyQuestMutation.isPending, children: hasCheckedInToday && status === 'IN_PROGRESS' ? (_jsx(CountdownTimer, { endDateTime: startOfDay(addDays(new Date(), 1)).toISOString(), renderAction: (timeLeft) => (_jsxs("div", { className: "flex items-center space-x-0.5", children: [_jsx(CheckIcon, { className: "size-5" }), _jsxs("p", { children: [timeLeft.hours, "h:", timeLeft.minutes, "m:", timeLeft.seconds, "s"] })] })), onEnd: () => {
64
77
  queryClient.invalidateQueries({
65
78
  queryKey: getAvailableQuestsQueryKey(),
66
79
  });
67
- } })) : ('Check-In') })] })] }));
68
- }
69
- function CalendarWithDayNumber({ day, currentCheckedInDays, }) {
70
- return (_jsxs("div", { className: twMerge('group relative h-fit w-fit', day <= currentCheckedInDays
71
- ? 'text-brand-400'
72
- : 'text-text-secondary-700'), children: [_jsx(CalendarIcon, {}), _jsx("div", { className: "absolute inset-0 mt-1 flex items-center justify-center text-2xs lg:mt-[2px]", children: _jsx("p", { className: "text-center", children: day }) })] }));
80
+ } })) : ('Check-In') })] }), _jsx(DailyCheckInQuestRules, { open: disclosure.open, onOpenChange: disclosure.setOpen })] }));
73
81
  }
@@ -0,0 +1,6 @@
1
+ export interface DailyCheckInQuestRulesProps {
2
+ open?: boolean;
3
+ onOpenChange?: (open: boolean) => void;
4
+ defaultOpen?: boolean;
5
+ }
6
+ export declare function DailyCheckInQuestRules(props: DailyCheckInQuestRulesProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,15 @@
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
+ export function DailyCheckInQuestRules(props) {
9
+ const [open, setOpen] = useControllableState({
10
+ value: props.open,
11
+ defaultValue: props.defaultOpen ?? false,
12
+ onChange: props.onOpenChange,
13
+ });
14
+ 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: "Daily Check-In Rules" }), _jsxs("ol", { className: "text-text-tertiary-600 group list-disc text-wrap pl-4 text-sm font-normal", children: [_jsx("li", { children: "Earn rewards just for checking in each day!" }), _jsx("li", { children: "Stay consistent to unlock special rewards on the 3rd, 5th, and 7th day." }), _jsx("li", { children: "Missing a day will reset your streak, starting again from Day 1." }), _jsx("li", { children: "Each check-in unlocks the next one on the following day." }), _jsx("li", { children: "Successfully check in for 7 consecutive days to complete the quest and reset the cycle." })] })] }), _jsx("div", { className: "pb-4 pt-6", children: _jsx(Button, { onClick: () => setOpen(false), children: "Ok" }) })] }) })] }) }));
15
+ }
@@ -1,4 +1 @@
1
- import type { Quest } from '@opexa/portal-sdk-core';
2
- export declare function OnboardingQuest(props: {
3
- quest: Quest;
4
- }): null;
1
+ export declare function OnboardingQuest(): import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,28 @@
1
- export function OnboardingQuest(props) {
2
- console.log('OnboardingQuest not implemented', props.quest);
3
- return null;
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useShallow } from 'zustand/shallow';
3
+ import { useDisclosure } from '../../../client/hooks/useDisclosure.js';
4
+ import { useGlobalStore } from '../../../client/hooks/useGlobalStore.js';
5
+ import { CheckIcon } from '../../../icons/CheckIcon.js';
6
+ import { ClockStopWatchIcon } from '../../../icons/ClockStopWatchIcon.js';
7
+ import { CoinsHandIcon } from '../../../icons/CoinsHandIcon.js';
8
+ import { FileCheck02Icon } from '../../../icons/FileCheck02Icon.js';
9
+ import { InfoCircleIcon } from '../../../icons/InfoCircleIcon.js';
10
+ import { Badge } from '../../../ui/Badge/index.js';
11
+ import { Button } from '../../../ui/Button/index.js';
12
+ import { Checkbox } from '../../../ui/Checkbox/index.js';
13
+ import { useQuestContext } from '../QuestsContext.js';
14
+ import { OnboardingQuestRules } from './OnboardingQuestRules.js';
15
+ export function OnboardingQuest() {
16
+ const quest = useQuestContext();
17
+ const disclosure = useDisclosure();
18
+ const globalStore = useGlobalStore(useShallow((ctx) => ({
19
+ kyc: ctx.kyc,
20
+ depositWithdrawal: ctx.depositWithdrawal,
21
+ })));
22
+ 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: [_jsxs(Badge.Root, { size: "lg", colorScheme: "brand", round: false, children: [_jsx(Badge.Icon, { children: _jsx(ClockStopWatchIcon, {}) }), _jsx(Badge.Label, { children: "123" })] }), _jsx("div", { role: "button", className: "bg-bg-primary border-border-secondary flex size-9 cursor-pointer items-center justify-center rounded-md border", children: _jsx(InfoCircleIcon, { className: "text-text-disabled size-5" }) })] }), _jsx("h2", { className: "text-xl font-semibold", children: quest.name }), _jsx("p", { className: "text-text-secondary-700 text-wrap text-sm font-normal", dangerouslySetInnerHTML: { __html: quest.description } })] }), _jsxs("div", { className: "w-full grow space-y-2", children: [_jsxs(Checkbox.Root, { children: [_jsx(Checkbox.Control, { className: "bg-transparent", children: _jsx(Checkbox.Indicator, { asChild: true, children: _jsx(CheckIcon, {}) }) }), _jsx(Checkbox.Label, { className: "text-sm font-medium leading-tight", children: "Complete personal verification" }), _jsx(Checkbox.HiddenInput, {})] }), _jsxs(Checkbox.Root, { children: [_jsx(Checkbox.Control, { className: "bg-transparent", children: _jsx(Checkbox.Indicator, { asChild: true, children: _jsx(CheckIcon, {}) }) }), _jsx(Checkbox.Label, { className: "text-sm font-medium leading-tight", children: "Make your first deposit" }), _jsx(Checkbox.HiddenInput, {})] })] }), _jsxs("div", { className: "flex gap-lg", children: [_jsxs(Button, { size: "sm", onClick: () => {
23
+ globalStore.kyc.setOpen(true);
24
+ }, children: [_jsx(FileCheck02Icon, { className: "size-5" }), "Verify"] }), _jsxs(Button, { size: "sm", onClick: () => {
25
+ globalStore.depositWithdrawal.setTab('DEPOSIT');
26
+ globalStore.depositWithdrawal.setOpen(true);
27
+ }, children: [_jsx(CoinsHandIcon, { className: "size-5" }), "Deposit"] })] })] }), _jsx(OnboardingQuestRules, { open: disclosure.open, onOpenChange: disclosure.setOpen })] }));
4
28
  }
@@ -0,0 +1,6 @@
1
+ export interface OnboardingQuestRulesProps {
2
+ open?: boolean;
3
+ onOpenChange?: (open: boolean) => void;
4
+ defaultOpen?: boolean;
5
+ }
6
+ export declare function OnboardingQuestRules(props: OnboardingQuestRulesProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,15 @@
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
+ export function OnboardingQuestRules(props) {
9
+ const [open, setOpen] = useControllableState({
10
+ value: props.open,
11
+ defaultValue: props.defaultOpen ?? false,
12
+ onChange: props.onOpenChange,
13
+ });
14
+ 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: "Welcome Quest Rules" }), _jsxs("ol", { className: "text-text-tertiary-600 group list-disc text-wrap pl-4 text-sm font-normal", children: [_jsx("li", { children: "Begin your quest whenever you're ready" }), _jsx("li", { children: "Tackle the tasks in any order you like" }), _jsx("li", { children: "Finish all tasks and we'll credit your reward automatically!" })] })] }), _jsx("div", { className: "pb-4 pt-6", children: _jsx(Button, { onClick: () => setOpen(false), children: "Ok" }) })] }) })] }) }));
15
+ }
@@ -1,4 +1 @@
1
- import type { Quest } from '@opexa/portal-sdk-core';
2
- export declare function WageringQuest({ quest }: {
3
- quest: Quest;
4
- }): import("react/jsx-runtime").JSX.Element;
1
+ export declare function WageringQuest(): import("react/jsx-runtime").JSX.Element;
@@ -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;