@opexa/portal-components 0.0.886 → 0.0.888

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 (41) hide show
  1. package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/OnlineBankDepositContext.d.ts +2 -2
  2. package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/useOnlineBankDeposit.d.ts +1 -1
  3. package/dist/components/DepositWithdrawal/Deposit/QRPHDeposit/QRPHDepositContext.d.ts +2 -2
  4. package/dist/components/DepositWithdrawal/Deposit/QRPHDeposit/useQRPHDeposit.d.ts +1 -1
  5. package/dist/components/ForgotPassword/Crazywin/CWForgotPassword.d.ts +6 -0
  6. package/dist/components/ForgotPassword/Crazywin/CWForgotPassword.js +11 -0
  7. package/dist/components/ForgotPassword/Crazywin/CWForgotPasswordForm.d.ts +2 -0
  8. package/dist/components/ForgotPassword/Crazywin/CWForgotPasswordForm.js +75 -0
  9. package/dist/components/ForgotPassword/Crazywin/ForgotPassword.module.css +43 -0
  10. package/dist/components/ForgotPassword/ForgotPassword.lazy.d.ts +3 -0
  11. package/dist/components/ForgotPassword/ForgotPassword.lazy.js +6 -1
  12. package/dist/components/Jackpots/JackpotsCarousel/JackpotsCarouselItem.CrazyWin.js +5 -16
  13. package/dist/components/Jackpots/JackpotsCarousel/JackpotsCarouselItem.HappyBingo.d.ts +0 -1
  14. package/dist/components/Jackpots/JackpotsCarousel/JackpotsCarouselItem.HappyBingo.js +2 -8
  15. package/dist/components/Jackpots/JackpotsList/JackpotsList.js +2 -1
  16. package/dist/components/Jackpots/JackpotsList/JackpotsListItem.CrazyWin.js +6 -12
  17. package/dist/components/Jackpots/JackpotsList/JackpotsListItem.HappyBingo.d.ts +6 -0
  18. package/dist/components/Jackpots/JackpotsList/JackpotsListItem.HappyBingo.js +167 -0
  19. package/dist/components/Jackpots/utils.d.ts +1 -0
  20. package/dist/components/Jackpots/utils.js +6 -0
  21. package/dist/components/Promos/Cashback.d.ts +4 -1
  22. package/dist/components/Promos/Cashback.js +6 -3
  23. package/dist/components/Promos/CustomPromo.d.ts +3 -1
  24. package/dist/components/Promos/CustomPromo.js +3 -2
  25. package/dist/components/Promos/Promo.d.ts +4 -1
  26. package/dist/components/Promos/Promo.js +6 -3
  27. package/dist/components/Promos/PromosGrid.d.ts +3 -0
  28. package/dist/components/Promos/PromosGrid.js +1 -1
  29. package/dist/components/Promos/utils.d.ts +1 -0
  30. package/dist/components/Promos/utils.js +10 -0
  31. package/dist/components/SignIn/MobileNumberField.js +14 -11
  32. package/dist/images/3d-star.webp +0 -0
  33. package/dist/schemas/forgotPasswordSchema.d.ts +32 -0
  34. package/dist/schemas/forgotPasswordSchema.js +15 -0
  35. package/dist/services/game.d.ts +1 -1
  36. package/dist/services/game.js +2 -0
  37. package/dist/services/queries.d.ts +1 -1
  38. package/dist/services/queries.js +8 -0
  39. package/dist/services/wallet.d.ts +1 -1
  40. package/dist/services/wallet.js +2 -0
  41. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  export declare const OnlineBankDepositContext: (props: {
2
2
  value: {
3
3
  view: "form" | "vca";
4
- status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
4
+ status: "waiting" | "failed" | "processing" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
5
5
  verify: () => void;
6
6
  reset: () => void;
7
7
  deposit: import("../../../../types").Deposit | null;
@@ -14,7 +14,7 @@ export declare const OnlineBankDepositContext: (props: {
14
14
  children?: import("react").ReactNode | undefined;
15
15
  }) => React.ReactNode, useOnlineBankDepositContext: () => {
16
16
  view: "form" | "vca";
17
- status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
17
+ status: "waiting" | "failed" | "processing" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
18
18
  verify: () => void;
19
19
  reset: () => void;
20
20
  deposit: import("../../../../types").Deposit | null;
@@ -2,7 +2,7 @@ import type { Deposit } from '../../../../types';
2
2
  export type UseOnlineBankDepositReturn = ReturnType<typeof useOnlineBankDeposit>;
3
3
  export declare function useOnlineBankDeposit(): {
4
4
  view: "form" | "vca";
5
- status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
5
+ status: "waiting" | "failed" | "processing" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
6
6
  verify: () => void;
7
7
  reset: () => void;
8
8
  deposit: Deposit | null;
@@ -1,6 +1,6 @@
1
1
  export declare const QRPHDepositContext: (props: {
2
2
  value: {
3
- status: "failed" | "idle" | "generating-qr-code" | "qr-code-generated" | "confirmed";
3
+ status: "idle" | "generating-qr-code" | "qr-code-generated" | "failed" | "confirmed";
4
4
  deposit: import("../../../../types").Deposit | null;
5
5
  errorMessage: {
6
6
  name: string;
@@ -13,7 +13,7 @@ export declare const QRPHDepositContext: (props: {
13
13
  } & {
14
14
  children?: import("react").ReactNode | undefined;
15
15
  }) => React.ReactNode, useQRPHDepositContext: () => {
16
- status: "failed" | "idle" | "generating-qr-code" | "qr-code-generated" | "confirmed";
16
+ status: "idle" | "generating-qr-code" | "qr-code-generated" | "failed" | "confirmed";
17
17
  deposit: import("../../../../types").Deposit | null;
18
18
  errorMessage: {
19
19
  name: string;
@@ -5,7 +5,7 @@ export interface GenerateQRCodeInput {
5
5
  promo?: string | null;
6
6
  }
7
7
  export declare function useQRPHDeposit(): {
8
- status: "failed" | "idle" | "generating-qr-code" | "qr-code-generated" | "confirmed";
8
+ status: "idle" | "generating-qr-code" | "qr-code-generated" | "failed" | "confirmed";
9
9
  deposit: Deposit | null;
10
10
  errorMessage: {
11
11
  name: string;
@@ -0,0 +1,6 @@
1
+ import { type ImageProps } from 'next/image';
2
+ type Props = {
3
+ logo: ImageProps['src'];
4
+ };
5
+ declare const ForgotPassword: ({ logo }: Props) => import("react/jsx-runtime").JSX.Element;
6
+ export default ForgotPassword;
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import Image, {} from 'next/image';
3
+ import { twMerge } from 'tailwind-merge';
4
+ import { XIcon } from '../../../icons/XIcon.js';
5
+ import { Dialog } from '../../../ui/Dialog/index.js';
6
+ import CWForgotPasswordForm from './CWForgotPasswordForm.js';
7
+ import styles from './ForgotPassword.module.css';
8
+ const ForgotPassword = ({ logo }) => {
9
+ return (_jsx(Dialog.Content, { className: "bg-transparent h-full w-full overflow-y-invisible left-0 top-0 flex items-center", children: _jsxs("div", { className: "flex h-[90dvh] w-full flex-col justify-center scroll-smooth", children: [_jsxs("div", { className: "relative mx-auto w-full max-w-[22.5rem]", children: [_jsx(Image, { src: logo, alt: "", width: 200, height: 100, className: "mx-auto mt-8 h-auto w-[12.04544rem]", draggable: false }), _jsx(Dialog.CloseTrigger, { className: 'w-fit h-fit text-[#6C5200] rounded-md bg-gradient-to-t from-[#FFE5AF] to-[#EAC467] p-0.5', children: _jsx(XIcon, {}) })] }), _jsx("h2", { className: "mx-auto mt-10 w-fit bg-[linear-gradient(50deg,#c7802d_-5.1%,#ffe585_44.95%,#c7802d_109.05%)] bg-clip-text text-2xl font-bold uppercase text-transparent", children: "Forgot Password" }), _jsx("div", { className: twMerge('mx-auto mt-7.5 max-w-[20.6875rem] p-7.5', styles.card), children: _jsx(CWForgotPasswordForm, {}) })] }) }));
10
+ };
11
+ export default ForgotPassword;
@@ -0,0 +1,2 @@
1
+ declare const CWForgotPasswordForm: () => import("react/jsx-runtime").JSX.Element;
2
+ export default CWForgotPasswordForm;
@@ -0,0 +1,75 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { zodResolver } from '@hookform/resolvers/zod';
3
+ import Image from 'next/image';
4
+ import { useMemo } from 'react';
5
+ import { useForm } from 'react-hook-form';
6
+ import { twMerge } from 'tailwind-merge';
7
+ import { useShallow } from 'zustand/shallow';
8
+ import { useCooldown } from '../../../client/hooks/useCooldown.js';
9
+ import { useGlobalStore } from '../../../client/hooks/useGlobalStore.js';
10
+ import { useLocaleInfo } from '../../../client/hooks/useLocaleInfo.js';
11
+ import { useMobileNumberParser } from '../../../client/hooks/useMobileNumberParser.js';
12
+ import { useResetPasswordMutation } from '../../../client/hooks/useResetPasswordMutation.js';
13
+ import { useSendVerificationCodeMutation } from '../../../client/hooks/useSendVerificationCodeMutation.js';
14
+ import { toaster } from '../../../client/utils/toaster.js';
15
+ import { EyeIcon } from '../../../icons/EyeIcon.js';
16
+ import { EyeOffIcon } from '../../../icons/EyeOffIcon.js';
17
+ import lockIcon from '../../../images/lock-icon.webp';
18
+ import { createForgotPasswordSchema, } from '../../../schemas/forgotPasswordSchema.js';
19
+ import { Button } from '../../../ui/Button/index.js';
20
+ import { Field } from '../../../ui/Field/index.js';
21
+ import { PasswordInput } from '../../../ui/PasswordInput/index.js';
22
+ const CWForgotPasswordForm = () => {
23
+ const mobileNumberParser = useMobileNumberParser();
24
+ const schema = useMemo(() => createForgotPasswordSchema(mobileNumberParser), [mobileNumberParser]);
25
+ const { register, watch, getValues, handleSubmit, formState: { isValid, isDirty, errors }, } = useForm({
26
+ resolver: zodResolver(schema),
27
+ mode: 'onChange',
28
+ });
29
+ const mobileNumberValue = watch('mobileNumber');
30
+ const globalStore = useGlobalStore(useShallow((ctx) => ({
31
+ signIn: ctx.signIn,
32
+ forgotPassword: ctx.forgotPassword,
33
+ })));
34
+ const commonInputClass = 'h-10 w-full rounded-full border-none bg-black/40 text-xs placeholder:text-text-placeholder focus:outline-none focus:ring-0';
35
+ const localeInfo = useLocaleInfo();
36
+ const sendVerificationCodeMutation = useSendVerificationCodeMutation();
37
+ const resetPasswordMutation = useResetPasswordMutation({
38
+ onSuccess() {
39
+ globalStore.forgotPassword.setOpen(false);
40
+ globalStore.signIn.setOpen(true);
41
+ toaster.success({
42
+ description: 'Your password has been updated.',
43
+ });
44
+ },
45
+ onError(error) {
46
+ toaster.error({
47
+ description: error.message,
48
+ });
49
+ },
50
+ });
51
+ const cooldown = useCooldown({
52
+ max: 60,
53
+ duration: 1000 * 60,
54
+ });
55
+ const onSubmit = (data) => {
56
+ resetPasswordMutation.mutate({
57
+ mobileNumber: mobileNumberParser.format(data.mobileNumber),
58
+ newPassword: data.password,
59
+ verificationCode: data.verificationCode,
60
+ });
61
+ };
62
+ return (_jsx("form", { autoComplete: 'off', onSubmit: handleSubmit(onSubmit), children: _jsxs("div", { className: "space-y-4", children: [_jsxs(Field.Root, { invalid: !!errors.mobileNumber, children: [_jsx(Field.Label, { className: "text-xs", children: "Phone Number" }), _jsxs("div", { className: "relative flex h-10 gap-3", children: [_jsxs("div", { className: "flex h-full items-center gap-2 rounded-full bg-black/40 px-3.5 text-xs", children: [_jsx(localeInfo.country.flag, { className: "size-5" }), _jsx("span", { className: "text-text-placeholder", children: localeInfo.mobileNumber.areaCode })] }), _jsx(Field.Input, { className: commonInputClass, placeholder: "Enter Phone Number", ...register('mobileNumber') })] }), _jsx(Field.ErrorText, { className: "text-[#ff2525b3] text-xs", children: errors.mobileNumber?.message })] }), _jsx(Field.Root, { invalid: !!errors.password, children: _jsxs(PasswordInput.Root, { children: [_jsx(PasswordInput.Label, { className: "text-xs", children: "Password" }), _jsxs("div", { children: [_jsxs(PasswordInput.Control, { className: "relative flex h-10 items-center rounded-full text-xs bg-black/40 border-0", children: [_jsx(Image, { src: lockIcon, alt: "lock icon", width: 20, height: 20, className: "-translate-y-1/2 pointer-events-none absolute top-1/2 left-3 h-5 w-5" }), _jsx(PasswordInput.Input, { className: "pl-10", placeholder: "8 - 20 characters", ...register('password') }), _jsx(PasswordInput.VisibilityTrigger, { children: _jsx(PasswordInput.Indicator, { fallback: _jsx(EyeOffIcon, { className: "text-white/50" }), asChild: true, children: _jsx(EyeIcon, { className: "text-white/50" }) }) })] }), _jsx(Field.ErrorText, { className: "text-[#ff2525b3] text-xs", children: errors.password?.message })] })] }) }), _jsx(Field.Root, { invalid: !!errors.confirmPassword, children: _jsxs(PasswordInput.Root, { children: [_jsx(PasswordInput.Label, { className: "text-xs", children: "Confirm Password" }), _jsxs("div", { children: [_jsxs(PasswordInput.Control, { className: "relative flex h-10 items-center rounded-full text-xs bg-black/40 border-0", children: [_jsx(Image, { src: lockIcon, alt: "lock icon", width: 20, height: 20, className: "-translate-y-1/2 pointer-events-none absolute top-1/2 left-3 h-5 w-5" }), _jsx(PasswordInput.Input, { className: "pl-10", placeholder: "8 - 20 characters", ...register('confirmPassword') }), _jsx(PasswordInput.VisibilityTrigger, { children: _jsx(PasswordInput.Indicator, { fallback: _jsx(EyeOffIcon, { className: "text-white/50" }), asChild: true, children: _jsx(EyeIcon, { className: "text-white/50" }) }) })] }), _jsx(Field.ErrorText, { className: "text-[#ff2525b3] text-xs", children: errors.confirmPassword?.message })] })] }) }), _jsxs(Field.Root, { invalid: !!errors.verificationCode, children: [_jsx(Field.Label, { className: "text-xs", children: "OTP Code" }), _jsxs("div", { className: "relative", children: [_jsx(Field.Input, { className: twMerge(commonInputClass, 'pr-[5.75rem]'), placeholder: "Enter OTP Code", ...register('verificationCode') }), _jsx(Button, { type: "button", className: "absolute right-1 top-1/2 h-fit w-fit -translate-y-1/2 rounded-full py-[0.375rem] text-sm shadow-[inset_0px_-1px_2px_1px_#fff7e1] bg-[linear-gradient(89deg,#c7802d_-15.91%,#ffe585_28.75%,#ffeca6_49.46%,#c7802d_112.69%)]", disabled: !mobileNumberValue || !!errors.mobileNumber || cooldown.cooling, onClick: async () => {
63
+ if (!cooldown.cooling) {
64
+ await sendVerificationCodeMutation.mutateAsync({
65
+ channel: 'SMS',
66
+ recipient: mobileNumberParser.format(getValues('mobileNumber'))
67
+ });
68
+ cooldown.start();
69
+ toaster.success({
70
+ description: `OTP sent to ${getValues('mobileNumber')}`
71
+ });
72
+ }
73
+ }, children: cooldown.cooling ? cooldown.countdown : 'Get OTP' })] }), _jsx(Field.ErrorText, { className: "text-[#ff2525b3] text-xs", children: errors.verificationCode?.message })] }), _jsx(Button, { type: "submit", className: "mt-7.5 text-sm rounded-full shadow-[inset_0px_-1px_2px_1px_#fff7e1] bg-[linear-gradient(89deg,#c7802d_-15.91%,#ffe585_28.75%,#ffeca6_49.46%,#c7802d_112.69%)]", fullWidth: true, disabled: !isValid || !isDirty, children: "Change Password" })] }) }));
74
+ };
75
+ export default CWForgotPasswordForm;
@@ -0,0 +1,43 @@
1
+ .card {
2
+ --gradient-bg: radial-gradient(103.87% 100% at 50.15% 0%, #072b37 20.3%, #051125 100%);
3
+
4
+ --gradient-border-top: radial-gradient(
5
+ 139.23% 113.41% at 50.14% 0%,
6
+ #8affdc 0.49%,
7
+ rgba(138, 255, 220, 0) 33.03%
8
+ );
9
+
10
+ --gradient-border-bottom: radial-gradient(
11
+ 42.09% 54.21% at 50.14% 100%,
12
+ #8affdc 5.74%,
13
+ rgba(138, 255, 220, 0) 93.84%
14
+ );
15
+
16
+ position: relative;
17
+ background: var(--gradient-bg);
18
+ box-shadow: 0px 4px 14px 6px rgba(0, 0, 0, 0.6);
19
+ backdrop-filter: blur(25px);
20
+ border-radius: 1.25em;
21
+ border: 1px solid rgba(255, 255, 255, 0.1);
22
+ }
23
+
24
+ .card::after,
25
+ .card::before {
26
+ content: '';
27
+ position: absolute;
28
+ top: 0;
29
+ left: 0;
30
+ width: 100%;
31
+ height: 100%;
32
+ z-index: -1;
33
+ border: 0.5px solid transparent;
34
+ border-image-slice: 1;
35
+ }
36
+
37
+ .card::before {
38
+ border-image-source: var(--gradient-border-bottom);
39
+ }
40
+
41
+ .card::after {
42
+ border-image-source: var(--gradient-border-top);
43
+ }
@@ -1,8 +1,11 @@
1
1
  import { type ImageProps } from 'next/image';
2
2
  import { type ReactNode } from 'react';
3
+ type ForgotPasswordLayout = 'crazywin';
3
4
  export interface ForgotPasswordProps {
4
5
  logo: ImageProps['src'];
5
6
  children?: ReactNode;
6
7
  className?: string;
8
+ layout?: ForgotPasswordLayout;
7
9
  }
8
10
  export declare function ForgotPassword(props: ForgotPasswordProps): import("react/jsx-runtime").JSX.Element;
11
+ export {};
@@ -8,12 +8,17 @@ import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
8
8
  import { XIcon } from '../../icons/XIcon.js';
9
9
  import { Dialog } from '../../ui/Dialog/index.js';
10
10
  import { Portal } from '../../ui/Portal/index.js';
11
+ import CrazywinForgotPassword from './Crazywin/CWForgotPassword.js';
11
12
  import { ForgotPasswordForm } from './ForgotPasswordForm.js';
12
13
  export function ForgotPassword(props) {
13
14
  const globalStore = useGlobalStore(useShallow((ctx) => ({
14
15
  forgotPassword: ctx.forgotPassword,
15
16
  })));
17
+ const Body = {
18
+ crazywin: (_jsx(CrazywinForgotPassword, { logo: props.logo })),
19
+ default: (_jsxs(Dialog.Content, { className: twMerge('mx-auto h-full w-full items-start bg-bg-primary-alt p-3xl pb-4xl lg:h-auto lg:w-[400px] lg:rounded-xl', props.className), children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsx(Image, { src: props.logo, alt: "", width: 200, height: 100, className: "mx-auto h-auto w-[120px]", draggable: false }), _jsx(Suspense, { children: _jsx(ForgotPasswordForm, {}) })] }))
20
+ };
16
21
  return (_jsx(Dialog.Root, { open: globalStore.forgotPassword.open, onOpenChange: (details) => {
17
22
  globalStore.forgotPassword.setOpen(details.open);
18
- }, lazyMount: true, unmountOnExit: true, closeOnEscape: false, closeOnInteractOutside: false, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, {}), _jsx(Dialog.Positioner, { children: _jsxs(Dialog.Content, { className: twMerge('mx-auto h-full w-full items-start bg-bg-primary-alt p-3xl pb-4xl lg:h-auto lg:w-[400px] lg:rounded-xl', props.className), children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsx(Image, { src: props.logo, alt: "", width: 200, height: 100, className: "mx-auto h-auto w-[120px]", draggable: false }), _jsx(Suspense, { children: _jsx(ForgotPasswordForm, {}) })] }) })] }) }));
23
+ }, lazyMount: true, unmountOnExit: true, closeOnEscape: false, closeOnInteractOutside: false, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, {}), _jsx(Dialog.Positioner, { children: Body[props.layout ?? 'default'] })] }) }));
19
24
  }
@@ -14,9 +14,9 @@ import treasureChestBg from '../../../images/chest-bg.webp';
14
14
  import star from '../../../images/star.webp';
15
15
  import treasureChest from '../../../images/treasure.webp';
16
16
  import { formatNumber } from '../../../utils/formatNumber.js';
17
- import { parseDecimal } from '../../../utils/parseDecimal.js';
17
+ import { getPercentage } from '../../../utils/getPercentage.js';
18
18
  import styles from '../Jackpots.module.css';
19
- import { CRAZYWIN_JACKPOTS_VARIATIONS } from '../utils.js';
19
+ import { CRAZYWIN_JACKPOTS_VARIATIONS, getAccumulatingJackpotDescription } from '../utils.js';
20
20
  import { useJackpotsCarouselItemContext } from './JackpotsCarouselContext.js';
21
21
  export function JackpotsCarouselItemCrazyWin({ index, }) {
22
22
  const [ref] = useIntersectionObserver({
@@ -111,19 +111,19 @@ export function JackpotsCarouselItemCrazyWin({ index, }) {
111
111
  styles['flicker-scale-fade-2'],
112
112
  'absolute right-[50%] top-[55%] h-4 w-4',
113
113
  ],
114
- ].map(([animationClass, positionClass], i) => (_jsx(Image, { src: star, alt: "star", draggable: "false", className: twMerge(animationClass, positionClass) }, i))), _jsx("div", { className: "flex h-full flex-col justify-between", children: _jsx("div", { className: "flex w-full justify-between", children: _jsx("div", { className: "flex w-full flex-col", children: _jsxs("div", { className: "relative flex w-full justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "mb-2 flex gap-1 font-medium", children: _jsxs("div", { className: twMerge('flex w-fit items-center justify-center gap-1 rounded-[10px] border border-[#82F0D0] px-[10px] py-1 text-[#82F0D0] text-xs lg:text-sm'), children: [_jsx("div", { className: twMerge('h-[6px] w-[6px] animate-color rounded-full', isPayingOut
114
+ ].map(([animationClass, positionClass], i) => (_jsx(Image, { src: star, alt: "star", draggable: "false", className: twMerge(animationClass, positionClass), unoptimized: true }, i))), _jsx("div", { className: "flex h-full flex-col justify-between", children: _jsx("div", { className: "flex w-full justify-between", children: _jsx("div", { className: "flex w-full flex-col", children: _jsxs("div", { className: "relative flex w-full justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "mb-2 flex gap-1 font-medium", children: _jsxs("div", { className: twMerge('flex w-fit items-center justify-center gap-1 rounded-[10px] border border-[#82F0D0] px-[10px] py-1 text-[#82F0D0] text-xs lg:text-sm'), children: [_jsx("div", { className: twMerge('h-[6px] w-[6px] animate-color rounded-full', isPayingOut
115
115
  ? styles['pulse-error']
116
116
  : styles['pulse-success']) }), _jsx("div", { className: twMerge('rounded text-[#CECFD2]'), children: isPayingOut ? 'Paying Out' : 'Accumulating' })] }) }), _jsx("div", { className: "mb-2 text-left font-semibold text-[18px] text-white lg:mb-0 lg:text-2xl", children: jackpot?.name }), _jsx("div", { className: `${variation.poolBg} ${variation.textColor} flex w-fit rounded-lg px-2 font-semibold text-[26px] lg:text-[36px]`, children: formatNumber(jackpotAmount, {
117
117
  currency: localeInfo.currency.code,
118
118
  minDecimalPlaces: 2,
119
119
  maxDecimalPlaces: 2,
120
- }) })] }), _jsx(Image, { width: 175, height: 175, src: treasureChest, alt: "treasure chest", className: twMerge('absolute top-[0px] right-[-3px] h-[124px] w-[124px] md:top-0 lg:top-[-30px] lg:h-[175px] lg:w-[175px]'), priority: false, loading: "lazy" })] }) }) }) }), _jsxs("div", { className: "mt-3 lg:mt-4", children: [_jsxs("div", { className: "mb-1 flex justify-between", children: [_jsx("div", { className: "font-semibold text-text-primary-900 text-xs", "aria-live": "polite", children: formatNumber(0, {
120
+ }) })] }), _jsx(Image, { width: 175, height: 175, src: treasureChest, alt: "treasure chest", className: twMerge('absolute top-[0px] right-[-3px] h-[124px] w-[124px] md:top-0 lg:top-[-30px] lg:h-[175px] lg:w-[175px]'), priority: false, loading: "lazy", unoptimized: true })] }) }) }) }), _jsxs("div", { className: "mt-3 lg:mt-4", children: [_jsxs("div", { className: "mb-1 flex justify-between", children: [_jsx("div", { className: "font-semibold text-text-primary-900 text-xs", "aria-live": "polite", children: formatNumber(0, {
121
121
  currency: localeInfo.currency.code,
122
122
  compact: true,
123
123
  }) }), _jsxs("div", { className: "relative flex items-center justify-end gap-1.5", children: [isPayingOut ? (_jsx("div", { className: "flex w-6 items-center", children: [0, 1.5, 3].map((left, i) => (_jsx("div", { className: twMerge(`absolute left-${left}`, styles[`animate-arrow-red-flash-${i + 1}`]), children: _jsx(ChevronLeftIcon, { className: "size-4.5" }) }, i))) })) : (_jsx("div", { className: "flex w-6 items-center", children: [0, 1.5, 3].map((left, i) => (_jsx("div", { className: twMerge(`absolute left-${left}`, styles[`animate-arrow-green-flash-${i + 1}`]), children: _jsx(ChevronRightIcon, { className: "size-4.5" }) }, i))) })), _jsx("div", { className: "font-semibold text-text-primary-900 text-xs", children: formatNumber(jackpot?.maximumJackpotPoolLimit, {
124
124
  currency: localeInfo.currency.code,
125
125
  compact: true,
126
- }) })] })] }), _jsx(Progress.Root, { className: "h-2 w-full rounded-full bg-bg-primary lg:h-4", max: 100, value: getPercentage(jackpot.pool, jackpot.maximumJackpotPoolLimit), "aria-valuenow": getPercentage(jackpot.pool, jackpot.maximumJackpotPoolLimit), "aria-valuemax": 100, "aria-label": "Jackpot progress", children: _jsx(Progress.Track, { className: twMerge('h-full overflow-hidden rounded-full', variation.progressBg), children: _jsx(Progress.Range, { className: "relative h-full overflow-hidden rounded-full bg-brand-500 pl-1.5", children: _jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-start pl-1.5", "aria-hidden": "true", children: arrowImages }) }) }) }), _jsx("div", { className: "mt-2 h-2 text-left text-[#F5F5F6] text-xs lg:h-auto lg:text-sm", dangerouslySetInnerHTML: { __html: getInfoBlocks()[infoIndex] } }, infoIndex)] })] }), isPayingOut ? (_jsx("div", { className: twMerge(styles['light-rays'], variation.raysColor, 'rounded-t-2xl [--light-rays-left:90%] [--light-rays-top:100px]') })) : (_jsx(Image, { width: 175, height: 175, src: treasureChestBg, alt: "treasure chest background", className: twMerge('absolute top-0 right-0 h-full w-[380px] object-cover opacity-50'), priority: false, loading: "lazy" }))] }), _jsxs("div", { className: "relative flex h-[56px] min-h-[40px] w-full flex-1 items-center justify-between rounded-b-2xl bg-[#171b26] px-4 py-[10px]", children: [showSeeDetailsButton ? (_jsxs("button", { type: "button", className: "flex items-center gap-1 font-medium text-[#fff] text-sm", children: ["See details", _jsx(ArrowNarrowUpRightIcon, { className: "h-5 w-5" })] })) : (_jsxs("div", { className: "w-full text-white text-xs opacity-100 transition-opacity duration-500 ease-in-out", children: [_jsxs("div", { children: ["Minimum bet:", ' ', _jsxs("span", { className: "font-semibold text-[#FFE5AF]", children: ["PHP", ' ', formatNumber(jackpot.minimumBet, {
126
+ }) })] })] }), _jsx(Progress.Root, { className: "h-2 w-full rounded-full bg-bg-primary lg:h-4", max: 100, value: getPercentage(jackpot.pool, jackpot.maximumJackpotPoolLimit), "aria-valuenow": getPercentage(jackpot.pool, jackpot.maximumJackpotPoolLimit), "aria-valuemax": 100, "aria-label": "Jackpot progress", children: _jsx(Progress.Track, { className: twMerge('h-full overflow-hidden rounded-full', variation.progressBg), children: _jsx(Progress.Range, { className: "relative h-full overflow-hidden rounded-full bg-brand-500 pl-1.5", children: _jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-start pl-1.5", "aria-hidden": "true", children: arrowImages }) }) }) }), _jsx("div", { className: "mt-2 h-2 text-left text-[#F5F5F6] text-xs lg:h-auto lg:text-sm", dangerouslySetInnerHTML: { __html: getInfoBlocks()[infoIndex] } }, infoIndex)] })] }), isPayingOut ? (_jsx("div", { className: twMerge(styles['light-rays'], variation.raysColor, 'rounded-t-2xl [--light-rays-left:90%] [--light-rays-top:100px]') })) : (_jsx(Image, { width: 175, height: 175, src: treasureChestBg, alt: "treasure chest background", className: twMerge('absolute top-0 right-0 h-full w-[380px] object-cover opacity-50'), priority: false, loading: "lazy", unoptimized: true }))] }), _jsxs("div", { className: "relative flex h-[56px] min-h-[40px] w-full flex-1 items-center justify-between rounded-b-2xl bg-[#171b26] px-4 py-[10px]", children: [showSeeDetailsButton ? (_jsxs("button", { type: "button", className: "flex items-center gap-1 font-medium text-[#fff] text-sm", children: ["See details", _jsx(ArrowNarrowUpRightIcon, { className: "h-5 w-5" })] })) : (_jsxs("div", { className: "w-full text-white text-xs opacity-100 transition-opacity duration-500 ease-in-out", children: [_jsxs("div", { children: ["Minimum bet:", ' ', _jsxs("span", { className: "font-semibold text-[#FFE5AF]", children: ["PHP", ' ', formatNumber(jackpot.minimumBet, {
127
127
  currency: localeInfo.currency.code,
128
128
  minDecimalPlaces: 2,
129
129
  maxDecimalPlaces: 2,
@@ -131,14 +131,3 @@ export function JackpotsCarouselItemCrazyWin({ index, }) {
131
131
  ? `${jackpot.minimumMultiplier}X or more`
132
132
  : 'N/A' })] })] })), _jsx("button", { type: "button", className: "text-nowrap text-[#FFE5AF] text-sm underline underline-offset-4", children: "Jackpot Rules" })] })] }));
133
133
  }
134
- const getAccumulatingJackpotDescription = (part, total) => {
135
- const percentage = total === 0 ? 0 : (part / total) * 100;
136
- return percentage <= 90
137
- ? 'The jackpot is heating up! Keep playing to stay in the action and watch it grow!'
138
- : '🔥 It’s about to pop! Stay in the game for your shot at the prize!';
139
- };
140
- function getPercentage(value, total) {
141
- const v = parseDecimal(value, 0);
142
- const t = parseDecimal(total, 0);
143
- return t === 0 ? 0 : (v / t) * 100;
144
- }
@@ -6,4 +6,3 @@ export interface JackpotsCarouselItemHappyBingoProps {
6
6
  viewAllUrl?: string;
7
7
  }
8
8
  export declare function JackpotsCarouselItemHappyBingo({ index, }: JackpotsCarouselItemHappyBingoProps): import("react/jsx-runtime").JSX.Element | null;
9
- export declare const getAccumulatingJackpotDescription: (part: number, total: number) => string;
@@ -19,7 +19,7 @@ import treasureChest from '../../../images/treasure.webp';
19
19
  import { formatNumber } from '../../../utils/formatNumber.js';
20
20
  import { getPercentage } from '../../../utils/getPercentage.js';
21
21
  import styles from '../Jackpots.module.css';
22
- import { HAPPYBINGO_JACKPOTS_VARIATIONS, maskName } from '../utils.js';
22
+ import { getAccumulatingJackpotDescription, HAPPYBINGO_JACKPOTS_VARIATIONS, maskName } from '../utils.js';
23
23
  import { useJackpotsCarouselItemContext } from './JackpotsCarouselContext.js';
24
24
  export function JackpotsCarouselItemHappyBingo({ index, }) {
25
25
  // 1. Hooks (Context, Data, State, Refs)
@@ -144,7 +144,7 @@ export function JackpotsCarouselItemHappyBingo({ index, }) {
144
144
  currency: localeInfo.currency.code,
145
145
  minDecimalPlaces: 2,
146
146
  maxDecimalPlaces: 2,
147
- }) })] })] })] })) : (_jsxs("div", { className: "flex h-full w-full flex-row-reverse items-center justify-between", children: [_jsx(Image, { src: coins, alt: "coins", className: "ml-2", unoptimized: true }), _jsxs("div", { children: [_jsx("p", { className: "mt-1 font-semibold text-lg leading-6", children: "No one has won big yet" }), _jsxs("p", { className: "mt-1 text-[0.75rem] leading-[1.125rem]", children: ["You could be the first to win the ", _jsx("br", {}), " jackpot!"] })] })] })) })] }), isPayingOut ? (_jsx("div", { className: twMerge(styles['light-rays'], variation.raysColor, 'rounded-t-2xl [--light-rays-left:90%] [--light-rays-top:100px]') })) : (_jsx(Image, { width: 175, height: 175, src: treasureChestBg, alt: "treasure chest background", className: twMerge('absolute top-0 right-0 h-full w-[380px] object-cover opacity-50'), priority: false, loading: "lazy", unoptimized: true }))] }), _jsxs("div", { className: "relative flex h-[56px] min-h-[40px] w-full flex-1 items-center justify-between rounded-b-2xl bg-white px-4 py-[10px] text-[#475467] dark:bg-[#161B26] dark:text-[#94969C]", children: [showSeeDetailsButton ? (_jsxs("button", { type: "button", className: "] flex items-center gap-1 font-medium text-sm", children: ["See details", _jsx(ArrowNarrowUpRightIcon, { className: "h-5 w-5" })] })) : (_jsxs("div", { className: "w-full text-xs transition-opacity duration-500 ease-in-out", children: [_jsxs("div", { children: ["Minimum bet:", ' ', _jsxs("span", { className: "font-semibold text-[#A15C07] dark:text-[#EAAA08]", children: ["PHP", ' ', formatNumber(jackpot.minimumBet, {
147
+ }) })] })] })] })) : (_jsxs("div", { className: "flex h-full w-full flex-row-reverse items-center justify-between", children: [_jsx(Image, { src: coins, alt: "coins", className: "ml-2", unoptimized: true }), _jsxs("div", { children: [_jsx("p", { className: "mt-1 font-semibold text-lg leading-6", children: "No one has won big yet" }), _jsxs("p", { className: "mt-1 text-[0.75rem] leading-[1.125rem]", children: ["You could be the first to win the ", _jsx("br", {}), " jackpot!"] })] })] })) })] }), isPayingOut ? (_jsx("div", { className: twMerge(styles['light-rays'], variation.raysColor, 'rounded-t-2xl [--light-rays-left:90%] [--light-rays-top:100px]') })) : (_jsx(Image, { width: 175, height: 175, src: treasureChestBg, alt: "treasure chest background", className: twMerge('absolute top-0 right-0 h-full w-[380px] object-cover opacity-50'), priority: false, loading: "lazy", unoptimized: true }))] }), _jsxs("div", { className: "relative flex h-[56px] min-h-[40px] w-full flex-1 items-center justify-between rounded-b-2xl bg-white px-4 py-[10px] text-[#475467] dark:bg-[#161B26] dark:text-[#94969C]", children: [showSeeDetailsButton ? (_jsxs("button", { type: "button", className: 'flex items-center gap-1 font-medium text-sm', children: ["See details", _jsx(ArrowNarrowUpRightIcon, { className: "h-5 w-5" })] })) : (_jsxs("div", { className: "w-full text-xs transition-opacity duration-500 ease-in-out", children: [_jsxs("div", { children: ["Minimum bet:", ' ', _jsxs("span", { className: "font-semibold text-[#A15C07] dark:text-[#EAAA08]", children: ["PHP", ' ', formatNumber(jackpot.minimumBet, {
148
148
  currency: localeInfo.currency.code,
149
149
  minDecimalPlaces: 2,
150
150
  maxDecimalPlaces: 2,
@@ -152,9 +152,3 @@ export function JackpotsCarouselItemHappyBingo({ index, }) {
152
152
  ? `${jackpot.minimumMultiplier}X or more`
153
153
  : 'N/A' })] })] })), _jsx("button", { type: "button", className: "inline-flex h-9 items-center justify-center gap-1.5 text-nowrap rounded-lg border border-[#EAAA08] bg-white px-4 py-2.5 font-semibold text-[#A15C07] text-sm text-sm shadow-xs transition-colors duration-200 hover:border-[#FDE272] hover:bg-[#FEFBE8] disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:border-[#EAAA08] disabled:hover:bg-white dark:border-[#333741] dark:bg-[#161B26] dark:text-[#CECFD2] dark:disabled:hover:border-[#333741] dark:disabled:hover:bg-[#161B26]", children: "Jackpot Rules" })] })] }));
154
154
  }
155
- export const getAccumulatingJackpotDescription = (part, total) => {
156
- const percentage = total === 0 ? 0 : (part / total) * 100;
157
- return percentage <= 90
158
- ? 'The jackpot is heating up! Keep playing to stay in the action and watch it grow!'
159
- : '🔥 It’s about to pop! Stay in the game for your shot at the prize!';
160
- };
@@ -10,6 +10,7 @@ import { isStyleEntries } from '../../../utils/isStyleEntries.js';
10
10
  import { JackpotsListNext } from '../JackpotsListNext/JackpotsList.js';
11
11
  import { JackpotsListItemContext, JackpotsListPropsContext, } from './JackpotsListContext.js';
12
12
  import { JackpotsListItemCrazyWin } from './JackpotsListItem.CrazyWin.js';
13
+ import { JackpotsListItemHappyBingo } from './JackpotsListItem.HappyBingo.js';
13
14
  import { JackpotsListItemDesktop } from './JackpotsListItemDesktop.js';
14
15
  import { JackpotsListItemMobile } from './JackpotsListItemMobile.js';
15
16
  export function JackpotsList(props) {
@@ -44,5 +45,5 @@ export function JackpotsList(props) {
44
45
  future.enabled) {
45
46
  return _jsx(JackpotsListNext, { ...props });
46
47
  }
47
- return (_jsx(JackpotsListPropsContext, { value: props, children: _jsxs("div", { ref: ref, style: styles.root, className: classNames.root, children: [_jsx("div", { className: "mb-3 font-semibold text-lg lg:mb-4.5", children: props.heading ?? 'Jackpots' }), jackpots.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "hidden flex-col gap-6 lg:flex", children: jackpots.map((jackpot, index) => (_jsx(JackpotsListItemContext, { value: jackpot, children: props.variant === 'crazywin' ? (_jsx(JackpotsListItemCrazyWin, { index: index, className: classNames })) : (_jsx(JackpotsListItemDesktop, { style: styles.itemRoot, className: classNames, animate: props.animate, customJackpotChestImage: props.customJackpotChestImage, jackpotProfileShape: props.jackpotProfileShape, chestImagesByTier: props.chestImagesByTier })) }, index))) }), _jsx("div", { className: "flex flex-col gap-6 lg:hidden", children: jackpots.map((jackpot, index) => (_jsx(JackpotsListItemContext, { value: jackpot, children: props.variant === 'crazywin' ? (_jsx(JackpotsListItemCrazyWin, { index: index, className: classNames })) : (_jsx(JackpotsListItemMobile, { style: styles.itemRoot, className: classNames, animate: props.animate, customJackpotChestImage: props.customJackpotChestImage, jackpotProfileShape: props.jackpotProfileShape, chestImagesByTier: props.chestImagesByTier })) }, index))) })] })) : (_jsxs("div", { className: "mt-5 flex h-fit flex-col items-center justify-center lg:mt-0 lg:h-62", children: [_jsx(Image, { width: 100, height: 100, src: closeChest, alt: "closeChest", className: "size-full h-29.5 w-29.5 mix-blend-luminosity lg:h-25 lg:w-25" }), _jsx("div", { className: "mt-4 font-semibold text-base text-text-primary-900", children: "No Jackpots" }), _jsxs("div", { className: "mt-1 text-center text-sm text-text-tertiary-600", children: ["No jackpots are running at the moment. ", _jsx("br", {}), "Please check back later!"] })] }))] }) }));
48
+ return (_jsx(JackpotsListPropsContext, { value: props, children: _jsxs("div", { ref: ref, style: styles.root, className: classNames.root, children: [_jsx("div", { className: "mb-3 font-semibold text-lg lg:mb-4.5", children: props.heading ?? 'Jackpots' }), jackpots.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "hidden flex-col gap-6 lg:flex", children: jackpots.map((jackpot, index) => (_jsx(JackpotsListItemContext, { value: jackpot, children: props.variant === 'crazywin' ? (_jsx(JackpotsListItemCrazyWin, { index: index, className: classNames })) : props.variant === 'happybingo' ? (_jsx(JackpotsListItemHappyBingo, { index: index, className: classNames })) : (_jsx(JackpotsListItemDesktop, { style: styles.itemRoot, className: classNames, animate: props.animate, customJackpotChestImage: props.customJackpotChestImage, jackpotProfileShape: props.jackpotProfileShape, chestImagesByTier: props.chestImagesByTier })) }, index))) }), _jsx("div", { className: "flex flex-col gap-6 lg:hidden", children: jackpots.map((jackpot, index) => (_jsx(JackpotsListItemContext, { value: jackpot, children: props.variant === 'crazywin' ? (_jsx(JackpotsListItemCrazyWin, { index: index, className: classNames })) : props.variant === 'happybingo' ? (_jsx(JackpotsListItemHappyBingo, { index: index, className: classNames })) : (_jsx(JackpotsListItemMobile, { style: styles.itemRoot, className: classNames, animate: props.animate, customJackpotChestImage: props.customJackpotChestImage, jackpotProfileShape: props.jackpotProfileShape, chestImagesByTier: props.chestImagesByTier })) }, index))) })] })) : (_jsxs("div", { className: "mt-5 flex h-fit flex-col items-center justify-center lg:mt-0 lg:h-62", children: [_jsx(Image, { width: 100, height: 100, src: closeChest, alt: "closeChest", className: "size-full h-29.5 w-29.5 mix-blend-luminosity lg:h-25 lg:w-25" }), _jsx("div", { className: "mt-4 font-semibold text-base text-text-primary-900", children: "No Jackpots" }), _jsxs("div", { className: "mt-1 text-center text-sm text-text-tertiary-600", children: ["No jackpots are running at the moment. ", _jsx("br", {}), "Please check back later!"] })] }))] }) }));
48
49
  }
@@ -22,7 +22,7 @@ import treasureChest from '../../../images/treasure.webp';
22
22
  import { formatNumber } from '../../../utils/formatNumber.js';
23
23
  import { getPercentage } from '../../../utils/getPercentage.js';
24
24
  import styles from '../Jackpots.module.css';
25
- import { CRAZYWIN_JACKPOTS_VARIATIONS, maskName } from '../utils.js';
25
+ import { CRAZYWIN_JACKPOTS_VARIATIONS, formatProviderName, maskName } from '../utils.js';
26
26
  import { useJackpotsListItemContext } from './JackpotsListContext.js';
27
27
  import { JackpotsListItemGameProviders } from './JackpotsListItemGameProviders.js';
28
28
  import { useJackpotsListItemData } from './useJackpotsListItemData.js';
@@ -133,23 +133,23 @@ export function JackpotsListItemCrazyWin({ index, }) {
133
133
  styles['flicker-scale-fade-2'],
134
134
  'absolute right-[50%] top-[55%] h-4 w-4',
135
135
  ],
136
- ].map(([animationClass, positionClass], i) => (_jsx(Image, { src: star, alt: "star", draggable: "false", className: twMerge(animationClass, positionClass) }, i))), _jsx("div", { className: "flex h-full flex-col justify-between", children: _jsx("div", { className: "flex w-full justify-between", children: _jsx("div", { className: "flex w-full flex-col", children: _jsxs("div", { className: "relative flex w-full justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "mb-2 flex gap-1 font-medium", children: _jsxs("div", { className: twMerge('flex w-fit items-center justify-center gap-1 rounded-[10px] border border-[#82F0D0] px-[10px] py-1 text-[#82F0D0] text-xs lg:text-sm'), children: [_jsx("div", { className: twMerge('h-[6px] w-[6px] animate-color rounded-full', isPayingOut
136
+ ].map(([animationClass, positionClass], i) => (_jsx(Image, { src: star, alt: "star", draggable: "false", className: twMerge(animationClass, positionClass), unoptimized: true }, i))), _jsx("div", { className: "flex h-full flex-col justify-between", children: _jsx("div", { className: "flex w-full justify-between", children: _jsx("div", { className: "flex w-full flex-col", children: _jsxs("div", { className: "relative flex w-full justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "mb-2 flex gap-1 font-medium", children: _jsxs("div", { className: twMerge('flex w-fit items-center justify-center gap-1 rounded-[10px] border border-[#82F0D0] px-[10px] py-1 text-[#82F0D0] text-xs lg:text-sm'), children: [_jsx("div", { className: twMerge('h-[6px] w-[6px] animate-color rounded-full', isPayingOut
137
137
  ? styles['pulse-error']
138
138
  : styles['pulse-success']) }), _jsx("div", { className: twMerge('rounded text-[#CECFD2]'), children: isPayingOut ? 'Paying Out' : 'Accumulating' })] }) }), _jsx("div", { className: "mb-2 text-left font-semibold text-[18px] text-white lg:mb-0 lg:text-2xl", children: jackpot?.name }), _jsx("div", { className: `${variation.poolBg} ${variation.textColor} flex w-fit rounded-lg px-2 font-semibold text-[26px] lg:text-[36px]`, children: formatNumber(jackpotAmount, {
139
139
  currency: localeInfo.currency.code,
140
140
  minDecimalPlaces: 2,
141
141
  maxDecimalPlaces: 2,
142
- }) })] }), _jsx(Image, { width: 175, height: 175, src: treasureChest, alt: "treasure chest", className: twMerge('absolute top-[0px] right-[-3px] h-[124px] w-[124px] md:top-0 lg:top-[-30px] lg:h-[175px] lg:w-[175px]'), priority: false, loading: "lazy" })] }) }) }) }), _jsxs("div", { className: "mt-3 lg:mt-4", children: [_jsxs("div", { className: "mb-1 flex justify-between", children: [_jsx("div", { className: "font-semibold text-text-primary-900 text-xs", "aria-live": "polite", children: formatNumber(0, {
142
+ }) })] }), _jsx(Image, { width: 175, height: 175, src: treasureChest, alt: "treasure chest", className: twMerge('absolute top-[0px] right-[-3px] h-[124px] w-[124px] md:top-0 lg:top-[-30px] lg:h-[175px] lg:w-[175px]'), priority: false, loading: "lazy", unoptimized: true })] }) }) }) }), _jsxs("div", { className: "mt-3 lg:mt-4", children: [_jsxs("div", { className: "mb-1 flex justify-between", children: [_jsx("div", { className: "font-semibold text-text-primary-900 text-xs", "aria-live": "polite", children: formatNumber(0, {
143
143
  currency: localeInfo.currency.code,
144
144
  compact: true,
145
145
  }) }), _jsxs("div", { className: "relative flex items-center justify-end gap-1.5", children: [isPayingOut ? (_jsx("div", { className: "flex w-6 items-center", children: [0, 1.5, 3].map((left, i) => (_jsx("div", { className: twMerge(`absolute left-${left}`, styles[`animate-arrow-red-flash-${i + 1}`]), children: _jsx(ChevronLeftIcon, { className: "size-4.5" }) }, i))) })) : (_jsx("div", { className: "flex w-6 items-center", children: [0, 1.5, 3].map((left, i) => (_jsx("div", { className: twMerge(`absolute left-${left}`, styles[`animate-arrow-green-flash-${i + 1}`]), children: _jsx(ChevronRightIcon, { className: "size-4.5" }) }, i))) })), _jsx("div", { className: "font-semibold text-text-primary-900 text-xs", children: formatNumber(jackpot?.maximumJackpotPoolLimit, {
146
146
  currency: localeInfo.currency.code,
147
147
  compact: true,
148
- }) })] })] }), _jsx(Progress.Root, { className: "h-2 w-full rounded-full bg-bg-primary lg:h-4", max: 100, value: getPercentage(jackpot.pool, jackpot.maximumJackpotPoolLimit), "aria-valuenow": getPercentage(jackpot.pool, jackpot.maximumJackpotPoolLimit), "aria-valuemax": 100, "aria-label": "Jackpot progress", children: _jsx(Progress.Track, { className: twMerge('h-full overflow-hidden rounded-full', variation.progressBg), children: _jsx(Progress.Range, { className: "relative h-full overflow-hidden rounded-full bg-brand-500 pl-1.5", children: _jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-start pl-1.5", "aria-hidden": "true", children: arrowImages }) }) }) }), _jsx("div", { className: "mt-2 h-2 text-left text-[#F5F5F6] text-xs lg:h-auto lg:text-sm", dangerouslySetInnerHTML: { __html: getInfoBlocks()[infoIndex] } }, infoIndex)] })] }), _jsx("div", { className: "flex items-start gap-5 text-white", children: jackpotPayouts.length ? (_jsxs("div", { className: "flex h-full w-full flex-row items-center justify-between gap-3 lg:w-[280px] lg:flex-col lg:justify-center", children: [_jsx("p", { className: "hidden font-bold text-lg lg:block", children: "Recent Payout \uD83C\uDF89" }), _jsxs("div", { children: [_jsx("p", { className: "mb-1 block font-bold text-[14px] lg:hidden lg:text-lg", children: "Recent Payout \uD83C\uDF89" }), _jsxs("p", { className: "block text-xs leading-[18px] tracking-wider lg:hidden", children: ["Massive payout unlocked! ", _jsx("br", {}), " Who's next? \uD83D\uDCB0"] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("div", { className: `${variation.topPayoutImgBorderColor} relative flex h-[54px] w-[54px] items-center justify-center rounded-full object-contain p-[3.5px] lg:h-[74px] lg:w-[74px]`, children: [_jsx("div", { className: `flex h-full w-full items-center justify-center rounded-full ${variation.topPayoutImgBg}`, children: _jsx(User02Icon, { className: "h-[34px] w-auto lg:h-[44px]" }) }), _jsx("div", { className: `${variation.topPayoutImgBorderColor} absolute right-[-6px] bottom-[-5px] flex h-8 w-8 items-center justify-center rounded-full p-[2px] lg:right-0 lg:bottom-0`, children: _jsxs("div", { className: `flex h-full w-full items-center justify-center rounded-full font-bold text-[10px] ${variation.topPayoutImgBorderColor} ${variation.textColor} ${variation.multiplierBg} ${variation.multiplierColor}`, children: [jackpotPayouts[0].multiplier, "x"] }) })] }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold text-2xl", children: maskName(jackpotPayouts[0].member.name) }), _jsx("p", { className: `${variation.poolBg} rounded-lg px-2 font-semibold text-[22px] ${variation.textColor}`, children: formatNumber(jackpotPayouts[0].amount, {
148
+ }) })] })] }), _jsx(Progress.Root, { className: "h-2 w-full rounded-full bg-bg-primary lg:h-4", max: 100, value: getPercentage(jackpot.pool, jackpot.maximumJackpotPoolLimit), "aria-valuenow": getPercentage(jackpot.pool, jackpot.maximumJackpotPoolLimit), "aria-valuemax": 100, "aria-label": "Jackpot progress", children: _jsx(Progress.Track, { className: twMerge('h-full overflow-hidden rounded-full', variation.progressBg), children: _jsx(Progress.Range, { className: "relative h-full overflow-hidden rounded-full bg-brand-500 pl-1.5", children: _jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-start pl-1.5", "aria-hidden": "true", children: arrowImages }) }) }) }), _jsx("div", { className: "mt-2 h-2 text-left text-[#F5F5F6] text-xs lg:h-auto lg:text-sm", dangerouslySetInnerHTML: { __html: getInfoBlocks()[infoIndex] } }, infoIndex)] })] }), _jsx("div", { className: "z-1 flex items-start gap-5 text-white", children: jackpotPayouts.length ? (_jsxs("div", { className: "flex h-full w-full flex-row items-center justify-between gap-3 lg:w-[280px] lg:flex-col lg:justify-center", children: [_jsx("p", { className: "hidden font-bold text-lg lg:block", children: "Recent Payout \uD83C\uDF89" }), _jsxs("div", { children: [_jsx("p", { className: "mb-1 block font-bold text-[14px] lg:hidden lg:text-lg", children: "Recent Payout \uD83C\uDF89" }), _jsxs("p", { className: "block text-xs leading-[18px] tracking-wider lg:hidden", children: ["Massive payout unlocked! ", _jsx("br", {}), " Who's next? \uD83D\uDCB0"] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("div", { className: `${variation.topPayoutImgBorderColor} relative flex h-[54px] w-[54px] items-center justify-center rounded-full object-contain p-[3.5px] lg:h-[74px] lg:w-[74px]`, children: [_jsx("div", { className: `flex h-full w-full items-center justify-center rounded-full ${variation.topPayoutImgBg}`, children: _jsx(User02Icon, { className: "h-[34px] w-auto lg:h-[44px]" }) }), _jsx("div", { className: `${variation.topPayoutImgBorderColor} absolute right-[-6px] bottom-[-5px] flex h-8 w-8 items-center justify-center rounded-full p-[2px] lg:right-0 lg:bottom-0`, children: _jsxs("div", { className: `flex h-full w-full items-center justify-center rounded-full font-bold text-[10px] ${variation.topPayoutImgBorderColor} ${variation.textColor} ${variation.multiplierBg} ${variation.multiplierColor}`, children: [jackpotPayouts[0].multiplier, "x"] }) })] }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold text-2xl", children: maskName(jackpotPayouts[0].member.name) }), _jsx("p", { className: `${variation.poolBg} rounded-lg px-2 font-semibold text-[22px] ${variation.textColor}`, children: formatNumber(jackpotPayouts[0].amount, {
149
149
  currency: localeInfo.currency.code,
150
150
  minDecimalPlaces: 2,
151
151
  maxDecimalPlaces: 2,
152
- }) })] })] }), _jsxs("p", { className: "hidden text-center text-xs leading-[18px] tracking-wider lg:block", children: ["Massive payout unlocked! ", _jsx("br", {}), " Who's next? \uD83D\uDCB0"] })] })) : (_jsxs("div", { className: "flex h-full w-full flex-row-reverse items-center justify-between lg:w-[280px] lg:flex-col lg:justify-center", children: [_jsx(Image, { src: coins, alt: "coins", className: "ml-2" }), _jsxs("div", { children: [_jsx("p", { className: "mt-1 font-semibold text-lg leading-6", children: "No one has won big yet" }), _jsxs("p", { className: "mt-1 text-start text-[0.75rem] leading-[1.125rem] lg:text-center", children: ["You could be the first to win the ", _jsx("br", {}), " jackpot!"] })] })] })) })] }), isPayingOut ? (_jsx("div", { className: twMerge(styles['light-rays'], variation.raysColor, 'rounded-t-2xl [--light-rays-left:90%] [--light-rays-top:100px]') })) : (_jsx(Image, { width: 175, height: 175, src: treasureChestBg, alt: "treasure chest background", className: twMerge('absolute top-0 right-0 h-full w-[380px] object-cover opacity-50'), priority: false, loading: "lazy" }))] }), _jsxs("div", { className: "relative flex w-full flex-col items-center rounded-b-2xl bg-[#171b26] px-4", children: [_jsxs("div", { className: "flex w-full justify-between py-4", children: [_jsxs("button", { onClick: () => setSeeDetails((v) => !v), type: "button", className: "flex items-center gap-1 font-medium text-[#fff] text-sm", children: ["See details", ' ', seeDetails ? (_jsx(ChevronUpIcon, { className: "h-5" })) : (_jsx(ChevronDownIcon, { className: "h-5" }))] }), _jsx("button", { type: "button", className: "text-nowrap text-[#FFE5AF] text-sm underline underline-offset-4", children: "Jackpot Rules" })] }), seeDetails && (_jsxs("div", { className: "w-full", children: [_jsxs("div", { children: [_jsx("div", { className: "mt-[6px] flex justify-between text-[#CECFD2] text-lg", children: _jsxs("div", { className: "flex items-center gap-3 font-semibold", children: [_jsx(Image, { src: coin, alt: "coin", className: "h-6" }), "Recent Payouts"] }) }), _jsx("div", { className: "mt-[1.25rem] mb-[2rem] gap-[0.625rem]", children: _jsx("div", { className: "flex-1 overflow-x-auto rounded-lg border border-[#1F242F]", children: _jsxs("table", { className: "w-full min-w-[700px]", children: [_jsx("thead", { children: _jsx("tr", { className: "h-[44px] bg-[#0C111D] text-[#94969C] text-xs", children: [
152
+ }) })] })] }), _jsxs("p", { className: "hidden text-center text-xs leading-[18px] tracking-wider lg:block", children: ["Massive payout unlocked! ", _jsx("br", {}), " Who's next? \uD83D\uDCB0"] })] })) : (_jsxs("div", { className: "flex h-full w-full flex-row-reverse items-center justify-between lg:w-[280px] lg:flex-col lg:justify-center", children: [_jsx(Image, { src: coins, alt: "coins", className: "ml-2", unoptimized: true }), _jsxs("div", { children: [_jsx("p", { className: "mt-1 font-semibold text-lg leading-6", children: "No one has won big yet" }), _jsxs("p", { className: "mt-1 text-start text-[0.75rem] leading-[1.125rem] lg:text-center", children: ["You could be the first to win the ", _jsx("br", {}), " jackpot!"] })] })] })) })] }), isPayingOut ? (_jsx("div", { className: twMerge(styles['light-rays'], variation.raysColor, 'rounded-t-2xl [--light-rays-left:70%] [--light-rays-top:100px]') })) : (_jsx(Image, { width: 175, height: 175, src: treasureChestBg, alt: "treasure chest background", className: twMerge('absolute top-0 right-0 h-full w-[380px] object-cover opacity-50'), priority: false, loading: "lazy", unoptimized: true }))] }), _jsxs("div", { className: "relative flex w-full flex-col items-center rounded-b-2xl bg-[#171b26] px-4", children: [_jsxs("div", { className: "flex w-full justify-between py-4", children: [_jsxs("button", { onClick: () => setSeeDetails((v) => !v), type: "button", className: "flex items-center gap-1 font-medium text-[#fff] text-sm", children: ["See details", ' ', seeDetails ? (_jsx(ChevronUpIcon, { className: "h-5" })) : (_jsx(ChevronDownIcon, { className: "h-5" }))] }), _jsx("button", { type: "button", className: "text-nowrap text-[#FFE5AF] text-sm underline underline-offset-4", children: "Jackpot Rules" })] }), seeDetails && (_jsxs("div", { className: "w-full", children: [_jsxs("div", { children: [_jsx("div", { className: "mt-[6px] flex justify-between text-[#CECFD2] text-lg", children: _jsxs("div", { className: "flex items-center gap-3 font-semibold", children: [_jsx(Image, { src: coin, alt: "coin", className: "h-6", unoptimized: true }), "Recent Payouts"] }) }), _jsx("div", { className: "mt-[1.25rem] mb-[2rem] gap-[0.625rem]", children: _jsx("div", { className: "flex-1 overflow-x-auto rounded-lg border border-[#1F242F]", children: _jsxs("table", { className: "w-full min-w-[700px]", children: [_jsx("thead", { children: _jsx("tr", { className: "h-[44px] bg-[#0C111D] text-[#94969C] text-xs", children: [
153
153
  'Player',
154
154
  'Game Provider',
155
155
  'Multiplier',
@@ -163,11 +163,5 @@ export function JackpotsListItemCrazyWin({ index, }) {
163
163
  minDecimalPlaces: 2,
164
164
  maxDecimalPlaces: 2,
165
165
  }) }), _jsx("td", { className: "border-[#1F242F] border-b px-6 py-2", children: format(new Date(jp.dateTimeCreated), 'dd MMM yyyy h:mm a') })] }, jp.id)))
166
- : Array.from({ length: 5 }).map((_, i) => (_jsxs("tr", { className: "h-[44px] bg-[#0C111D] text-left text-[#94969C] text-sm", children: [_jsx("td", { className: "border-[#1F242F] border-b px-6 py-2", children: "-" }), _jsx("td", { className: "border-[#1F242F] border-b px-6 py-2", children: "-" }), _jsx("td", { className: "border-[#1F242F] border-b px-6 py-2", children: "-" }), _jsx("td", { className: "border-[#1F242F] border-b px-6 py-2", children: "-" }), _jsx("td", { className: "border-[#1F242F] border-b px-6 py-2", children: "-" })] }, i))) })] }) }) })] }), _jsx("div", { className: "w-full", children: Boolean(filteredGameProviders.length) && (_jsx(JackpotsListItemGameProviders, { gameProviders: filteredGameProviders, heading: _jsxs("div", { className: "flex items-center gap-3 font-semibold", children: [_jsx(Image, { src: treasureChest, alt: "treasure chest", className: "size-6" }), "Game Providers"] }) })) })] }))] })] }));
167
- }
168
- function formatProviderName(provider) {
169
- return provider
170
- .split('_')
171
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
172
- .join(' ');
166
+ : Array.from({ length: 5 }).map((_, i) => (_jsxs("tr", { className: "h-[44px] bg-[#0C111D] text-left text-[#94969C] text-sm", children: [_jsx("td", { className: "border-[#1F242F] border-b px-6 py-2", children: "-" }), _jsx("td", { className: "border-[#1F242F] border-b px-6 py-2", children: "-" }), _jsx("td", { className: "border-[#1F242F] border-b px-6 py-2", children: "-" }), _jsx("td", { className: "border-[#1F242F] border-b px-6 py-2", children: "-" }), _jsx("td", { className: "border-[#1F242F] border-b px-6 py-2", children: "-" })] }, i))) })] }) }) })] }), _jsx("div", { className: "w-full", children: Boolean(filteredGameProviders.length) && (_jsx(JackpotsListItemGameProviders, { gameProviders: filteredGameProviders, heading: _jsxs("div", { className: "flex items-center gap-3 font-semibold", children: [_jsx(Image, { src: treasureChest, alt: "treasure chest", className: "size-6", unoptimized: true }), "Game Providers"] }) })) })] }))] })] }));
173
167
  }
@@ -0,0 +1,6 @@
1
+ import type { ClassNameEntries } from './JackpotsList';
2
+ export interface JackpotsListItemDesktopHappyBingoProps {
3
+ index: number;
4
+ className?: ClassNameEntries;
5
+ }
6
+ export declare function JackpotsListItemHappyBingo({ index, }: JackpotsListItemDesktopHappyBingoProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,167 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Progress } from '@ark-ui/react/progress';
4
+ import { format } from 'date-fns';
5
+ import isMobile from 'is-mobile';
6
+ import Image from 'next/image';
7
+ import { useCallback, useEffect, useMemo, useState } from 'react';
8
+ import { twMerge } from 'tailwind-merge';
9
+ import { useIntersectionObserver } from 'usehooks-ts';
10
+ import { useJackpotPayoutsQuery } from '../../../client/hooks/useJackpotPayoutsQuery.js';
11
+ import { useLocaleInfo } from '../../../client/hooks/useLocaleInfo.js';
12
+ import { ChevronDownIcon } from '../../../icons/ChevronDownIcon.js';
13
+ import { ChevronLeftIcon } from '../../../icons/ChevronLeftIcon.js';
14
+ import { ChevronRightIcon } from '../../../icons/ChevronRightIcon.js';
15
+ import { ChevronUpIcon } from '../../../icons/ChevronUpIcon.js';
16
+ import { User02Icon } from '../../../icons/User02Icon.js';
17
+ import starTwo from '../../../images/3d-star.webp';
18
+ import treasureChestBg from '../../../images/chest-bg.webp';
19
+ import coins from '../../../images/happy-bingo-coins.webp';
20
+ import star from '../../../images/star.webp';
21
+ import treasureChest from '../../../images/treasure.webp';
22
+ import { formatNumber } from '../../../utils/formatNumber.js';
23
+ import { getPercentage } from '../../../utils/getPercentage.js';
24
+ import styles from '../Jackpots.module.css';
25
+ import { formatProviderName, HAPPYBINGO_JACKPOTS_VARIATIONS, maskName } from '../utils.js';
26
+ import { useJackpotsListItemContext } from './JackpotsListContext.js';
27
+ import { JackpotsListItemGameProviders } from './JackpotsListItemGameProviders.js';
28
+ import { useJackpotsListItemData } from './useJackpotsListItemData.js';
29
+ export function JackpotsListItemHappyBingo({ index, }) {
30
+ const jackpot = useJackpotsListItemContext();
31
+ const localeInfo = useLocaleInfo();
32
+ const { getAccumulatingJackpotDescription, filteredGameProviders } = useJackpotsListItemData();
33
+ const jackpotPayoutsQuery = useJackpotPayoutsQuery({
34
+ first: 30,
35
+ filter: {
36
+ jackpot: {
37
+ equal: jackpot.id,
38
+ },
39
+ },
40
+ });
41
+ const [ref] = useIntersectionObserver({
42
+ threshold: 0.5,
43
+ rootMargin: '50px',
44
+ });
45
+ const [infoIndex, setInfoIndex] = useState(0);
46
+ const [seeDetails, setSeeDetails] = useState(false);
47
+ const [mainTooltipOpen, setMainTooltipOpen] = useState(false);
48
+ const isPayingOut = jackpot.drawing;
49
+ const jackpotAmount = jackpot.pool;
50
+ const jackpotPayouts = jackpotPayoutsQuery.data?.pages[0].edges.map((edge) => edge.node) ?? [];
51
+ const variation = HAPPYBINGO_JACKPOTS_VARIATIONS[index % HAPPYBINGO_JACKPOTS_VARIATIONS.length];
52
+ const isMobileDevice = useMemo(() => isMobile(), []);
53
+ const getInfoBlocks = useCallback(() => {
54
+ return [
55
+ `Current Jackpot: <b>${formatNumber(jackpotAmount, {
56
+ currency: localeInfo.currency.code,
57
+ minDecimalPlaces: 2,
58
+ maxDecimalPlaces: 2,
59
+ })}</b>`,
60
+ `Minimum Payout Limit: <b>${formatNumber(jackpot.minimumJackpotPoolDrawingLimit, {
61
+ currency: localeInfo.currency.code,
62
+ minDecimalPlaces: 2,
63
+ maxDecimalPlaces: 2,
64
+ })}</b>`,
65
+ `Maximum Payout Limit: <b>${formatNumber(jackpot.maximumJackpotPoolLimit, {
66
+ currency: localeInfo.currency.code,
67
+ minDecimalPlaces: 2,
68
+ maxDecimalPlaces: 2,
69
+ })}</b>`,
70
+ isPayingOut
71
+ ? `The pot has hit <b>${formatNumber(jackpot.maximumJackpotPoolLimit, {
72
+ currency: localeInfo.currency.code,
73
+ minDecimalPlaces: 2,
74
+ maxDecimalPlaces: 2,
75
+ })}</b> Play now for your chance to win big! 🔥`
76
+ : getAccumulatingJackpotDescription(Number(jackpot.pool), Number(jackpot.maximumJackpotPoolLimit)),
77
+ ];
78
+ }, [
79
+ isPayingOut,
80
+ jackpot,
81
+ jackpotAmount,
82
+ localeInfo,
83
+ getAccumulatingJackpotDescription,
84
+ ]);
85
+ const Arrow = useCallback(({ index }) => {
86
+ const Icon = isPayingOut ? ChevronLeftIcon : ChevronRightIcon;
87
+ return (_jsx(Icon, { className: twMerge('min-w-2.5 scale-400 text-brand-300 lg:min-w-4 lg:scale-250', isPayingOut
88
+ ? styles['animate-wave-color-error']
89
+ : styles['animate-wave-color-success']), style: {
90
+ animationDelay: isPayingOut
91
+ ? `${(40 - index - 1) * 0.1}s`
92
+ : `${index * 0.1}s`,
93
+ } }));
94
+ }, [isPayingOut]);
95
+ const arrowImages = useMemo(() => Array.from({ length: 40 }, (_, i) => _jsx(Arrow, { index: i }, i)), [Arrow]);
96
+ useEffect(() => {
97
+ const interval = setInterval(() => {
98
+ setInfoIndex((i) => (i + 1) % getInfoBlocks().length);
99
+ }, 4000);
100
+ return () => clearInterval(interval);
101
+ }, [getInfoBlocks]);
102
+ useEffect(() => {
103
+ if (isMobileDevice && mainTooltipOpen) {
104
+ const timeout = setTimeout(() => setMainTooltipOpen(false), 3000);
105
+ return () => clearTimeout(timeout);
106
+ }
107
+ }, [mainTooltipOpen, isMobileDevice]);
108
+ if (jackpot.status === 'DISABLED' && jackpot.drawing !== true) {
109
+ return null;
110
+ }
111
+ return (_jsxs("div", { className: "w-full shrink-0", children: [_jsxs("div", { ref: ref, className: twMerge('relative flex w-full shrink-0 rounded-t-2xl p-3 text-center lg:gap-4 lg:p-5', variation.background), children: [_jsxs("div", { className: "flex w-full flex-col gap-6 lg:flex-row lg:gap-0", children: [_jsxs("div", { className: "relative z-1 flex flex-1 flex-col", children: [[
112
+ [
113
+ styles['flicker-scale-fade-2'],
114
+ 'absolute right-[38%] top-[2%] h-2 w-2 delay-75',
115
+ ],
116
+ [
117
+ styles['flicker-scale-fade'],
118
+ 'absolute right-[20%] top-[10%] h-3 w-3',
119
+ ],
120
+ [
121
+ styles['flicker-scale-fade-2'],
122
+ 'absolute right-[30%] top-[10%] h-5 w-5',
123
+ ],
124
+ [
125
+ styles['flicker-scale-fade'],
126
+ 'absolute right-[36%] top-[35%] h-3 w-3',
127
+ ],
128
+ [
129
+ styles['flicker-scale-fade'],
130
+ 'absolute right-[15%] top-[56%] h-3 w-3',
131
+ ],
132
+ [
133
+ styles['flicker-scale-fade-2'],
134
+ 'absolute right-[50%] top-[55%] h-4 w-4',
135
+ ],
136
+ ].map(([animationClass, positionClass], i) => (_jsx(Image, { src: star, alt: "star", draggable: "false", className: twMerge(animationClass, positionClass), unoptimized: true }, i))), _jsx("div", { className: "flex h-full flex-col justify-between", children: _jsx("div", { className: "flex w-full justify-between", children: _jsx("div", { className: "flex w-full flex-col", children: _jsxs("div", { className: "relative flex w-full justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "mb-2 flex gap-1 font-medium", children: _jsxs("div", { className: twMerge('flex w-fit items-center justify-center gap-1 rounded-[10px] border border-[#FECDCA] bg-[#FEF3F2] px-2.5 py-1 text-sm'), children: [_jsx("div", { className: twMerge('h-[6px] w-[6px] animate-color rounded-full', isPayingOut
137
+ ? styles['pulse-error']
138
+ : styles['pulse-success']) }), _jsx("div", { className: twMerge('rounded text-[#344054]'), children: isPayingOut ? 'Paying Out' : 'Accumulating' })] }) }), _jsx("div", { className: "mb-2 text-left font-semibold text-[18px] text-white lg:mb-0 lg:text-2xl", children: jackpot?.name }), _jsx("div", { className: `${variation.poolBg} ${variation.textColor} flex w-fit rounded-lg px-2 font-semibold text-[26px] lg:text-[36px]`, children: formatNumber(jackpotAmount, {
139
+ currency: localeInfo.currency.code,
140
+ minDecimalPlaces: 2,
141
+ maxDecimalPlaces: 2,
142
+ }) })] }), _jsx(Image, { width: 175, height: 175, src: treasureChest, alt: "treasure chest", className: twMerge('absolute top-[0px] right-[-3px] h-[124px] w-[124px] md:top-0 lg:top-[-30px] lg:h-[175px] lg:w-[175px]'), priority: false, loading: "lazy", unoptimized: true })] }) }) }) }), _jsxs("div", { className: "mt-3 lg:mt-4", children: [_jsxs("div", { className: "mb-1 flex justify-between", children: [_jsx("div", { className: "font-semibold text-text-primary-900 text-xs", "aria-live": "polite", children: formatNumber(0, {
143
+ currency: localeInfo.currency.code,
144
+ compact: true,
145
+ }) }), _jsxs("div", { className: "relative flex items-center justify-end gap-1.5", children: [isPayingOut ? (_jsx("div", { className: "flex w-6 items-center", children: [0, 1.5, 3].map((left, i) => (_jsx("div", { className: twMerge(`absolute left-${left}`, styles[`animate-arrow-red-flash-${i + 1}`]), children: _jsx(ChevronLeftIcon, { className: "size-4.5" }) }, i))) })) : (_jsx("div", { className: "flex w-6 items-center", children: [0, 1.5, 3].map((left, i) => (_jsx("div", { className: twMerge(`absolute left-${left}`, styles[`animate-arrow-green-flash-${i + 1}`]), children: _jsx(ChevronRightIcon, { className: "size-4.5" }) }, i))) })), _jsx("div", { className: "font-semibold text-text-primary-900 text-xs", children: formatNumber(jackpot?.maximumJackpotPoolLimit, {
146
+ currency: localeInfo.currency.code,
147
+ compact: true,
148
+ }) })] })] }), _jsx(Progress.Root, { className: "h-2 w-full rounded-full bg-bg-primary lg:h-4", max: 100, value: getPercentage(jackpot.pool, jackpot.maximumJackpotPoolLimit), "aria-valuenow": getPercentage(jackpot.pool, jackpot.maximumJackpotPoolLimit), "aria-valuemax": 100, "aria-label": "Jackpot progress", children: _jsx(Progress.Track, { className: twMerge('h-full overflow-hidden rounded-full', variation.progressBg), children: _jsx(Progress.Range, { className: "relative h-full overflow-hidden rounded-full bg-brand-500 pl-1.5", children: _jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-start pl-1.5", "aria-hidden": "true", children: arrowImages }) }) }) }), _jsx("div", { className: "mt-2 h-2 text-left text-[#F5F5F6] text-xs lg:h-auto lg:text-sm", dangerouslySetInnerHTML: { __html: getInfoBlocks()[infoIndex] } }, infoIndex)] })] }), _jsx("div", { className: "z-1 flex items-start gap-5 text-white", children: jackpotPayouts.length ? (_jsxs("div", { className: "flex h-full w-full flex-row items-center justify-between gap-3 lg:w-[280px] lg:flex-col lg:justify-center", children: [_jsx("p", { className: "hidden font-bold text-lg lg:block", children: "Recent Payout \uD83C\uDF89" }), _jsxs("div", { children: [_jsx("p", { className: "mb-1 block font-bold text-[14px] lg:hidden lg:text-lg", children: "Recent Payout \uD83C\uDF89" }), _jsxs("p", { className: "block text-xs leading-[18px] tracking-wider lg:hidden", children: ["Massive payout unlocked! ", _jsx("br", {}), " Who's next? \uD83D\uDCB0"] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("div", { className: `${variation.topPayoutImgBorderColor} relative flex h-[54px] w-[54px] items-center justify-center rounded-full object-contain p-[3.5px] lg:h-[74px] lg:w-[74px]`, children: [_jsx("div", { className: `flex h-full w-full items-center justify-center rounded-full ${variation.topPayoutImgBg}`, children: _jsx(User02Icon, { className: "h-[34px] w-auto lg:h-[44px]" }) }), _jsx("div", { className: `${variation.topPayoutImgBorderColor} absolute right-[-6px] bottom-[-5px] flex h-8 w-8 items-center justify-center rounded-full p-[2px] lg:right-0 lg:bottom-0`, children: _jsxs("div", { className: `flex h-full w-full items-center justify-center rounded-full font-bold text-[10px] ${variation.topPayoutImgBorderColor} ${variation.textColor} ${variation.multiplierBg} ${variation.multiplierColor}`, children: [jackpotPayouts[0].multiplier, "x"] }) })] }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold text-2xl", children: maskName(jackpotPayouts[0].member.name) }), _jsx("p", { className: `${variation.poolBg} rounded-lg px-2 font-semibold text-[22px] ${variation.textColor}`, children: formatNumber(jackpotPayouts[0].amount, {
149
+ currency: localeInfo.currency.code,
150
+ minDecimalPlaces: 2,
151
+ maxDecimalPlaces: 2,
152
+ }) })] })] }), _jsxs("p", { className: "hidden text-center text-xs leading-[18px] tracking-wider lg:block", children: ["Massive payout unlocked! ", _jsx("br", {}), " Who's next? \uD83D\uDCB0"] })] })) : (_jsxs("div", { className: "flex h-full w-full flex-row-reverse items-center justify-between lg:w-[280px] lg:flex-col lg:justify-center", children: [_jsx(Image, { src: coins, alt: "coins", className: "ml-2", unoptimized: true }), _jsxs("div", { children: [_jsx("p", { className: "mt-1 font-semibold text-lg leading-6", children: "No one has won big yet" }), _jsxs("p", { className: "mt-1 text-start text-[0.75rem] leading-[1.125rem] lg:text-center", children: ["You could be the first to win the ", _jsx("br", {}), " jackpot!"] })] })] })) })] }), isPayingOut ? (_jsx("div", { className: twMerge(styles['light-rays'], variation.raysColor, 'rounded-t-2xl [--light-rays-left:70%] [--light-rays-top:100px]') })) : (_jsx(Image, { width: 175, height: 175, src: treasureChestBg, alt: "treasure chest background", className: twMerge('absolute top-0 right-0 h-full w-[380px] object-cover opacity-50'), priority: false, loading: "lazy", unoptimized: true }))] }), _jsxs("div", { className: "relative flex w-full flex-col items-center rounded-b-2xl bg-white px-4 text-[#475467] dark:bg-[#161B26] dark:text-[#94969C]", children: [_jsxs("div", { className: "flex w-full justify-between py-3", children: [_jsxs("button", { onClick: () => setSeeDetails((v) => !v), type: "button", className: "flex items-center gap-1 font-medium text-sm", children: ["See details", ' ', seeDetails ? (_jsx(ChevronUpIcon, { className: "h-5" })) : (_jsx(ChevronDownIcon, { className: "h-5" }))] }), _jsx("button", { type: "button", className: "inline-flex h-9 items-center justify-center gap-1.5 text-nowrap rounded-lg border border-[#EAAA08] bg-white px-4 py-2.5 font-semibold text-[#A15C07] text-sm text-sm shadow-xs transition-colors duration-200 hover:border-[#FDE272] hover:bg-[#FEFBE8] disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:border-[#EAAA08] disabled:hover:bg-white dark:border-[#333741] dark:bg-[#161B26] dark:text-[#CECFD2] dark:disabled:hover:border-[#333741] dark:disabled:hover:bg-[#161B26]", children: "Jackpot Rules" })] }), seeDetails && (_jsxs("div", { className: "w-full", children: [_jsxs("div", { children: [_jsx("div", { className: "mt-[6px] flex justify-between text-[#344054] text-lg dark:text-[#CECFD2]", children: _jsxs("div", { className: "flex items-center gap-3 font-semibold", children: [_jsx(Image, { src: starTwo, alt: "3d star", className: "size-6", unoptimized: true }), "Recent Payouts"] }) }), _jsx("div", { className: "mt-[1.25rem] mb-[2rem] gap-[0.625rem]", children: _jsx("div", { className: "w-full max-w-full overflow-x-auto overflow-y-hidden whitespace-nowrap rounded-xl border border-[#eaecf0] dark:border-[#1f242f]", children: _jsxs("table", { className: "w-full min-w-[700px]", children: [_jsx("thead", { className: "border-[#EAECF0] border-b dark:border-[#1F242F]", children: _jsx("tr", { className: "border-[#EAECF0] border-b bg-white px-0 last:border-b-0 odd:bg-[#F9FAFB] dark:border-[#1F242F] dark:bg-[#0C111D] dark:odd:bg-[#0C111D]", children: [
153
+ 'Player',
154
+ 'Game Provider',
155
+ 'Multiplier',
156
+ 'Prize',
157
+ 'Timestamp',
158
+ ].map((label) => (_jsx("th", { className: "bg-white px-3xl py-lg text-left font-medium text-[#475467] text-xs dark:bg-[#0C111D] dark:text-[#94969C]", children: label }, label))) }) }), _jsx("tbody", { children: jackpotPayouts.length
159
+ ? jackpotPayouts
160
+ .filter((jp) => jp.id !== '5HMmGqAZDPqqeFHBmv')
161
+ .map((jp) => (_jsxs("tr", { className: "border-[#EAECF0] border-b bg-white last:border-b-0 odd:bg-[#F9FAFB] dark:border-[#1F242F] dark:bg-[#0C111D] dark:odd:bg-[#0C111D]", children: [_jsx("td", { className: "px-3xl py-xl text-left text-[#475467] text-sm dark:text-[#94969C]", children: maskName(jp?.member?.name) }), _jsx("td", { className: "px-3xl py-xl text-left text-[#475467] text-sm dark:text-[#94969C]", children: formatProviderName(jp?.game.provider ?? '-') }), _jsxs("td", { className: "px-3xl py-xl text-left text-[#475467] text-sm dark:text-[#94969C]", children: [jp?.multiplier, "x"] }), _jsx("td", { className: "px-3xl py-xl text-left text-[#079455] text-sm dark:text-[#47CD89]", children: formatNumber(jp?.amount ?? 0, {
162
+ currency: localeInfo.currency.code,
163
+ minDecimalPlaces: 2,
164
+ maxDecimalPlaces: 2,
165
+ }) }), _jsx("td", { className: "px-3xl py-xl text-left text-[#475467] text-sm dark:text-[#94969C]", children: format(new Date(jp.dateTimeCreated), 'dd MMM yyyy h:mm a') })] }, jp.id)))
166
+ : Array.from({ length: 5 }).map((_, i) => (_jsxs("tr", { className: "h-[44px] bg-[#0C111D] text-left text-[#94969C] text-sm", children: [_jsx("td", { className: "px-3xl py-xl text-left text-[#475467] text-sm dark:text-[#94969C]", children: "-" }), _jsx("td", { className: "px-3xl py-xl text-left text-[#475467] text-sm dark:text-[#94969C]", children: "-" }), _jsx("td", { className: "px-3xl py-xl text-left text-[#475467] text-sm dark:text-[#94969C]", children: "-" }), _jsx("td", { className: "px-3xl py-xl text-left text-[#475467] text-sm dark:text-[#94969C]", children: "-" }), _jsx("td", { className: "px-3xl py-xl text-left text-[#475467] text-sm dark:text-[#94969C]", children: "-" })] }, i))) })] }) }) })] }), _jsx("div", { className: "w-full", children: Boolean(filteredGameProviders.length) && (_jsx(JackpotsListItemGameProviders, { gameProviders: filteredGameProviders, heading: _jsxs("div", { className: "flex items-center gap-3 font-semibold text-[#344054] dark:text-[#CECFD2]", children: [_jsx(Image, { src: treasureChest, alt: "treasure chest", className: "size-6", unoptimized: true }), "Jackpot Game Provider"] }) })) })] }))] })] }));
167
+ }
@@ -22,3 +22,4 @@ export declare const HAPPYBINGO_JACKPOTS_VARIATIONS: {
22
22
  }[];
23
23
  export declare function formatProviderName(provider: string): string;
24
24
  export declare const maskName: (name: string) => string;
25
+ export declare const getAccumulatingJackpotDescription: (part: number, total: number) => string;
@@ -88,3 +88,9 @@ export const maskName = (name) => {
88
88
  const maskedPart = '*'.repeat(7);
89
89
  return visiblePart + maskedPart;
90
90
  };
91
+ export const getAccumulatingJackpotDescription = (part, total) => {
92
+ const percentage = total === 0 ? 0 : (part / total) * 100;
93
+ return percentage <= 90
94
+ ? 'The jackpot is heating up! Keep playing to stay in the action and watch it grow!'
95
+ : '🔥 It’s about to pop! Stay in the game for your shot at the prize!';
96
+ };
@@ -2,6 +2,9 @@ import type { Cashback as TCashback } from '../../types';
2
2
  interface CashbackProps {
3
3
  data: TCashback;
4
4
  viewDetailsUrl: string;
5
+ hasPromotionPeriod?: boolean;
6
+ roundedButtons?: boolean;
7
+ textOrientation?: 'left' | 'center';
5
8
  }
6
- export declare function Cashback({ data, viewDetailsUrl }: CashbackProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function Cashback({ data, viewDetailsUrl, hasPromotionPeriod, roundedButtons, textOrientation, }: CashbackProps): import("react/jsx-runtime").JSX.Element;
7
10
  export {};
@@ -1,18 +1,21 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import Image from 'next/image';
3
3
  import Link from 'next/link';
4
+ import { twMerge } from 'tailwind-merge';
4
5
  import { useShallow } from 'zustand/shallow';
5
6
  import { useAvailablePromosQuery } from '../../client/hooks/useAvailablePromosQuery.js';
6
7
  import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
7
8
  import { Button } from '../../ui/Button/index.js';
8
- export function Cashback({ data, viewDetailsUrl }) {
9
+ import { formatPromotionPeriod } from './utils.js';
10
+ export function Cashback({ data, viewDetailsUrl, hasPromotionPeriod, roundedButtons, textOrientation = 'center', }) {
9
11
  const globalStore = useGlobalStore(useShallow((ctx) => ({
10
12
  depositWithdrawal: ctx.depositWithdrawal,
11
13
  })));
12
14
  const claimablePromos = useAvailablePromosQuery().data ?? [];
13
15
  const claimable = claimablePromos.find((availablePromo) => availablePromo.id === data.id);
14
- return (_jsxs("div", { className: "relative flex h-full flex-col overflow-hidden rounded-2xl border border-border-secondary bg-accent-50 bg-bg-primary-alt", children: [data.banner?.url && (_jsx(Image, { src: data.banner.url, alt: data.name, width: 400, height: 202, loading: "lazy", unoptimized: true, className: "block aspect-[365/180] w-full object-cover" })), _jsxs("div", { className: "flex flex-grow flex-col px-4 pt-2xl pb-3xl", children: [_jsx("div", { className: "w-full grow text-center font-semibold text-xl", children: data.name }), _jsxs("div", { className: "mt-auto flex flex-col gap-3 pt-4 lg:flex-row", children: [claimable && (_jsx(Button, { size: "sm", onClick: () => {
16
+ const promotionPeriod = formatPromotionPeriod(data.activationStartDateTime, data.activationEndDateTime);
17
+ return (_jsxs("div", { className: "relative flex h-full flex-col overflow-hidden rounded-2xl border border-border-secondary bg-accent-50 bg-bg-primary-alt", children: [data.banner?.url && (_jsx(Image, { src: data.banner.url, alt: data.name, width: 400, height: 202, loading: "lazy", unoptimized: true, className: "block aspect-[365/180] w-full object-cover" })), hasPromotionPeriod && (_jsxs("div", { className: "bg-black py-1.5 text-center font-bold text-3xs uppercase", children: ["PROMOTION PERIOD: ", promotionPeriod] })), _jsxs("div", { className: "flex flex-grow flex-col px-4 pt-2xl pb-3xl", children: [_jsx("div", { className: twMerge('w-full grow font-semibold text-xl', textOrientation === 'center' ? 'text-center' : 'text-left'), children: data.name }), _jsxs("div", { className: "mt-auto flex flex-col gap-3 pt-4 lg:flex-row", children: [claimable && (_jsx(Button, { size: "sm", onClick: () => {
15
18
  globalStore.depositWithdrawal.setOpen(true);
16
19
  globalStore.depositWithdrawal.setPromo(data.id);
17
- }, children: "Get bonus" })), _jsx(Button, { size: "sm", variant: "outline", asChild: true, children: _jsxs(Link, { href: `${viewDetailsUrl}/${data.id}`, children: ["Read more", _jsxs("span", { className: "sr-only", children: [" about ", data.name] })] }) })] })] })] }));
20
+ }, children: "Get bonus" })), _jsx(Button, { size: "sm", variant: "outline", asChild: true, className: roundedButtons ? 'rounded-full' : '', children: _jsxs(Link, { href: `${viewDetailsUrl}/${data.id}`, children: ["Read more", _jsxs("span", { className: "sr-only", children: [" about ", data.name] })] }) })] })] })] }));
18
21
  }
@@ -2,6 +2,8 @@ import type { CustomPromo as TCustomPromo } from '../../types';
2
2
  interface CustomPromoProps {
3
3
  data: TCustomPromo;
4
4
  viewDetailsUrl: string;
5
+ roundedButtons?: boolean;
6
+ textOrientation?: 'left' | 'center';
5
7
  }
6
- export declare function CustomPromo({ data, viewDetailsUrl }: CustomPromoProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function CustomPromo({ data, viewDetailsUrl, roundedButtons, textOrientation, }: CustomPromoProps): import("react/jsx-runtime").JSX.Element;
7
9
  export {};
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import Image from 'next/image';
3
3
  import Link from 'next/link';
4
+ import { twMerge } from 'tailwind-merge';
4
5
  import { Button } from '../../ui/Button/index.js';
5
- export function CustomPromo({ data, viewDetailsUrl }) {
6
- return (_jsxs("div", { className: "relative flex h-full flex-col overflow-hidden rounded-2xl border border-border-secondary bg-accent-50 bg-bg-primary-alt", children: [_jsx(Image, { src: data.banner, alt: data.name, width: 400, height: 202, loading: "lazy", unoptimized: true, className: "block aspect-[365/180] w-full object-cover" }), _jsxs("div", { className: "flex flex-grow flex-col px-4 pt-2xl pb-3xl", children: [_jsx("div", { className: "w-full grow text-center font-semibold text-xl", children: data.name }), _jsx("div", { className: "mt-auto flex flex-col gap-3 pt-4 lg:flex-row", children: _jsx(Button, { size: "sm", variant: "outline", asChild: true, children: _jsxs(Link, { href: `${viewDetailsUrl}/${data.id}`, children: ["Read more", _jsxs("span", { className: "sr-only", children: [" about ", data.name] })] }) }) })] })] }));
6
+ export function CustomPromo({ data, viewDetailsUrl, roundedButtons, textOrientation = 'center', }) {
7
+ return (_jsxs("div", { className: "relative flex h-full flex-col overflow-hidden rounded-2xl border border-border-secondary bg-accent-50 bg-bg-primary-alt", children: [_jsx(Image, { src: data.banner, alt: data.name, width: 400, height: 202, loading: "lazy", unoptimized: true, className: "block aspect-[365/180] w-full object-cover" }), _jsxs("div", { className: "flex flex-grow flex-col px-4 pt-2xl pb-3xl", children: [_jsx("div", { className: twMerge('w-full grow font-semibold text-xl', textOrientation === 'center' ? 'text-center' : 'text-left'), children: data.name }), _jsx("div", { className: "mt-auto flex flex-col gap-3 pt-4 lg:flex-row", children: _jsx(Button, { size: "sm", variant: "outline", asChild: true, className: roundedButtons ? 'rounded-full' : '', children: _jsxs(Link, { href: `${viewDetailsUrl}/${data.id}`, children: ["Read more", _jsxs("span", { className: "sr-only", children: [" about ", data.name] })] }) }) })] })] }));
7
8
  }
@@ -2,6 +2,9 @@ import type { Promo as TPromo } from '../../types';
2
2
  interface PromoProps {
3
3
  data: TPromo;
4
4
  viewDetailsUrl: string;
5
+ hasPromotionPeriod?: boolean;
6
+ roundedButtons?: boolean;
7
+ textOrientation?: 'left' | 'center';
5
8
  }
6
- export declare function Promo({ data, viewDetailsUrl }: PromoProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function Promo({ data, viewDetailsUrl, hasPromotionPeriod, roundedButtons, textOrientation, }: PromoProps): import("react/jsx-runtime").JSX.Element;
7
10
  export {};
@@ -1,18 +1,21 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import Image from 'next/image';
3
3
  import Link from 'next/link';
4
+ import { twMerge } from 'tailwind-merge';
4
5
  import { useShallow } from 'zustand/shallow';
5
6
  import { useAvailablePromosQuery } from '../../client/hooks/useAvailablePromosQuery.js';
6
7
  import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
7
8
  import { Button } from '../../ui/Button/index.js';
8
- export function Promo({ data, viewDetailsUrl }) {
9
+ import { formatPromotionPeriod } from './utils.js';
10
+ export function Promo({ data, viewDetailsUrl, hasPromotionPeriod, roundedButtons, textOrientation = 'center', }) {
9
11
  const globalStore = useGlobalStore(useShallow((ctx) => ({
10
12
  depositWithdrawal: ctx.depositWithdrawal,
11
13
  })));
12
14
  const claimablePromos = useAvailablePromosQuery().data ?? [];
13
15
  const claimable = claimablePromos.find((availablePromo) => availablePromo.id === data.id);
14
- return (_jsxs("div", { className: "relative flex h-full flex-col overflow-hidden rounded-2xl border border-border-secondary bg-accent-50 bg-bg-primary-alt", children: [data.banner?.url && (_jsx(Image, { src: data.banner.url, alt: data.name, width: 400, height: 202, loading: "lazy", unoptimized: true, className: "block aspect-[365/180] w-full object-cover" })), _jsxs("div", { className: "flex flex-grow flex-col px-4 pt-2xl pb-3xl", children: [_jsx("div", { className: "w-full grow text-center font-semibold text-xl", children: data.name }), _jsxs("div", { className: "mt-auto flex flex-col gap-3 pt-4 lg:flex-row", children: [claimable && (_jsx(Button, { size: "sm", onClick: () => {
16
+ const promotionPeriod = formatPromotionPeriod(data.activationStartDateTime, data.activationEndDateTime);
17
+ return (_jsxs("div", { className: "relative flex h-full flex-col overflow-hidden rounded-2xl border border-border-secondary bg-accent-50 bg-bg-primary-alt", children: [data.banner?.url && (_jsx(Image, { src: data.banner.url, alt: data.name, width: 400, height: 202, loading: "lazy", unoptimized: true, className: "block aspect-[365/180] w-full object-cover" })), hasPromotionPeriod && (_jsxs("div", { className: "bg-black py-1.5 text-center font-bold text-3xs uppercase", children: ["PROMOTION PERIOD: ", promotionPeriod] })), _jsxs("div", { className: "flex flex-grow flex-col px-4 pt-2xl pb-3xl", children: [_jsx("div", { className: twMerge('w-full grow font-semibold text-xl', textOrientation === 'center' ? 'text-center' : 'text-left'), children: data.name }), _jsxs("div", { className: "mt-auto flex flex-col gap-3 pt-4 lg:flex-row", children: [claimable && (_jsx(Button, { size: "sm", onClick: () => {
15
18
  globalStore.depositWithdrawal.setOpen(true);
16
19
  globalStore.depositWithdrawal.setPromo(data.id);
17
- }, children: "Get bonus" })), _jsx(Button, { size: "sm", variant: "outline", asChild: true, children: _jsxs(Link, { href: `${viewDetailsUrl}/${data.id}`, children: ["Read more", _jsxs("span", { className: "sr-only", children: [" about ", data.name] })] }) })] })] })] }));
20
+ }, children: "Get bonus" })), _jsx(Button, { size: "sm", variant: "outline", asChild: true, className: roundedButtons ? 'rounded-full' : '', children: _jsxs(Link, { href: `${viewDetailsUrl}/${data.id}`, children: ["Read more", _jsxs("span", { className: "sr-only", children: [" about ", data.name] })] }) })] })] })] }));
18
21
  }
@@ -9,6 +9,9 @@ export interface PromosGridProps {
9
9
  /** @default "/promos/cashback" */
10
10
  viewCashbackDetailsUrl?: string;
11
11
  customPromos?: TCustomPromo[];
12
+ hasPromotionPeriod?: boolean;
13
+ roundedButtons?: boolean;
14
+ textOrientation?: 'left' | 'center';
12
15
  exclude?: string[];
13
16
  className?: string;
14
17
  }
@@ -15,5 +15,5 @@ export function PromosGrid(props) {
15
15
  const cashbacks = cashbacksQuery.data?.filter((item) => !blacklist.includes(item.id)) ?? [];
16
16
  const customPromos = props.customPromos?.filter((item) => !blacklist.includes(item.id)) ?? [];
17
17
  const empty = promos.length <= 0 && cashbacks.length <= 0 && customPromos.length <= 0;
18
- return (_jsxs("div", { className: props.className, children: [_jsxs("div", { className: "flex items-center", children: [_jsx("h2", { className: "font-semibold text-lg", children: props.heading ?? 'Promos' }), _jsx("div", { className: "grow" })] }), empty && (_jsx(Empty, { icon: Gift01Icon, title: "No Promos", message: "No promo is currently available.", className: "mt-8" })), !empty && (_jsx("div", { className: "relative mt-lg lg:overflow-hidden", children: _jsxs("div", { className: "grid gap-3xl lg:grid-cols-3 lg:gap-2xl", children: [promos.map((promo) => (_jsx(Promo, { data: promo, viewDetailsUrl: props.viewPromoDetailsUrl ?? '/promos' }, promo.id))), cashbacks.map((cashback) => (_jsx(Cashback, { data: cashback, viewDetailsUrl: props.viewCashbackDetailsUrl ?? '/promos/cashback' }, cashback.id))), customPromos.map((customPromo) => (_jsx(CustomPromo, { data: customPromo, viewDetailsUrl: props.viewCashbackDetailsUrl ?? '/promos/custom' }, customPromo.id)))] }) }))] }));
18
+ return (_jsxs("div", { className: props.className, children: [_jsxs("div", { className: "flex items-center", children: [_jsx("h2", { className: "font-semibold text-lg", children: props.heading ?? 'Promos' }), _jsx("div", { className: "grow" })] }), empty && (_jsx(Empty, { icon: Gift01Icon, title: "No Promos", message: "No promo is currently available.", className: "mt-8" })), !empty && (_jsx("div", { className: "relative mt-lg lg:overflow-hidden", children: _jsxs("div", { className: "grid gap-3xl lg:grid-cols-3 lg:gap-2xl", children: [promos.map((promo) => (_jsx(Promo, { data: promo, viewDetailsUrl: props.viewPromoDetailsUrl ?? '/promos', hasPromotionPeriod: props.hasPromotionPeriod, roundedButtons: props.roundedButtons, textOrientation: props.textOrientation }, promo.id))), cashbacks.map((cashback) => (_jsx(Cashback, { data: cashback, viewDetailsUrl: props.viewCashbackDetailsUrl ?? '/promos/cashback', hasPromotionPeriod: props.hasPromotionPeriod, roundedButtons: props.roundedButtons, textOrientation: props.textOrientation }, cashback.id))), customPromos.map((customPromo) => (_jsx(CustomPromo, { data: customPromo, viewDetailsUrl: props.viewCashbackDetailsUrl ?? '/promos/custom', roundedButtons: props.roundedButtons, textOrientation: props.textOrientation }, customPromo.id)))] }) }))] }));
19
19
  }
@@ -0,0 +1 @@
1
+ export declare function formatPromotionPeriod(start: string | null | undefined, until: string | null | undefined): string | null;
@@ -0,0 +1,10 @@
1
+ import { format } from 'date-fns';
2
+ export function formatPromotionPeriod(start, until) {
3
+ if (!start)
4
+ return null;
5
+ if (!until)
6
+ return null;
7
+ const s = format(start, 'd/MM/yyyy hh:mm a');
8
+ const u = format(until, 'd/MM/yyyy hh:mm a');
9
+ return `${s} - ${u}`;
10
+ }
@@ -9,7 +9,9 @@ import { Field } from '../../ui/Field/index.js';
9
9
  import { getAllUniqueCountries, getCountryDetails, } from '../../utils/countries/getAllCountries.js';
10
10
  export const MobileNumberField = ({ enabledCountries, mobileNumber, onMobileNumberChange, setAreaCode, error, mobileNumberRegistration, }) => {
11
11
  const localeInfo = useLocaleInfo();
12
- const [selectedCountry, setSelectedCountry] = useState(getCountryDetails(localeInfo.country.code));
12
+ const [selectedCountry, setSelectedCountry] = useState(getCountryDetails(enabledCountries.includes(localeInfo.country.code)
13
+ ? localeInfo.country.code
14
+ : 'AE'));
13
15
  const [search, setSearch] = useState('');
14
16
  const [isPopoverOpen, setIsPopoverOpen] = useState(false);
15
17
  const allCountries = useMemo(() => getAllUniqueCountries(enabledCountries), [enabledCountries]);
@@ -36,7 +38,6 @@ export const MobileNumberField = ({ enabledCountries, mobileNumber, onMobileNumb
36
38
  }, className: "rounded-md border border-border-primary bg-background bg-bg-primary px-3 py-2 shadow-xs transition-colors placeholder:text-text-placeholder hover:border-border-hover focus:border-border-brand focus:border-border-focus focus:shadow-brand-xs focus:outline-none", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(selectedCountry.flag, { className: "size-5" }), _jsx("span", { children: selectedCountry.areaCode }), _jsx(Popover.Indicator, { children: _jsx(ChevronDownIcon, {}) })] }) }), _jsx(Popover.Positioner, { className: "w-full", children: _jsx(Popover.Content, { children: _jsx(Popover.Description, { children: _jsxs(Combobox.Root, { collection: countriesCollection, positioning: {
37
39
  sameWidth: true,
38
40
  }, value: [selectedCountry.code], onValueChange: (details) => {
39
- console.log('onValueChange?');
40
41
  if (details.value && details.value.length > 0) {
41
42
  setSelectedCountry(getCountryDetails(details.value[0]));
42
43
  setAreaCode(getCountryDetails(details.value[0]).areaCode);
@@ -44,20 +45,22 @@ export const MobileNumberField = ({ enabledCountries, mobileNumber, onMobileNumb
44
45
  setIsPopoverOpen(false);
45
46
  }
46
47
  }, inputValue: search, onInputValueChange: (details) => {
47
- console.log('onInputValueChange?');
48
48
  setSearch(details.inputValue);
49
49
  }, open: isPopoverOpen, onOpenChange: (details) => {
50
- console.log('onOpenChange?');
51
50
  if (isPopoverOpen && !details.open) {
52
51
  return;
53
52
  }
54
- }, openOnClick: true, children: [_jsx(Combobox.Control, { className: "rounded-lg border-1 shadow-none outline-none", children: _jsx(Combobox.Input, { placeholder: "Search country..." }) }), _jsx(Portal, { children: _jsx(Combobox.Positioner, { style: { zIndex: 9999 }, children: _jsx(Combobox.Content, { className: "w-full", style: { zIndex: 9999 }, children: _jsx(Combobox.ItemGroup, { children: countriesCollection.items
55
- .filter((country) => search === '' ||
56
- country.name
57
- .toLowerCase()
58
- .includes(search.toLowerCase()) ||
59
- country.areaCode.includes(search))
60
- .map((country) => (_jsxs(Combobox.Item, { item: country, children: [_jsxs(Combobox.ItemText, { children: [_jsx(country.flag, { className: "mr-2 inline-block size-5" }), country.name, " (", country.areaCode, ")"] }), _jsx(Combobox.ItemIndicator, { asChild: true, children: _jsx(CheckIcon, {}) })] }, country.code))) }) }) }) })] }) }) }) })] }), _jsx(Field.Input, { ...(mobileNumberRegistration || {}), style: { paddingLeft: '0.5rem' }, value: mobileNumber, onChange: handleMobileChange, placeholder: "Enter mobile number" })] }), _jsx(Field.ErrorText, { children: error })] }));
53
+ }, openOnClick: true, children: [_jsx(Combobox.Control, { className: "rounded-lg border-1 shadow-none outline-none", children: _jsx(Combobox.Input, { placeholder: "Search country..." }) }), _jsx(Portal, { children: _jsx(Combobox.Positioner, { style: { zIndex: 9999 }, children: _jsx(Combobox.Content, { className: "w-full", style: { zIndex: 9999 }, children: _jsx(Combobox.ItemGroup, { children: (() => {
54
+ const filteredCountries = countriesCollection.items.filter((country) => search === '' ||
55
+ country.name
56
+ .toLowerCase()
57
+ .includes(search.toLowerCase()) ||
58
+ country.areaCode.includes(search));
59
+ if (filteredCountries.length === 0) {
60
+ return (_jsx("div", { className: "p-3 text-center text-text-placeholder", children: "No countries found" }));
61
+ }
62
+ return filteredCountries.map((country) => (_jsxs(Combobox.Item, { item: country, children: [_jsxs(Combobox.ItemText, { children: [_jsx(country.flag, { className: "mr-2 inline-block size-5" }), country.name, " (", country.areaCode, ")"] }), _jsx(Combobox.ItemIndicator, { asChild: true, children: _jsx(CheckIcon, {}) })] }, country.code)));
63
+ })() }) }) }) })] }) }) }) })] }), _jsx(Field.Input, { ...(mobileNumberRegistration || {}), style: { paddingLeft: '0.5rem' }, value: mobileNumber, onChange: handleMobileChange, placeholder: "Enter mobile number" })] }), _jsx(Field.ErrorText, { children: error })] }));
61
64
  };
62
65
  const countriesListCollection = (countries) => createListCollection({
63
66
  items: countries,
Binary file
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ type MobileNumberParser = {
3
+ validate: (val: unknown) => val is string;
4
+ };
5
+ export declare const createForgotPasswordSchema: (mobileNumberParser: MobileNumberParser) => z.ZodEffects<z.ZodObject<{
6
+ password: z.ZodString;
7
+ confirmPassword: z.ZodString;
8
+ mobileNumber: z.ZodEffects<z.ZodString, string, string>;
9
+ verificationCode: z.ZodEffects<z.ZodString, string, string>;
10
+ }, "strip", z.ZodTypeAny, {
11
+ password: string;
12
+ confirmPassword: string;
13
+ mobileNumber: string;
14
+ verificationCode: string;
15
+ }, {
16
+ password: string;
17
+ confirmPassword: string;
18
+ mobileNumber: string;
19
+ verificationCode: string;
20
+ }>, {
21
+ password: string;
22
+ confirmPassword: string;
23
+ mobileNumber: string;
24
+ verificationCode: string;
25
+ }, {
26
+ password: string;
27
+ confirmPassword: string;
28
+ mobileNumber: string;
29
+ verificationCode: string;
30
+ }>;
31
+ export type ForgotPasswordSchema = z.infer<ReturnType<typeof createForgotPasswordSchema>>;
32
+ export {};
@@ -0,0 +1,15 @@
1
+ import { z } from 'zod';
2
+ export const createForgotPasswordSchema = (mobileNumberParser) => z.object({
3
+ password: z.string().min(8, 'Password must be 8 or more characters').max(20, 'Password must not be more than 20 characters'),
4
+ confirmPassword: z.string().min(8, 'Password must be 8 or more characters').max(20, 'Password must not be more than 20 characters'),
5
+ mobileNumber: z.string().superRefine((v, ctx) => {
6
+ if (!mobileNumberParser.validate(v)) {
7
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Invalid mobile number' });
8
+ }
9
+ }),
10
+ verificationCode: z.string().refine((v) => /^\d{4,6}$/.test(v), 'Invalid OTP'),
11
+ }).superRefine((val, ctx) => {
12
+ if (val.password !== val.confirmPassword) {
13
+ ctx.addIssue({ path: ['confirmPassword'], code: z.ZodIssueCode.custom, message: 'Passwords do not match' });
14
+ }
15
+ });
@@ -9,7 +9,7 @@ export interface GameSessionQueryVariables__Legacy {
9
9
  }
10
10
  export declare const getGameSession__legacy: (id: string, options?: GraphQLRequestOptions) => Promise<GameSession | null>;
11
11
  export type CreateGameSessionError__Legacy = {
12
- name: 'GameDoesNotExistError';
12
+ name: 'GameDoesNotExistError' | 'GameProviderNotEnabledError' | 'GameTypeNotEnabledError';
13
13
  message: string;
14
14
  };
15
15
  export interface CreateGameSessionMutation__Legacy {
@@ -36,4 +36,6 @@ const ERROR_CODES_MESSAGE_MAP = {
36
36
  GameProviderError: 'Game provider error',
37
37
  GameSessionAlreadyClosedError: 'Game session is already closed',
38
38
  GameSessionDoesNotExistError: 'Game session does not exist',
39
+ GameProviderNotEnabledError: 'Game provider is not enabled',
40
+ GameTypeNotEnabledError: 'Game type is not enabled',
39
41
  };
@@ -9,7 +9,7 @@ export declare const REDEEM_POINTS_TO_CASH = "\n mutation RedeemPointsToCash($i
9
9
  export declare const POINTS_WALLET_TRANSACTIONS = "\n query PointsWalletTransactions(\n $first: Int\n $after: Cursor\n $filter: MemberPointsWalletTransactionFilterInput\n ) {\n member {\n pointsWalletTransactions(first: $first, after: $after, filter: $filter) {\n edges {\n cursor\n node {\n ... on PointsWalletTransaction {\n id\n type\n amount\n balance\n dateTimeCreated\n }\n }\n }\n totalCount\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n }\n }\n";
10
10
  export declare const GAME_SESSION = "\n query GameSession($id: ObjectId!) {\n node(id: $id) {\n ... on GameSession {\n id\n game\n status\n launchUrl\n launchOptions\n }\n }\n }\n";
11
11
  export declare const GAME_SESSION__LEGACY = "\n query GameSession($id: ObjectId!) {\n node(id: $id) {\n ... on GameSession {\n id\n game {\n id\n }\n status\n launchUrl\n dateTimeCreated\n dateTimeLastUpdated\n }\n }\n }\n";
12
- export declare const CREATE_GAME_SESSION = "\n mutation CreateGameSession($input: CreateGameSessionInput!) {\n createGameSession(input: $input) {\n ... on GameDoesNotExistError {\n name: __typename\n message\n }\n }\n }\n";
12
+ export declare const CREATE_GAME_SESSION = "\n mutation CreateGameSession($input: CreateGameSessionInput!) {\n createGameSession(input: $input) {\n ... on GameDoesNotExistError {\n name: __typename\n message\n }\n ... on GameProviderNotEnabledError {\n name: __typename\n message\n }\n ... on GameTypeNotEnabledError {\n name: __typename\n message\n }\n }\n }\n";
13
13
  export declare const END_GAME_SESSION = "\n mutation EndGameSession($input: EndGameSessionInput!) {\n endGameSession(input: $input)\n }\n";
14
14
  export declare const END_GAME_SESSION__LEGACY = "\n mutation EndGameSession($input: EndGameSessionInput!) {\n endGameSession(input: $input) {\n ... on GameSessionDoesNotExistError {\n name: __typename\n message\n }\n ... on GameSessionAlreadyClosedError {\n name: __typename\n message\n }\n ... on GameProviderError {\n name: __typename\n message\n }\n }\n }\n";
15
15
  export declare const RECOMMENDED_GAMES = "\n query RecommendedGames {\n recommendedGames {\n id\n name\n type\n provider\n }\n }\n";
@@ -167,6 +167,14 @@ export const CREATE_GAME_SESSION = /* GraphQL */ `
167
167
  name: __typename
168
168
  message
169
169
  }
170
+ ... on GameProviderNotEnabledError {
171
+ name: __typename
172
+ message
173
+ }
174
+ ... on GameTypeNotEnabledError {
175
+ name: __typename
176
+ message
177
+ }
170
178
  }
171
179
  }
172
180
  `;
@@ -556,7 +556,7 @@ export interface GameSessionQueryVariables {
556
556
  }
557
557
  export declare const getGameSession: (id: string, options?: GraphQLRequestOptions) => Promise<GameSession | null>;
558
558
  export type CreateGameSessionError = {
559
- name: 'GameDoesNotExistError';
559
+ name: 'GameDoesNotExistError' | 'GameProviderNotEnabledError' | 'GameTypeNotEnabledError';
560
560
  message: string;
561
561
  };
562
562
  export interface CreateGameSessionMutation {
@@ -550,6 +550,8 @@ const ERROR_CODES_MESSAGE_MAP = {
550
550
  DepositPromoMaximumAmountExceededError: 'Deposit amount exceeds maximum amount for selected promo',
551
551
  DepositPromoMinimumAmountNotMetError: 'Deposit amount does not meet minimum amount for selected promo',
552
552
  GameDoesNotExistError: 'Game does not exist',
553
+ GameProviderNotEnabledError: 'Game provider is not enabled',
554
+ GameTypeNotEnabledError: 'Game type is not enabled',
553
555
  InsufficientPointsError: 'Insufficient points',
554
556
  InvalidTransactionPasswordError: 'Invalid transaction password',
555
557
  InvalidWithdrawalAmountError: 'Invalid withdrawal amount',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opexa/portal-components",
3
- "version": "0.0.886",
3
+ "version": "0.0.888",
4
4
  "exports": {
5
5
  "./ui/*": {
6
6
  "types": "./dist/ui/*/index.d.ts",