@opexa/portal-components 0.0.123 → 0.0.125
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.
- package/dist/components/BetRecords/BetRecords.client.d.ts +13 -0
- package/dist/components/BetRecords/BetRecords.client.js +9 -1
- package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/OnlineBankDepositContext.d.ts +2 -2
- package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/useOnlineBankDeposit.d.ts +1 -1
- package/dist/components/DepositWithdrawal/Deposit/QRPHDeposit/QRPHDepositContext.d.ts +2 -2
- package/dist/components/DepositWithdrawal/Deposit/QRPHDeposit/useQRPHDeposit.d.ts +1 -1
- package/dist/components/FavoriteGames/FavoriteGames.client.d.ts +7 -1
- package/dist/components/FavoriteGames/FavoriteGames.client.js +24 -5
- package/dist/components/ForgotPassword/ForgotPasswordForm.js +14 -7
- package/dist/components/GameLaunch/GameLaunch.lazy.js +25 -2
- package/dist/components/Games/Game.js +25 -2
- package/dist/components/Jackpots/JackpotsList/JackpotsList.d.ts +12 -1
- package/dist/components/Jackpots/JackpotsList/JackpotsListItemGameProviders.js +14 -7
- package/dist/components/KYC/CaptureSelfie.js +5 -3
- package/dist/components/SignIn/MobileNumberSignIn.js +14 -6
- package/dist/components/SignIn/NameAndPasswordSignIn.js +1 -1
- package/dist/components/SignUp/SignUpForm.js +21 -10
- package/dist/components/Tournaments/TournamentsList/TournamentsList.d.ts +12 -1
- package/dist/components/Tournaments/TournamentsList/TournamentsListItemGameProviders.js +11 -1
- package/dist/components/TransactionRecords/DepositRecordsTable.js +29 -17
- package/dist/components/TransactionRecords/TableFilters.d.ts +5 -1
- package/dist/components/TransactionRecords/TableFilters.js +105 -31
- package/dist/components/TransactionRecords/TransactionRecordsTable.js +21 -9
- package/dist/components/TransactionRecords/WithdrawalRecordsTable.js +29 -17
- package/dist/services/queries.d.ts +5 -5
- package/dist/services/queries.js +13 -18
- package/dist/services/trigger.js +2 -2
- package/dist/services/wallet.d.ts +7 -6
- package/dist/services/wallet.js +14 -12
- package/dist/ui/AlertDialog/AlertDialog.d.ts +121 -121
- package/dist/ui/AlertDialog/alertDialog.recipe.d.ts +11 -11
- package/dist/ui/Avatar/Avatar.d.ts +9 -9
- package/dist/ui/Avatar/avatar.recipe.d.ts +3 -3
- package/dist/ui/Badge/Badge.d.ts +12 -12
- package/dist/ui/Badge/badge.anatomy.d.ts +1 -1
- package/dist/ui/Badge/badge.recipe.d.ts +3 -3
- package/dist/ui/Clipboard/Clipboard.d.ts +18 -18
- package/dist/ui/Clipboard/clipboard.recipe.d.ts +3 -3
- package/dist/ui/Collapsible/Collapsible.d.ts +32 -32
- package/dist/ui/Collapsible/collapsible.recipe.d.ts +8 -8
- package/dist/ui/Combobox/Combobox.d.ts +42 -42
- package/dist/ui/Combobox/combobox.recipe.d.ts +3 -3
- package/dist/ui/DatePicker/DatePicker.d.ts +72 -72
- package/dist/ui/DatePicker/datePicker.recipe.d.ts +3 -3
- package/dist/ui/Dialog/Dialog.d.ts +121 -121
- package/dist/ui/Dialog/dialog.recipe.d.ts +11 -11
- package/dist/ui/Drawer/Drawer.d.ts +33 -33
- package/dist/ui/Drawer/drawer.recipe.d.ts +3 -3
- package/dist/ui/Field/Field.d.ts +21 -21
- package/dist/ui/Field/field.recipe.d.ts +3 -3
- package/dist/ui/Menu/Menu.d.ts +252 -252
- package/dist/ui/Menu/menu.recipe.d.ts +14 -14
- package/dist/ui/NumberInput/NumberInput.d.ts +24 -24
- package/dist/ui/NumberInput/numberInput.recipe.d.ts +3 -3
- package/dist/ui/Popover/Popover.d.ts +121 -121
- package/dist/ui/Popover/popover.recipe.d.ts +11 -11
- package/dist/ui/Progress/Progress.d.ts +27 -27
- package/dist/ui/Progress/progress.recipe.d.ts +3 -3
- package/dist/ui/QrCode/QrCode.d.ts +25 -25
- package/dist/ui/QrCode/qrCode.recipe.d.ts +5 -5
- package/dist/ui/SegmentGroup/SegmentGroup.d.ts +18 -18
- package/dist/ui/SegmentGroup/segmentGroup.recipe.d.ts +3 -3
- package/dist/ui/Select/Select.d.ts +45 -45
- package/dist/ui/Select/select.recipe.d.ts +3 -3
- package/dist/ui/Table/Table.d.ts +21 -21
- package/dist/ui/Table/table.anatomy.d.ts +1 -1
- package/dist/ui/Table/table.recipe.d.ts +3 -3
- package/dist/ui/Tabs/Tabs.d.ts +15 -15
- package/dist/ui/Tabs/tabs.recipe.d.ts +3 -3
- package/package.json +1 -1
|
@@ -2,6 +2,19 @@ import type { GameProvider, GameType } from '../../types';
|
|
|
2
2
|
export interface BetRecordsProps {
|
|
3
3
|
gameTypes: GameType[];
|
|
4
4
|
gameProviders: GameProvider[];
|
|
5
|
+
/**
|
|
6
|
+
* Game providers grouped by game type.
|
|
7
|
+
* This is used to filter the game providers based on the selected game type.
|
|
8
|
+
* If not provided, all game providers will be shown regardless of the game type.
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* gameProvidersGroup={{
|
|
12
|
+
* SLOTS: ['JILI', 'PGSOFT', 'FACHAI'],
|
|
13
|
+
* SPORTS: ['BTI', 'DIGITAIN']
|
|
14
|
+
* }}
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
gameProvidersGroup?: Partial<Record<GameType, GameProvider[]>>;
|
|
5
18
|
className?: string;
|
|
6
19
|
}
|
|
7
20
|
export declare function BetRecords__client(props: BetRecordsProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -40,8 +40,16 @@ export function BetRecords__client(props) {
|
|
|
40
40
|
type: null,
|
|
41
41
|
});
|
|
42
42
|
const localeInfo = useLocaleInfo();
|
|
43
|
+
const providersByGroup = gameProviders.filter((o) => {
|
|
44
|
+
if (!state.type)
|
|
45
|
+
return true;
|
|
46
|
+
const l = props.gameProvidersGroup?.[state.type];
|
|
47
|
+
if (!l?.length)
|
|
48
|
+
return true;
|
|
49
|
+
return l.includes(o.id);
|
|
50
|
+
});
|
|
43
51
|
const providerCollection = createListCollection({
|
|
44
|
-
items:
|
|
52
|
+
items: providersByGroup,
|
|
45
53
|
itemToValue: (item) => item.id,
|
|
46
54
|
itemToString: (item) => item.name,
|
|
47
55
|
});
|
package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/OnlineBankDepositContext.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const OnlineBankDepositContext: import("react").Context<{
|
|
2
|
-
view: "
|
|
2
|
+
view: "vca" | "form";
|
|
3
3
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
4
4
|
verify: () => void;
|
|
5
5
|
reset: () => void;
|
|
@@ -9,7 +9,7 @@ export declare const OnlineBankDepositContext: import("react").Context<{
|
|
|
9
9
|
promo?: string | null;
|
|
10
10
|
}) => void;
|
|
11
11
|
}>, useOnlineBankDepositContext: () => {
|
|
12
|
-
view: "
|
|
12
|
+
view: "vca" | "form";
|
|
13
13
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
14
14
|
verify: () => void;
|
|
15
15
|
reset: () => void;
|
package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/useOnlineBankDeposit.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Deposit } from '../../../../types';
|
|
2
2
|
export type UseOnlineBankDepositReturn = ReturnType<typeof useOnlineBankDeposit>;
|
|
3
3
|
export declare function useOnlineBankDeposit(): {
|
|
4
|
-
view: "
|
|
4
|
+
view: "vca" | "form";
|
|
5
5
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
6
6
|
verify: () => void;
|
|
7
7
|
reset: () => void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const QRPHDepositContext: import("react").Context<{
|
|
2
|
-
view: "
|
|
2
|
+
view: "qrCode" | "form";
|
|
3
3
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
4
4
|
verify: () => void;
|
|
5
5
|
reset: () => void;
|
|
@@ -9,7 +9,7 @@ export declare const QRPHDepositContext: import("react").Context<{
|
|
|
9
9
|
promo?: string | null;
|
|
10
10
|
}) => void;
|
|
11
11
|
}>, useQRPHDepositContext: () => {
|
|
12
|
-
view: "
|
|
12
|
+
view: "qrCode" | "form";
|
|
13
13
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
14
14
|
verify: () => void;
|
|
15
15
|
reset: () => void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Deposit } from '../../../../types';
|
|
2
2
|
export type UseQRPHDepositReturn = ReturnType<typeof useQRPHDeposit>;
|
|
3
3
|
export declare function useQRPHDeposit(): {
|
|
4
|
-
view: "
|
|
4
|
+
view: "qrCode" | "form";
|
|
5
5
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
6
6
|
verify: () => void;
|
|
7
7
|
reset: () => void;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
interface ClassNameEntries {
|
|
2
|
+
root?: string;
|
|
3
|
+
thumbnailRoot?: string;
|
|
4
|
+
thumbnailTitle?: string;
|
|
5
|
+
}
|
|
1
6
|
export interface FavoriteGamesProps {
|
|
2
|
-
className?: string;
|
|
7
|
+
className?: string | ClassNameEntries;
|
|
3
8
|
/** @default 'Favorite Games' */
|
|
4
9
|
heading?: string;
|
|
5
10
|
}
|
|
6
11
|
export declare function FavoriteGames__client(props: FavoriteGamesProps): import("react/jsx-runtime").JSX.Element | null;
|
|
12
|
+
export {};
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import useEmblaCarousel from 'embla-carousel-react';
|
|
4
|
+
import { isString } from 'lodash-es';
|
|
4
5
|
import Image from 'next/image';
|
|
5
6
|
import { useCallback, useEffect, useState } from 'react';
|
|
6
7
|
import { twMerge } from 'tailwind-merge';
|
|
7
8
|
import { useFavoriteGamesQuery } from '../../client/hooks/useFavoriteGamesQuery.js';
|
|
8
9
|
import { useSessionQuery } from '../../client/hooks/useSessionQuery.js';
|
|
9
10
|
import { useUnmarkGameAsFavoriteMutation } from '../../client/hooks/useUnmarkGameAsFavoriteMutation.js';
|
|
11
|
+
import { toaster } from '../../client/utils/toaster.js';
|
|
10
12
|
import { ArrowLeftIcon } from '../../icons/ArrowLeftIcon.js';
|
|
11
13
|
import { ArrowRightIcon } from '../../icons/ArrowRightIcon.js';
|
|
12
14
|
import { Star01Icon } from '../../icons/Star01Icon.js';
|
|
@@ -38,13 +40,30 @@ export function FavoriteGames__client(props) {
|
|
|
38
40
|
const games = gamesQuery.data ?? [];
|
|
39
41
|
if (games.length <= 0)
|
|
40
42
|
return null;
|
|
41
|
-
|
|
43
|
+
const classNames = isString(props.className)
|
|
44
|
+
? { root: props.className }
|
|
45
|
+
: (props.className ?? {});
|
|
46
|
+
return (_jsxs("div", { className: classNames.root, children: [_jsxs("div", { className: "flex items-center", children: [_jsx("h2", { className: "text-lg font-semibold", children: props.heading ?? 'Favorite Games' }), _jsx("div", { className: "grow" }), _jsx("div", { className: "flex items-center justify-center gap-xl", children: _jsxs("div", { className: "hidden lg:flex", children: [_jsx(Button, { variant: "outline", colorScheme: "gray", className: "rounded-r-none border-r-0", onClick: onPrevButtonClick, disabled: prevBtnDisabled, "aria-label": "Previous", children: _jsx(ArrowLeftIcon, { className: "size-5" }) }), _jsx(Button, { variant: "outline", colorScheme: "gray", className: "rounded-l-none", onClick: onNextButtonClick, disabled: nextBtnDisabled, "aria-label": "Next", children: _jsx(ArrowRightIcon, { className: "size-5" }) })] }) })] }), _jsx("div", { ref: emblaRef, className: "relative mt-lg lg:overflow-hidden", children: _jsx("div", { className: twMerge('grid auto-cols-[calc((100%-(0.375rem*2))/3)] grid-flow-col grid-rows-1 gap-sm lg:auto-cols-[calc((100%-(0.5rem*5))/6)] lg:gap-md'), children: games.map((game) => (_jsx(Item, { game: game, className: {
|
|
47
|
+
thumbnailRoot: classNames.thumbnailRoot,
|
|
48
|
+
thumbnailTitle: classNames.thumbnailTitle,
|
|
49
|
+
} }, game.id))) }) })] }));
|
|
42
50
|
}
|
|
43
|
-
function Item({ game }) {
|
|
51
|
+
function Item({ game, className, }) {
|
|
44
52
|
const sessionQuery = useSessionQuery();
|
|
45
53
|
const session = sessionQuery.data;
|
|
46
|
-
const unmarkGameAsFavoriteMutation = useUnmarkGameAsFavoriteMutation(
|
|
47
|
-
|
|
54
|
+
const unmarkGameAsFavoriteMutation = useUnmarkGameAsFavoriteMutation({
|
|
55
|
+
onSuccess() {
|
|
56
|
+
toaster.create({
|
|
57
|
+
description: 'Game removed from favorites',
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
onError() {
|
|
61
|
+
toaster.create({
|
|
62
|
+
description: 'Failed to remove game from favorites',
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
return (_jsxs(GameLaunchTrigger, { game: game, className: twMerge('relative block w-full shadow-sm', className?.thumbnailRoot), children: [session?.status === 'authenticated' && (_jsx("div", { role: "button", onClick: (e) => {
|
|
48
67
|
e.preventDefault();
|
|
49
68
|
e.stopPropagation();
|
|
50
69
|
if (unmarkGameAsFavoriteMutation.isPending)
|
|
@@ -53,5 +72,5 @@ function Item({ game }) {
|
|
|
53
72
|
}, "aria-disabled": unmarkGameAsFavoriteMutation.isPending, className: "rounded-xs absolute right-2 top-2 flex size-9 items-center justify-center bg-black/65 blur-[0.5px]", children: _jsx(Star01Icon, { className: "fill-yellow-400 text-yellow-400 size-5" }) })), _jsx(Image, { src: getGameImageUrl({
|
|
54
73
|
id: game.id,
|
|
55
74
|
provider: game.provider,
|
|
56
|
-
}), alt: "", width: 200, height: 200, priority: true, className: "aspect-square w-full rounded-t-md object-cover" }), _jsx("span", { className:
|
|
75
|
+
}), alt: "", width: 200, height: 200, priority: true, className: "aspect-square w-full rounded-t-md object-cover" }), _jsx("span", { className: twMerge('bg-bg-tertiary text-text-primary-brand block w-full truncate rounded-b-md px-2 py-3.5 text-center text-xs font-semibold', className?.thumbnailTitle), children: game.name })] }));
|
|
57
76
|
}
|
|
@@ -70,7 +70,14 @@ export function ForgotPasswordForm() {
|
|
|
70
70
|
}
|
|
71
71
|
});
|
|
72
72
|
const Step2Definition = z.object({
|
|
73
|
-
verificationCode: z.array(z.string()
|
|
73
|
+
verificationCode: z.array(z.string()).superRefine((val, ctx) => {
|
|
74
|
+
if (val.length !== 6 || val.some((v) => v.length !== 1)) {
|
|
75
|
+
ctx.addIssue({
|
|
76
|
+
code: z.ZodIssueCode.custom,
|
|
77
|
+
message: 'Please Enter your 6 digits verification code',
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}),
|
|
74
81
|
});
|
|
75
82
|
const step1Form = useForm({
|
|
76
83
|
mode: 'all',
|
|
@@ -110,17 +117,17 @@ export function ForgotPasswordForm() {
|
|
|
110
117
|
}
|
|
111
118
|
}), children: [_jsxs(Field.Root, { invalid: !!step1Form.formState.errors.mobileNumber, children: [_jsx(Field.Label, { children: "Mobile Number" }), _jsxs("div", { className: "relative", children: [_jsxs("div", { className: "absolute left-3.5 top-1/2 flex shrink-0 -translate-y-1/2 items-center gap-md", children: [_jsx(localeInfo.country.flag, { className: "size-5" }), _jsx("span", { className: "text-text-placeholder", children: localeInfo.mobileNumber.areaCode })] }), _jsx(Field.Input, { style: {
|
|
112
119
|
paddingLeft: `calc(2.75rem + ${localeInfo.mobileNumber.areaCode.length}ch)`,
|
|
113
|
-
}, ...step1Form.register('mobileNumber') })] }), _jsx(Field.ErrorText, { children: step1Form.formState.errors.mobileNumber?.message })] }), _jsx(Field.Root, { invalid: !!step1Form.formState.errors.newPassword, className: "mt-xl", children: _jsxs(PasswordInput.Root, { children: [_jsx(PasswordInput.Label, { children: "New Password" }), _jsxs(PasswordInput.Control, { children: [_jsx(PasswordInput.Input, { placeholder: "Enter your new password", ...step1Form.register('newPassword') }), _jsx(PasswordInput.VisibilityTrigger, { children: _jsx(PasswordInput.Indicator, { fallback: _jsx(EyeOffIcon, {}), asChild: true, children: _jsx(EyeIcon, {}) }) })] }), _jsx(Field.ErrorText, { children: step1Form.formState.errors.newPassword?.message })] }) }), _jsx(Field.Root, { invalid: !!step1Form.formState.errors.confirmPassword, className: "mt-xl", children: _jsxs(PasswordInput.Root, { children: [_jsx(PasswordInput.Label, { children: "Confirm Password" }), _jsxs(PasswordInput.Control, { children: [_jsx(PasswordInput.Input, { placeholder: "Confirm new password", ...step1Form.register('confirmPassword') }), _jsx(PasswordInput.VisibilityTrigger, { children: _jsx(PasswordInput.Indicator, { fallback: _jsx(EyeOffIcon, {}), asChild: true, children: _jsx(EyeIcon, {}) }) })] }), _jsx(Field.ErrorText, { children: step1Form.formState.errors.confirmPassword?.message })] }) }), _jsx(Button, { type: "submit", className: "mt-3xl", disabled: step1Form.formState.isSubmitting, children: "Continue" })] })] })), step === 2 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "mt-xl text-center text-lg font-semibold", children: "Check your Phone" }), _jsxs("p", { className: "text-text-secondary-700 mt-xs text-center text-sm", children: ["We\u2019ve sent a verification code to your mobile number", ' ', _jsx("span", { className: "font-semibold", children: mobileNumberParser.format(step1Form.getValues('mobileNumber')) }), ' ', "via text"] }), _jsxs("form", { ref: form2Ref, className: "mt-5", onSubmit: step2Form.handleSubmit(async ({ verificationCode }) => {
|
|
120
|
+
}, ...step1Form.register('mobileNumber') })] }), _jsx(Field.ErrorText, { children: step1Form.formState.errors.mobileNumber?.message })] }), _jsx(Field.Root, { invalid: !!step1Form.formState.errors.newPassword, className: "mt-xl", children: _jsxs(PasswordInput.Root, { children: [_jsx(PasswordInput.Label, { children: "New Password" }), _jsxs(PasswordInput.Control, { children: [_jsx(PasswordInput.Input, { placeholder: "Enter your new password", ...step1Form.register('newPassword') }), _jsx(PasswordInput.VisibilityTrigger, { children: _jsx(PasswordInput.Indicator, { fallback: _jsx(EyeOffIcon, {}), asChild: true, children: _jsx(EyeIcon, {}) }) })] }), _jsx(Field.ErrorText, { children: step1Form.formState.errors.newPassword?.message })] }) }), _jsx(Field.Root, { invalid: !!step1Form.formState.errors.confirmPassword, className: "mt-xl", children: _jsxs(PasswordInput.Root, { children: [_jsx(PasswordInput.Label, { children: "Confirm Password" }), _jsxs(PasswordInput.Control, { children: [_jsx(PasswordInput.Input, { placeholder: "Confirm new password", ...step1Form.register('confirmPassword') }), _jsx(PasswordInput.VisibilityTrigger, { children: _jsx(PasswordInput.Indicator, { fallback: _jsx(EyeOffIcon, {}), asChild: true, children: _jsx(EyeIcon, {}) }) })] }), _jsx(Field.ErrorText, { children: step1Form.formState.errors.confirmPassword?.message })] }) }), _jsx(Button, { type: "submit", className: "mt-3xl", disabled: step1Form.formState.isSubmitting, children: "Continue" })] })] })), step === 2 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "mt-xl text-center text-lg font-semibold", children: "Check your Phone" }), _jsxs("p", { className: "text-text-secondary-700 mt-xs text-center text-sm", children: ["We\u2019ve sent a verification code to your mobile number", ' ', _jsx("span", { className: "font-semibold", children: mobileNumberParser.format(step1Form.getValues('mobileNumber')) }), ' ', "via text"] }), _jsxs("form", { ref: form2Ref, className: "mt-5", autoComplete: "off", onSubmit: step2Form.handleSubmit(async ({ verificationCode }) => {
|
|
114
121
|
resetPasswordMutation.mutate({
|
|
115
122
|
mobileNumber: mobileNumberParser.format(step1Form.getValues('mobileNumber')),
|
|
116
123
|
newPassword: step1Form.getValues('newPassword'),
|
|
117
124
|
verificationCode: verificationCode.join(''),
|
|
118
125
|
});
|
|
119
|
-
}), children: [_jsx(Controller, { name: "verificationCode", control: step2Form.control, render: (o) => (_jsxs(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
126
|
+
}), children: [_jsx(Controller, { name: "verificationCode", control: step2Form.control, render: (o) => (_jsxs(Field.Root, { invalid: o.fieldState.invalid, children: [_jsxs(PinInput.Root, { placeholder: "0", value: o.field.value, onValueChange: (details) => {
|
|
127
|
+
o.field.onChange(details.value);
|
|
128
|
+
}, onValueComplete: () => {
|
|
129
|
+
form2Ref.current?.requestSubmit();
|
|
130
|
+
}, children: [_jsxs(PinInput.Control, { className: "grid-cols-[1fr_1fr_1fr_auto_1fr_1fr_1fr] items-center gap-md", children: [_jsx(PinInput.Input, { index: 0 }), _jsx(PinInput.Input, { index: 1 }), _jsx(PinInput.Input, { index: 2 }), _jsx("span", { className: "text-text-placeholder-subtle text-2xl font-medium", children: "\u2013" }), _jsx(PinInput.Input, { index: 3 }), _jsx(PinInput.Input, { index: 4 }), _jsx(PinInput.Input, { index: 5 })] }), _jsx(PinInput.HiddenInput, {})] }), _jsx(Field.ErrorText, { children: o.formState.errors.verificationCode?.message })] })) }), _jsx(Button, { type: "submit", className: "mt-4xl", disabled: resetPasswordMutation.isPending, children: "Verify" }), _jsxs("div", { className: "mt-3 flex w-full items-center justify-center gap-xs text-sm", children: [_jsx("span", { className: "text-text-secondary-700", children: "Didn't recieve the code?" }), _jsx("button", { type: "button", className: "text-button-secondary-fg font-semibold disabled:cursor-not-allowed disabled:opacity-75", disabled: cooldown.cooling, onClick: async () => {
|
|
124
131
|
await sendVerificationCodeMutation.mutateAsync({
|
|
125
132
|
channel: 'SMS',
|
|
126
133
|
recipient: mobileNumberParser.format(step1Form.getValues('mobileNumber')),
|
|
@@ -9,6 +9,7 @@ import { useFavoriteGamesQuery } from '../../client/hooks/useFavoriteGamesQuery.
|
|
|
9
9
|
import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
|
|
10
10
|
import { useMarkGameAsFavoriteMutation } from '../../client/hooks/useMarkGameAsFavoriteMutation.js';
|
|
11
11
|
import { useUnmarkGameAsFavoriteMutation } from '../../client/hooks/useUnmarkGameAsFavoriteMutation.js';
|
|
12
|
+
import { toaster } from '../../client/utils/toaster.js';
|
|
12
13
|
import { AlertCircleIcon } from '../../icons/AlertCircleIcon.js';
|
|
13
14
|
import { ChevronDownIcon } from '../../icons/ChevronDownIcon.js';
|
|
14
15
|
import { ChevronLeftIcon } from '../../icons/ChevronLeftIcon.js';
|
|
@@ -46,8 +47,30 @@ export function GameLaunch() {
|
|
|
46
47
|
const favoriteGamesQuery = useFavoriteGamesQuery();
|
|
47
48
|
const favoriteGames = favoriteGamesQuery.data ?? [];
|
|
48
49
|
const endGameSessionMutation = useEndGameSessionMutation();
|
|
49
|
-
const markGameAsFavoriteMutation = useMarkGameAsFavoriteMutation(
|
|
50
|
-
|
|
50
|
+
const markGameAsFavoriteMutation = useMarkGameAsFavoriteMutation({
|
|
51
|
+
onSuccess() {
|
|
52
|
+
toaster.create({
|
|
53
|
+
description: 'Game added to favorites',
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
onError() {
|
|
57
|
+
toaster.create({
|
|
58
|
+
description: 'Failed to add game to favorites',
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
const unmarkGameAsFavoriteMutation = useUnmarkGameAsFavoriteMutation({
|
|
63
|
+
onSuccess() {
|
|
64
|
+
toaster.create({
|
|
65
|
+
description: 'Game removed from favorites',
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
onError() {
|
|
69
|
+
toaster.create({
|
|
70
|
+
description: 'Failed to remove game from favorites',
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
});
|
|
51
74
|
const markedAsFavorite = favoriteGames.some((favoriteGame) => {
|
|
52
75
|
return !globalStore.gameLaunch.details.game
|
|
53
76
|
? false
|
|
@@ -6,6 +6,7 @@ import { useFavoriteGamesQuery } from '../../client/hooks/useFavoriteGamesQuery.
|
|
|
6
6
|
import { useMarkGameAsFavoriteMutation } from '../../client/hooks/useMarkGameAsFavoriteMutation.js';
|
|
7
7
|
import { useSessionQuery } from '../../client/hooks/useSessionQuery.js';
|
|
8
8
|
import { useUnmarkGameAsFavoriteMutation } from '../../client/hooks/useUnmarkGameAsFavoriteMutation.js';
|
|
9
|
+
import { toaster } from '../../client/utils/toaster.js';
|
|
9
10
|
import { Star01Icon } from '../../icons/Star01Icon.js';
|
|
10
11
|
import { getGameImageUrl } from '../../utils/getGameImageUrl.js';
|
|
11
12
|
import { GameLaunchTrigger } from '../GameLaunch/index.js';
|
|
@@ -19,8 +20,30 @@ export function Game(props) {
|
|
|
19
20
|
const session = sessionQuery.data;
|
|
20
21
|
const favoriteGamesQuery = useFavoriteGamesQuery();
|
|
21
22
|
const favoriteGames = favoriteGamesQuery.data ?? [];
|
|
22
|
-
const markGameAsFavoriteMutation = useMarkGameAsFavoriteMutation(
|
|
23
|
-
|
|
23
|
+
const markGameAsFavoriteMutation = useMarkGameAsFavoriteMutation({
|
|
24
|
+
onSuccess() {
|
|
25
|
+
toaster.create({
|
|
26
|
+
description: 'Game added to favorites',
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
onError() {
|
|
30
|
+
toaster.create({
|
|
31
|
+
description: 'Failed to add game to favorites',
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
const unmarkGameAsFavoriteMutation = useUnmarkGameAsFavoriteMutation({
|
|
36
|
+
onSuccess() {
|
|
37
|
+
toaster.create({
|
|
38
|
+
description: 'Game removed from favorites',
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
onError() {
|
|
42
|
+
toaster.create({
|
|
43
|
+
description: 'Failed to remove game from favorites',
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
});
|
|
24
47
|
const markedAsFavorite = favoriteGames.some((favoriteGame) => favoriteGame.id === game.reference);
|
|
25
48
|
const classNames = isString(props.className)
|
|
26
49
|
? { root: props.className }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ImageProps } from 'next/image';
|
|
2
2
|
import type { CSSProperties } from 'react';
|
|
3
|
-
import type { GameProvider } from '../../../types';
|
|
3
|
+
import type { GameProvider, GameProviderData } from '../../../types';
|
|
4
4
|
interface ClassNameEntries {
|
|
5
5
|
root?: string;
|
|
6
6
|
itemRoot?: string;
|
|
@@ -19,6 +19,17 @@ export interface JackpotsListProps {
|
|
|
19
19
|
style?: CSSProperties | StyleEntries;
|
|
20
20
|
gameProviders: GameProvider[];
|
|
21
21
|
gameProviderImages?: Partial<Record<GameProvider, ImageProps['src']>>;
|
|
22
|
+
/**
|
|
23
|
+
* @default '/providers/<slug>'
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* '/bingo/:slug' // '/bingo/jili'
|
|
27
|
+
* '/bingo/:id' // '/bingo/JILI'
|
|
28
|
+
* // or using a function
|
|
29
|
+
* ({slug}) => `/bingo/${slug}`
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
viewGamesUrl?: string | ((gameProvider: GameProviderData) => string);
|
|
22
33
|
animate?: boolean;
|
|
23
34
|
}
|
|
24
35
|
export declare function JackpotsList(props: JackpotsListProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -8,9 +8,20 @@ import { twMerge } from 'tailwind-merge';
|
|
|
8
8
|
import { ArrowLeftIcon } from '../../../icons/ArrowLeftIcon.js';
|
|
9
9
|
import { ArrowRightIcon } from '../../../icons/ArrowRightIcon.js';
|
|
10
10
|
import { Button } from '../../../ui/Button/index.js';
|
|
11
|
+
import { callIfFn } from '../../../utils/callIfFn.js';
|
|
11
12
|
import { useJackpotsListPropsContext } from './JackpotsListContext.js';
|
|
12
13
|
export function JackpotsListItemGameProviders({ gameProviders, }) {
|
|
13
|
-
const
|
|
14
|
+
const jackpotsProps = useJackpotsListPropsContext();
|
|
15
|
+
const viewGamesUrl = (data) => {
|
|
16
|
+
return jackpotsProps.viewGamesUrl
|
|
17
|
+
? callIfFn(jackpotsProps.viewGamesUrl, data)
|
|
18
|
+
.replace(':id', data.id)
|
|
19
|
+
.replace(':slug', data.slug)
|
|
20
|
+
: `/providers/${data.slug}`;
|
|
21
|
+
};
|
|
22
|
+
const classNames = isString(jackpotsProps.className)
|
|
23
|
+
? { root: jackpotsProps.className }
|
|
24
|
+
: (jackpotsProps.className ?? {});
|
|
14
25
|
const [emblaRef, emblaApi] = useEmblaCarousel({
|
|
15
26
|
align: 'start',
|
|
16
27
|
slidesToScroll: 1,
|
|
@@ -38,10 +49,6 @@ export function JackpotsListItemGameProviders({ gameProviders, }) {
|
|
|
38
49
|
emblaApi.on('select', onSelect);
|
|
39
50
|
emblaApi.on('reInit', onSelect);
|
|
40
51
|
}, [emblaApi, onSelect]);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
? { root: props.className }
|
|
44
|
-
: (props.className ?? {});
|
|
45
|
-
return (_jsxs("div", { className: "p-4 pb-8", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-text-primary-900 text-lg font-semibold", children: "Jackpot Game Providers" }), _jsxs("div", { className: "hidden lg:flex", children: [_jsx(Button, { disabled: !canScrollPrev, onClick: scrollPrev, variant: "outline", colorScheme: "gray", className: "rounded-r-none border-r-0", "aria-label": "Previous", children: _jsx(ArrowLeftIcon, { className: "size-5" }) }), _jsxs(Button, { disabled: !canScrollNext, onClick: scrollNext, variant: "outline", colorScheme: "gray", className: "rounded-l-none", "aria-label": "Next", children: [_jsx("span", { className: "sr-only", children: "Next" }), _jsx(ArrowRightIcon, { className: "size-5" })] })] })] }), _jsx("div", { className: "relative mt-3 overflow-hidden", ref: emblaRef, children: _jsx("div", { className: "flex gap-3.5", children: gameProviders.map((provider, i) => (_jsx(Link, { href: `/${provider.slug}`, className: twMerge('bg-gray-800 lg:bg-bg-primary-900 min-w-27.5 rounded-md', classNames.providerThumbnailRoot), children: _jsx(Image, { src: jackpotsProps.gameProviderImages?.[provider.id] ??
|
|
46
|
-
provider.logo, alt: "provider", className: twMerge('size-full', classNames.providerThumbnailImage), width: 300, height: 150 }) }, i))) }) })] }));
|
|
52
|
+
return (_jsxs("div", { className: "p-4 pb-8", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-text-primary-900 text-lg font-semibold", children: "Jackpot Game Providers" }), _jsxs("div", { className: "hidden lg:flex", children: [_jsx(Button, { disabled: !canScrollPrev, onClick: scrollPrev, variant: "outline", colorScheme: "gray", className: "rounded-r-none border-r-0", "aria-label": "Previous", children: _jsx(ArrowLeftIcon, { className: "size-5" }) }), _jsxs(Button, { disabled: !canScrollNext, onClick: scrollNext, variant: "outline", colorScheme: "gray", className: "rounded-l-none", "aria-label": "Next", children: [_jsx("span", { className: "sr-only", children: "Next" }), _jsx(ArrowRightIcon, { className: "size-5" })] })] })] }), _jsx("div", { className: "relative mt-3 overflow-hidden", ref: emblaRef, children: _jsx("div", { className: "flex gap-3.5", children: gameProviders.map((provider) => (_jsx(Link, { href: viewGamesUrl(provider), className: twMerge('bg-gray-800 lg:bg-bg-primary-900 min-w-27.5 rounded-md', classNames.providerThumbnailRoot), children: _jsx(Image, { src: jackpotsProps.gameProviderImages?.[provider.id] ??
|
|
53
|
+
provider.logo, alt: "provider", className: twMerge('size-full', classNames.providerThumbnailImage), width: 300, height: 150 }) }, provider.slug))) }) })] }));
|
|
47
54
|
}
|
|
@@ -8,6 +8,7 @@ import { Camera01Icon } from '../../icons/Camera01Icon.js';
|
|
|
8
8
|
import { XIcon } from '../../icons/XIcon.js';
|
|
9
9
|
import { Button } from '../../ui/Button/index.js';
|
|
10
10
|
import { Dialog } from '../../ui/Dialog/index.js';
|
|
11
|
+
import { onMobileDevice } from '../../utils/onMobileDevice.js';
|
|
11
12
|
import { useKYCContext } from './KYCContext.js';
|
|
12
13
|
import { loadFaceApiModels } from './loadModels.js';
|
|
13
14
|
import PersonOverlayDesktop from './PersonOverlayDesktop.js';
|
|
@@ -15,6 +16,7 @@ import { dataURLtoBlob, resizeFile } from './utils.js';
|
|
|
15
16
|
export function CaptureSelfie() {
|
|
16
17
|
const kyc = useKYCContext();
|
|
17
18
|
const { mutate, isPending } = useUploadImageFileMutation();
|
|
19
|
+
const mobileDevice = onMobileDevice();
|
|
18
20
|
const [modelsLoaded, setModelsLoaded] = useState(false);
|
|
19
21
|
const [videoStream, setVideoStream] = useState(null);
|
|
20
22
|
const [cameraError, setCameraError] = useState(null);
|
|
@@ -40,8 +42,8 @@ export function CaptureSelfie() {
|
|
|
40
42
|
setCaptureInProgress(true);
|
|
41
43
|
const stream = await navigator.mediaDevices.getUserMedia({
|
|
42
44
|
video: {
|
|
43
|
-
facingMode: 'environment',
|
|
44
|
-
aspectRatio: 16 / 9,
|
|
45
|
+
facingMode: mobileDevice ? 'user' : 'environment',
|
|
46
|
+
aspectRatio: mobileDevice ? 9 / 16 : 16 / 9,
|
|
45
47
|
width: { ideal: 1920 },
|
|
46
48
|
height: { ideal: 1080 },
|
|
47
49
|
},
|
|
@@ -232,5 +234,5 @@ export function CaptureSelfie() {
|
|
|
232
234
|
return (_jsxs("div", { className: "w-full p-4 lg:w-[640px] lg:px-12 lg:py-4xl", children: [_jsxs("button", { type: "button", className: "flex items-center gap-lg lg:absolute lg:right-5 lg:top-5 lg:p-md", onClick: () => {
|
|
233
235
|
stopCamera();
|
|
234
236
|
kyc.setCapturing(null);
|
|
235
|
-
}, children: [_jsx(XIcon, { className: "text-text-senary-300 hidden size-5 lg:block" }), _jsx(ArrowLeftIcon, { className: "text-text-senary-300 size-5 lg:hidden" }), _jsx("span", { className: "text-lg font-semibold lg:hidden", children: "Back" })] }), _jsx(Dialog.Title, { className: "mt-6 text-center text-lg font-semibold lg:mt-0", children: "Take a Selfie Holding Your ID" }), _jsx(Dialog.Description, { className: "text-text-tertiary-600 mx-auto mt-sm max-w-[19rem] text-center text-sm lg:max-w-full", children: "Make sure your face and ID are clearly visible, with no glare or blur." }), _jsx("div", { id: "parent", className: "border-border-disabled mt-6 aspect-video rounded-xl border bg-black lg:mt-8", children: captureInProgress ? (_jsxs("div", { className: "relative flex h-fit w-full flex-col items-center justify-center", children: [_jsx("video", { ref: videoRef, autoPlay: true, muted: true, className: "h-[60vh] w-full rounded-lg object-cover md:aspect-video md:h-[333px]", width: "100%", height: "100%" }), _jsx("canvas", { ref: faceCanvasRef, className: "absolute inset-0 h-[60vh] w-full object-cover md:aspect-video md:h-[333px] md:object-contain", width: "100%", height: "100%" }), isFaceCentered && (_jsx("span", { className: "absolute inset-x-0 bottom-
|
|
237
|
+
}, children: [_jsx(XIcon, { className: "text-text-senary-300 hidden size-5 lg:block" }), _jsx(ArrowLeftIcon, { className: "text-text-senary-300 size-5 lg:hidden" }), _jsx("span", { className: "text-lg font-semibold lg:hidden", children: "Back" })] }), _jsx(Dialog.Title, { className: "mt-6 text-center text-lg font-semibold lg:mt-0", children: "Take a Selfie Holding Your ID" }), _jsx(Dialog.Description, { className: "text-text-tertiary-600 mx-auto mt-sm max-w-[19rem] text-center text-sm lg:max-w-full", children: "Make sure your face and ID are clearly visible, with no glare or blur." }), _jsx("div", { id: "parent", className: "border-border-disabled mt-6 aspect-video rounded-xl border bg-black lg:mt-8", children: captureInProgress ? (_jsxs("div", { className: "relative flex h-fit w-full flex-col items-center justify-center", children: [_jsx("video", { ref: videoRef, autoPlay: true, muted: true, className: "h-[60vh] w-full rounded-lg object-cover md:aspect-video md:h-[333px]", width: "100%", height: "100%" }), _jsx("canvas", { ref: faceCanvasRef, className: "absolute inset-0 h-[60vh] w-full object-cover md:aspect-video md:h-[333px] md:object-contain", width: "100%", height: "100%" }), isFaceCentered && (_jsx("span", { className: "absolute inset-x-0 bottom-8 flex items-center justify-center text-5xl font-bold text-[#713B12CC] md:bottom-4", children: countdown })), !isFaceCentered && (_jsx("span", { className: "absolute inset-x-0 bottom-12 mx-auto w-1/2 text-center text-xs text-white md:bottom-3", children: "Please center your face in the camera view. Make sure your ID is clearly visible next to your face." })), _jsx(PersonOverlayDesktop, { isFaceCentered: isFaceCentered, width: videoRef.current?.clientWidth || 543, height: videoRef.current?.clientHeight || 333 })] })) : (selectedImage && (_jsx("img", { src: selectedImage, alt: "Captured Photo", className: "h-full w-full rounded-lg object-cover md:aspect-video md:h-[333px]" }))) }), selectedImage && (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 md:flex-row", children: [_jsxs(Button, { className: "disabled:bg-bg-disabled disabled:text-text-disabled mx-auto mt-4 px-xl disabled:opacity-100", size: "sm", onClick: retakePhoto, type: "button", children: ["Rekate Photo", _jsx(Camera01Icon, { className: "size-5" })] }), _jsxs(Button, { className: "disabled:bg-bg-disabled disabled:text-text-disabled mx-auto mt-4 px-xl disabled:opacity-100", size: "sm", onClick: usePhoto, type: "button", disabled: isPending, children: ["Use Photo", _jsx(Camera01Icon, { className: "size-5" })] })] })), !selectedImage && (_jsxs(Button, { className: "mx-auto mt-6 px-xl lg:mt-8", onClick: startCamera, disabled: !modelsLoaded, type: "button", children: ["Start Camera", _jsx(Camera01Icon, { className: "size-5" })] }))] }));
|
|
236
238
|
}
|
|
@@ -53,7 +53,14 @@ export function MobileNumberSignIn() {
|
|
|
53
53
|
}),
|
|
54
54
|
});
|
|
55
55
|
const Step2Definition = z.object({
|
|
56
|
-
verificationCode: z.array(z.string()
|
|
56
|
+
verificationCode: z.array(z.string()).superRefine((val, ctx) => {
|
|
57
|
+
if (val.length !== 6 || val.some((v) => v.length !== 1)) {
|
|
58
|
+
ctx.addIssue({
|
|
59
|
+
code: z.ZodIssueCode.custom,
|
|
60
|
+
message: 'Please Enter your 6 digits verification code',
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}),
|
|
57
64
|
});
|
|
58
65
|
const step1Form = useForm({
|
|
59
66
|
resolver: zodResolver(Step1Definition),
|
|
@@ -119,11 +126,12 @@ export function MobileNumberSignIn() {
|
|
|
119
126
|
description: 'Invalid Verification Code',
|
|
120
127
|
});
|
|
121
128
|
}
|
|
122
|
-
}), children: [_jsx(Controller, { name: "verificationCode", control: step2Form.control, render: (o) => (_jsxs(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
129
|
+
}), children: [_jsx(Controller, { name: "verificationCode", control: step2Form.control, render: (o) => (_jsxs(Field.Root, { invalid: o.fieldState.invalid, children: [_jsxs(PinInput.Root, { placeholder: "0", value: o.field.value, onValueChange: (details) => {
|
|
130
|
+
o.field.onChange(details.value);
|
|
131
|
+
o.field.onBlur();
|
|
132
|
+
}, otp: true, onValueComplete: () => {
|
|
133
|
+
form2Ref.current?.requestSubmit();
|
|
134
|
+
}, children: [_jsxs(PinInput.Control, { className: "grid-cols-[1fr_1fr_1fr_auto_1fr_1fr_1fr] items-center gap-md", children: [_jsx(PinInput.Input, { index: 0 }), _jsx(PinInput.Input, { index: 1 }), _jsx(PinInput.Input, { index: 2 }), _jsx("span", { className: "text-text-placeholder-subtle text-2xl font-medium", children: "\u2013" }), _jsx(PinInput.Input, { index: 3 }), _jsx(PinInput.Input, { index: 4 }), _jsx(PinInput.Input, { index: 5 })] }), _jsx(PinInput.HiddenInput, {})] }), _jsx(Field.ErrorText, { children: o.fieldState.error?.message })] })) }), _jsx(Button, { type: "submit", className: "mt-4xl", disabled: step2Form.formState.isSubmitting, children: "Verify" }), _jsxs("div", { className: "mt-3 flex w-full items-center justify-center gap-xs text-sm", children: [_jsx("span", { className: "text-text-secondary-700", children: "Didn't recieve the code?" }), _jsx("button", { type: "button", className: "text-button-secondary-fg font-semibold", disabled: cooldown.cooling, onClick: async () => {
|
|
127
135
|
await sendVerificationCodeMutation.mutateAsync({
|
|
128
136
|
channel: 'SMS',
|
|
129
137
|
recipient: mobileNumberParser.format(step1Form.getValues('mobileNumber')),
|
|
@@ -119,7 +119,7 @@ export function NameAndPasswordSignIn() {
|
|
|
119
119
|
signInMutation.reset();
|
|
120
120
|
form.setValue('secretAnswer', '');
|
|
121
121
|
},
|
|
122
|
-
}) }), _jsx(Field.ErrorText, { children: form.formState.errors.name?.message })] }), _jsx(Field.Root, { disabled: !!signInMutation.data, invalid: !!form.formState.errors.
|
|
122
|
+
}) }), _jsx(Field.ErrorText, { children: form.formState.errors.name?.message })] }), _jsx(Field.Root, { disabled: !!signInMutation.data, invalid: !!form.formState.errors.password, className: "mt-xl", children: _jsxs(PasswordInput.Root, { children: [_jsx(PasswordInput.Label, { children: "Password" }), _jsxs("div", { children: [_jsxs(PasswordInput.Control, { children: [_jsx(PasswordInput.Input, { placeholder: "Enter your password", ...form.register('password') }), _jsx(PasswordInput.VisibilityTrigger, { children: _jsx(PasswordInput.Indicator, { fallback: _jsx(EyeOffIcon, {}), asChild: true, children: _jsx(EyeIcon, {}) }) })] }), _jsx(Field.ErrorText, { children: form.formState.errors.password?.message })] }), _jsx("div", { className: "mt-2 flex justify-end", children: _jsx("button", { type: "button", tabIndex: -1, className: "text-button-tertiary-fg text-sm font-semibold", onClick: () => {
|
|
123
123
|
globalStore.forgotPassword.setOpen(true);
|
|
124
124
|
dialog.setOpen(false);
|
|
125
125
|
}, children: "Forgot Password" }) })] }) }), signInMutation.data && (_jsxs(Field.Root, { invalid: !!form.formState.errors.secretAnswer, className: "mt-xl", children: [_jsx(Field.Label, { children: secretQuestion }), _jsx(Field.Input, { placeholder: "Answer the security question", ...form.register('secretAnswer') }), _jsx(Field.ErrorText, { children: form.formState.errors.secretAnswer?.message })] })), _jsx(Button, { type: "submit", className: "mt-3xl", disabled: signInMutation.isPending || authenticateMutation.isPending, children: "Log In" }), _jsx(Controller, { control: form.control, name: "termsAccepted", render: (o) => (_jsxs(Field.Root, { invalid: o.fieldState.invalid, className: "mt-xl", children: [_jsxs(Checkbox.Root, { checked: o.field.value, onCheckedChange: (details) => {
|
|
@@ -54,7 +54,10 @@ export function SignUpForm() {
|
|
|
54
54
|
const localeInfo = useLocaleInfo();
|
|
55
55
|
const mobileNumberParser = useMobileNumberParser();
|
|
56
56
|
const Step1Definition = z.object({
|
|
57
|
-
mobileNumber: z
|
|
57
|
+
mobileNumber: z
|
|
58
|
+
.string()
|
|
59
|
+
.min(1, 'Mobile number is required')
|
|
60
|
+
.superRefine((v, ctx) => {
|
|
58
61
|
if (!mobileNumberParser.validate(v)) {
|
|
59
62
|
ctx.addIssue({
|
|
60
63
|
code: z.ZodIssueCode.custom,
|
|
@@ -93,7 +96,14 @@ export function SignUpForm() {
|
|
|
93
96
|
branchCode: z.string().min(1, 'Branch is required').trim(),
|
|
94
97
|
});
|
|
95
98
|
const Step2Definition = z.object({
|
|
96
|
-
verificationCode: z.array(z.string()
|
|
99
|
+
verificationCode: z.array(z.string()).superRefine((val, ctx) => {
|
|
100
|
+
if (val.length !== 6 || val.some((v) => v.length !== 1)) {
|
|
101
|
+
ctx.addIssue({
|
|
102
|
+
code: z.ZodIssueCode.custom,
|
|
103
|
+
message: 'Please Enter your 6 digits verification code',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}),
|
|
97
107
|
});
|
|
98
108
|
const step1Form = useForm({
|
|
99
109
|
mode: 'all',
|
|
@@ -118,7 +128,7 @@ export function SignUpForm() {
|
|
|
118
128
|
const form2Ref = useRef(null);
|
|
119
129
|
const birthDay = step1Form.watch('birthDay');
|
|
120
130
|
const branchCode = step1Form.watch('branchCode', '');
|
|
121
|
-
return (_jsxs(_Fragment, { children: [step === 1 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "mt-xl text-center text-lg font-semibold", children: "Create an account" }), _jsx("p", { className: "text-text-secondary-700 mt-xs text-center text-sm", children: "Register instantly and start playing!" }), _jsxs("form", { className: "mt-3xl", onSubmit: step1Form.handleSubmit(async (data) => {
|
|
131
|
+
return (_jsxs(_Fragment, { children: [step === 1 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "mt-xl text-center text-lg font-semibold", children: "Create an account" }), _jsx("p", { className: "text-text-secondary-700 mt-xs text-center text-sm", children: "Register instantly and start playing!" }), _jsxs("form", { className: "mt-3xl", autoComplete: "off", onSubmit: step1Form.handleSubmit(async (data) => {
|
|
122
132
|
try {
|
|
123
133
|
await sendVerificationCodeMutation.mutateAsync({
|
|
124
134
|
channel: 'SMS',
|
|
@@ -145,7 +155,9 @@ export function SignUpForm() {
|
|
|
145
155
|
shouldValidate: true,
|
|
146
156
|
});
|
|
147
157
|
}
|
|
148
|
-
}, children: [_jsx(DatePicker.Label, { children: "Date of Birth" }), _jsxs(DatePicker.Control, { children: [_jsx(DatePicker.Input, {
|
|
158
|
+
}, children: [_jsx(DatePicker.Label, { children: "Date of Birth" }), _jsxs(DatePicker.Control, { children: [_jsx(DatePicker.Input, { onBlur: () => {
|
|
159
|
+
step1Form.trigger('birthDay');
|
|
160
|
+
} }), _jsx(DatePicker.Trigger, { children: _jsx(CalendarIcon, {}) })] }), _jsx(DatePicker.Positioner, { children: _jsx(DatePicker.Content, { children: _jsx(DatePicker.View, { view: "day", children: _jsx(DatePicker.Context, { children: (api) => (_jsxs(_Fragment, { children: [_jsxs(DatePicker.ViewControl, { children: [_jsx(DatePicker.PrevTrigger, { children: _jsx(ChevronLeftIcon, {}) }), _jsx(DatePicker.ViewTrigger, { children: _jsx(DatePicker.RangeText, {}) }), _jsx(DatePicker.NextTrigger, { children: _jsx(ChevronRightIcon, {}) })] }), _jsxs(DatePicker.Table, { children: [_jsx(DatePicker.TableHead, { children: _jsx(DatePicker.TableRow, { children: api.weekDays.map((weekDay, id) => (_jsx(DatePicker.TableHeader, { children: weekDay.short.substring(0, 2) }, id))) }) }), _jsx(DatePicker.TableBody, { children: api.weeks.map((week, id) => (_jsx(DatePicker.TableRow, { children: week.map((day, id) => (_jsx(DatePicker.TableCell, { value: day, children: _jsx(DatePicker.TableCellTrigger, { children: day.day }) }, id))) }, id))) })] })] })) }) }) }) })] }), _jsx(Field.ErrorText, { children: step1Form.formState.errors.birthDay?.message })] }), _jsxs(Field.Root, { invalid: !!step1Form.formState.errors.branchCode, className: "mt-xl", children: [_jsxs(Select.Root, { value: [branchCode], onValueChange: (details) => {
|
|
149
161
|
step1Form.setValue('branchCode', details.value.at(0) ?? BRANCH_CODES[0].code, {
|
|
150
162
|
shouldDirty: true,
|
|
151
163
|
shouldTouch: true,
|
|
@@ -213,17 +225,16 @@ export function SignUpForm() {
|
|
|
213
225
|
}
|
|
214
226
|
catch (error) {
|
|
215
227
|
toaster.error({
|
|
216
|
-
title: 'Login Failed',
|
|
217
228
|
description: error instanceof Error
|
|
218
229
|
? error.message
|
|
219
230
|
: 'Invalid Verification Code',
|
|
220
231
|
});
|
|
221
232
|
}
|
|
222
|
-
}), children: [_jsx(Controller, { name: "verificationCode", control: step2Form.control, render: (o) => (_jsxs(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
233
|
+
}), children: [_jsx(Controller, { name: "verificationCode", control: step2Form.control, render: (o) => (_jsxs(Field.Root, { invalid: o.fieldState.invalid, children: [_jsxs(PinInput.Root, { placeholder: "0", value: o.field.value, onValueChange: (details) => {
|
|
234
|
+
o.field.onChange(details.value);
|
|
235
|
+
}, onValueComplete: () => {
|
|
236
|
+
form2Ref.current?.requestSubmit();
|
|
237
|
+
}, children: [_jsxs(PinInput.Control, { className: "grid-cols-[1fr_1fr_1fr_auto_1fr_1fr_1fr] items-center gap-md", children: [_jsx(PinInput.Input, { index: 0 }), _jsx(PinInput.Input, { index: 1 }), _jsx(PinInput.Input, { index: 2 }), _jsx("span", { className: "text-text-placeholder-subtle text-2xl font-medium", children: "\u2013" }), _jsx(PinInput.Input, { index: 3 }), _jsx(PinInput.Input, { index: 4 }), _jsx(PinInput.Input, { index: 5 })] }), _jsx(PinInput.HiddenInput, {})] }), _jsx(Field.ErrorText, { children: o.formState.errors.verificationCode?.message })] })) }), _jsx(Button, { type: "submit", className: "mt-4xl", disabled: step2Form.formState.isSubmitting, children: "Verify" }), _jsxs("div", { className: "mt-3 flex w-full items-center justify-center gap-xs text-sm", children: [_jsx("span", { className: "text-text-secondary-700", children: "Didn't recieve the code?" }), _jsx("button", { type: "button", className: "text-button-secondary-fg font-semibold disabled:cursor-not-allowed disabled:opacity-75", disabled: cooldown.cooling, onClick: async () => {
|
|
227
238
|
await sendVerificationCodeMutation.mutateAsync({
|
|
228
239
|
channel: 'SMS',
|
|
229
240
|
recipient: mobileNumberParser.format(step1Form.getValues('mobileNumber')),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CSSProperties } from 'react';
|
|
2
|
-
import type { GameProvider } from '../../../types';
|
|
2
|
+
import type { GameProvider, GameProviderData } from '../../../types';
|
|
3
3
|
interface ClassNameEntries {
|
|
4
4
|
root?: string;
|
|
5
5
|
itemRoot?: string;
|
|
@@ -21,6 +21,17 @@ export interface TournamentsListProps {
|
|
|
21
21
|
className?: string | ClassNameEntries;
|
|
22
22
|
style?: CSSProperties | StyleEntries;
|
|
23
23
|
gameProviders: GameProvider[];
|
|
24
|
+
/**
|
|
25
|
+
* @default '/providers/<slug>'
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* '/bingo/:slug' // '/bingo/jili'
|
|
29
|
+
* '/bingo/:id' // '/bingo/JILI'
|
|
30
|
+
* // or using a function
|
|
31
|
+
* ({slug}) => `/bingo/${slug}`
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
viewGamesUrl?: string | ((gameProvider: GameProviderData) => string);
|
|
24
35
|
}
|
|
25
36
|
export declare function TournamentsList({ style, className, ...props }: TournamentsListProps): import("react/jsx-runtime").JSX.Element;
|
|
26
37
|
export {};
|
|
@@ -6,7 +6,17 @@ import { useCallback, useEffect, useState } from 'react';
|
|
|
6
6
|
import { ArrowLeftIcon } from '../../../icons/ArrowLeftIcon.js';
|
|
7
7
|
import { ArrowRightIcon } from '../../../icons/ArrowRightIcon.js';
|
|
8
8
|
import { Button } from '../../../ui/Button/index.js';
|
|
9
|
+
import { callIfFn } from '../../../utils/callIfFn.js';
|
|
10
|
+
import { useTournamentsListPropsContext } from './TournamentsListContext.js';
|
|
9
11
|
export function TournamentsListItemGameProviders({ gameProviders, }) {
|
|
12
|
+
const tournamentsProps = useTournamentsListPropsContext();
|
|
13
|
+
const viewGamesUrl = (data) => {
|
|
14
|
+
return tournamentsProps.viewGamesUrl
|
|
15
|
+
? callIfFn(tournamentsProps.viewGamesUrl, data)
|
|
16
|
+
.replace(':id', data.id)
|
|
17
|
+
.replace(':slug', data.slug)
|
|
18
|
+
: `/providers/${data.slug}`;
|
|
19
|
+
};
|
|
10
20
|
const [emblaRef, emblaApi] = useEmblaCarousel({
|
|
11
21
|
align: 'start',
|
|
12
22
|
slidesToScroll: 1,
|
|
@@ -34,5 +44,5 @@ export function TournamentsListItemGameProviders({ gameProviders, }) {
|
|
|
34
44
|
emblaApi.on('select', onSelect);
|
|
35
45
|
emblaApi.on('reInit', onSelect);
|
|
36
46
|
}, [emblaApi, onSelect]);
|
|
37
|
-
return (_jsxs("div", { className: "p-4 pb-8", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-text-primary-900 text-lg font-semibold", children: "Tournament Game Providers" }), _jsxs("div", { className: "hidden lg:flex", children: [_jsx(Button, { disabled: !canScrollPrev, onClick: scrollPrev, variant: "outline", colorScheme: "gray", className: "rounded-r-none border-r-0", "aria-label": "Previous", children: _jsx(ArrowLeftIcon, { className: "size-5" }) }), _jsxs(Button, { disabled: !canScrollNext, onClick: scrollNext, variant: "outline", colorScheme: "gray", className: "rounded-l-none", "aria-label": "Next", children: [_jsx("span", { className: "sr-only", children: "Next" }), _jsx(ArrowRightIcon, { className: "size-5" })] })] })] }), _jsx("div", { className: "relative mt-3 overflow-hidden", ref: emblaRef, children: _jsx("div", { className: "flex gap-3.5", children: gameProviders.map((provider
|
|
47
|
+
return (_jsxs("div", { className: "p-4 pb-8", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-text-primary-900 text-lg font-semibold", children: "Tournament Game Providers" }), _jsxs("div", { className: "hidden lg:flex", children: [_jsx(Button, { disabled: !canScrollPrev, onClick: scrollPrev, variant: "outline", colorScheme: "gray", className: "rounded-r-none border-r-0", "aria-label": "Previous", children: _jsx(ArrowLeftIcon, { className: "size-5" }) }), _jsxs(Button, { disabled: !canScrollNext, onClick: scrollNext, variant: "outline", colorScheme: "gray", className: "rounded-l-none", "aria-label": "Next", children: [_jsx("span", { className: "sr-only", children: "Next" }), _jsx(ArrowRightIcon, { className: "size-5" })] })] })] }), _jsx("div", { className: "relative mt-3 overflow-hidden", ref: emblaRef, children: _jsx("div", { className: "flex gap-3.5", children: gameProviders.map((provider) => (_jsx(Link, { href: viewGamesUrl(provider), className: "bg-gray-800 lg:bg-bg-primary-900 min-w-27.5 rounded-md", children: _jsx(Image, { src: provider.logo, alt: "provider", className: "size-full", width: 300, height: 150 }) }, provider.slug))) }) })] }));
|
|
38
48
|
}
|