@opexa/portal-components 0.0.49 → 0.0.51
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/client/hooks/index.d.ts +2 -0
- package/dist/client/hooks/index.js +2 -0
- package/dist/client/hooks/useAvailableQuestsQuery.d.ts +3 -0
- package/dist/client/hooks/useAvailableQuestsQuery.js +34 -0
- package/dist/client/hooks/useCheckInDailyCheckInQuestMutation.d.ts +2 -0
- package/dist/client/hooks/useCheckInDailyCheckInQuestMutation.js +29 -0
- package/dist/client/hooks/useGlobalStore.d.ts +3 -3
- package/dist/client/hooks/useGlobalStore.js +3 -3
- package/dist/components/Account/AccountTrigger.d.ts +6 -0
- package/dist/components/Account/AccountTrigger.js +13 -0
- package/dist/components/Account/index.d.ts +1 -0
- package/dist/components/Account/index.js +1 -0
- 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/DepositWithdrawal/DepositWithdrawalTrigger.js +3 -2
- package/dist/components/GameLaunch/GameLaunchTrigger.js +13 -10
- package/dist/components/Games/Game.js +1 -1
- package/dist/components/GamesSearch/GamesSearch.d.ts +4 -2
- package/dist/components/GamesSearch/GamesSearch.js +28 -21
- package/dist/components/GamesSearch/index.d.ts +0 -1
- package/dist/components/GamesSearch/index.js +0 -1
- package/dist/components/Messages/Messages.js +1 -1
- package/dist/components/Messages/MessagesTrigger.js +2 -2
- package/dist/components/Quests/CountdownTimer.d.ts +15 -0
- package/dist/components/Quests/CountdownTimer.js +33 -0
- package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuest.d.ts +4 -1
- package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuest.js +52 -37
- package/dist/components/Quests/Quests.js +25 -1
- package/dist/components/Quests/WageringQuest/WageringQuest.d.ts +4 -1
- package/dist/components/Quests/WageringQuest/WageringQuest.js +9 -7
- package/dist/components/Quests/WageringQuest/WageringQuestModal.d.ts +1 -0
- package/dist/components/Quests/WageringQuest/WageringQuestModal.js +1 -1
- package/dist/components/Search/Search.d.ts +6 -0
- package/dist/components/Search/Search.js +38 -0
- package/dist/components/Search/SearchTrigger.d.ts +5 -0
- package/dist/components/Search/SearchTrigger.js +14 -0
- package/dist/components/Search/index.d.ts +2 -0
- package/dist/components/Search/index.js +2 -0
- package/dist/components/SignIn/SignInTrigger.js +2 -2
- package/dist/components/SignUp/SignUpTrigger.js +2 -2
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/styles/theme.css +24 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/ui/Combobox/Combobox.d.ts +840 -798
- package/dist/ui/Combobox/combobox.recipe.d.ts +54 -51
- package/dist/ui/Combobox/combobox.recipe.js +59 -1
- package/dist/ui/Progress/Progress.d.ts +27 -27
- package/dist/ui/Progress/progress.recipe.d.ts +3 -3
- 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.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/dist/utils/queryKeys.d.ts +2 -0
- package/dist/utils/queryKeys.js +6 -0
- package/package.json +2 -2
|
@@ -53,3 +53,5 @@ export * from './useUnreadMessagesCountQuery';
|
|
|
53
53
|
export * from './useUpdateAccountMutation';
|
|
54
54
|
export * from './useWalletQuery';
|
|
55
55
|
export * from './useWithdrawalRecordsQuery';
|
|
56
|
+
export * from './useAvailableQuestsQuery';
|
|
57
|
+
export * from './useCheckInDailyCheckInQuestMutation';
|
|
@@ -53,3 +53,5 @@ export * from './useUnreadMessagesCountQuery.js';
|
|
|
53
53
|
export * from './useUpdateAccountMutation.js';
|
|
54
54
|
export * from './useWalletQuery.js';
|
|
55
55
|
export * from './useWithdrawalRecordsQuery.js';
|
|
56
|
+
export * from './useAvailableQuestsQuery.js';
|
|
57
|
+
export * from './useCheckInDailyCheckInQuestMutation.js';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { getAvailableQuests } from '@opexa/portal-sdk-core';
|
|
2
|
+
import { useQuery } from '@tanstack/react-query';
|
|
3
|
+
import invariant from 'tiny-invariant';
|
|
4
|
+
import { ENVIRONMENT, PLATFORM_CODE } from '../../constants/index.js';
|
|
5
|
+
import { getAvailableQuestsQueryKey, getQueryClient, getSessionQueryKey, } from '../../utils/index.js';
|
|
6
|
+
import { getSession } from '../services/index.js';
|
|
7
|
+
import { useSessionQuery } from './useSessionQuery.js';
|
|
8
|
+
export const useAvailableQuestsQuery = (config) => {
|
|
9
|
+
const queryClient = getQueryClient();
|
|
10
|
+
const sessionQuery = useSessionQuery();
|
|
11
|
+
const query = useQuery({
|
|
12
|
+
...config,
|
|
13
|
+
enabled: config?.enabled === false
|
|
14
|
+
? false
|
|
15
|
+
: sessionQuery.data?.status === 'authenticated',
|
|
16
|
+
queryKey: getAvailableQuestsQueryKey(),
|
|
17
|
+
queryFn: async ({ signal }) => {
|
|
18
|
+
const session = await queryClient.fetchQuery({
|
|
19
|
+
queryKey: getSessionQueryKey(),
|
|
20
|
+
queryFn: () => getSession(),
|
|
21
|
+
});
|
|
22
|
+
invariant(session.status === 'authenticated');
|
|
23
|
+
return await getAvailableQuests({
|
|
24
|
+
signal,
|
|
25
|
+
environment: ENVIRONMENT,
|
|
26
|
+
headers: {
|
|
27
|
+
'Platform-Code': PLATFORM_CODE,
|
|
28
|
+
Authorization: `Bearer ${session.token}`,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
return query;
|
|
34
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getCheckInDailyQuestMutationKey, getQueryClient, getSessionQueryKey, } from '../../utils/index.js';
|
|
2
|
+
import { useMutation } from '@tanstack/react-query';
|
|
3
|
+
import { getSession } from '../services/index.js';
|
|
4
|
+
import invariant from 'tiny-invariant';
|
|
5
|
+
import { checkInDailyCheckInQuest } from '@opexa/portal-sdk-core';
|
|
6
|
+
import { ENVIRONMENT, PLATFORM_CODE } from '../../constants/index.js';
|
|
7
|
+
export const useCheckInDailyCheckInQuestMutation = (config) => {
|
|
8
|
+
const queryClient = getQueryClient();
|
|
9
|
+
const mutation = useMutation({
|
|
10
|
+
...config,
|
|
11
|
+
mutationKey: getCheckInDailyQuestMutationKey(),
|
|
12
|
+
mutationFn: async (id) => {
|
|
13
|
+
const session = await queryClient.fetchQuery({
|
|
14
|
+
queryKey: getSessionQueryKey(),
|
|
15
|
+
queryFn: () => getSession(),
|
|
16
|
+
});
|
|
17
|
+
invariant(session.status === 'authenticated');
|
|
18
|
+
await checkInDailyCheckInQuest(id, {
|
|
19
|
+
environment: ENVIRONMENT,
|
|
20
|
+
headers: {
|
|
21
|
+
'Platform-Code': PLATFORM_CODE,
|
|
22
|
+
Authorization: `Bearer ${session.token}`,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
return id;
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
return mutation;
|
|
29
|
+
};
|
|
@@ -24,12 +24,12 @@ type GameLaunchDetails = {
|
|
|
24
24
|
game: Game | FavoriteGame;
|
|
25
25
|
session?: null;
|
|
26
26
|
};
|
|
27
|
-
interface GamesSearchStore extends PopupStore {
|
|
28
|
-
}
|
|
29
27
|
interface GameLaunchStore {
|
|
30
28
|
details: GameLaunchDetails;
|
|
31
29
|
setDetails: (details: GameLaunchDetails) => void;
|
|
32
30
|
}
|
|
31
|
+
interface SearchStore extends PopupStore {
|
|
32
|
+
}
|
|
33
33
|
type DepositWithdrawalTab = 'DEPOSIT' | 'WITHDRAWAL';
|
|
34
34
|
type MessagesTab = 'ALL' | 'UNREAD';
|
|
35
35
|
interface MessageStore extends PopupStore {
|
|
@@ -50,7 +50,7 @@ interface GlobalStore {
|
|
|
50
50
|
disclaimer: PopupStore;
|
|
51
51
|
depositWithdrawal: DepositWithdrawalStore;
|
|
52
52
|
gameLaunch: GameLaunchStore;
|
|
53
|
-
|
|
53
|
+
search: SearchStore;
|
|
54
54
|
account: PopupStore;
|
|
55
55
|
account__mobile: PopupStore;
|
|
56
56
|
messages: MessagesStore;
|
|
@@ -126,12 +126,12 @@ export const useGlobalStore = create((set) => ({
|
|
|
126
126
|
}));
|
|
127
127
|
},
|
|
128
128
|
},
|
|
129
|
-
|
|
129
|
+
search: {
|
|
130
130
|
open: false,
|
|
131
131
|
setOpen(open) {
|
|
132
132
|
set((prev) => ({
|
|
133
|
-
|
|
134
|
-
...prev.
|
|
133
|
+
search: {
|
|
134
|
+
...prev.search,
|
|
135
135
|
open,
|
|
136
136
|
},
|
|
137
137
|
}));
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef } from 'react';
|
|
2
|
+
export interface AccountTriggerProps extends ComponentPropsWithRef<'button'> {
|
|
3
|
+
mobile?: boolean;
|
|
4
|
+
asChild?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function AccountTrigger(props: AccountTriggerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { ark } from '@ark-ui/react';
|
|
4
|
+
import { useShallow } from 'zustand/shallow';
|
|
5
|
+
import { useGlobalStore } from '../../client/hooks/index.js';
|
|
6
|
+
export function AccountTrigger(props) {
|
|
7
|
+
const { mobile, ...rest } = props;
|
|
8
|
+
const { open, setOpen } = useGlobalStore(useShallow((ctx) => (mobile ? ctx.account__mobile : ctx.account)));
|
|
9
|
+
return (_jsx(ark.button, { type: "button", "aria-label": "Toggle account menu", "data-open": open ? 'open' : 'closed', ...rest, onClick: (e) => {
|
|
10
|
+
setOpen(!open);
|
|
11
|
+
return props.onClick?.(e);
|
|
12
|
+
} }));
|
|
13
|
+
}
|
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: "form" | "vca";
|
|
3
3
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
4
4
|
verify: () => void;
|
|
5
5
|
reset: () => void;
|
|
@@ -10,7 +10,7 @@ export declare const OnlineBankDepositContext: import("react").Context<{
|
|
|
10
10
|
}) => void;
|
|
11
11
|
} | null>;
|
|
12
12
|
export declare const useOnlineBankDepositContext: () => {
|
|
13
|
-
view: "
|
|
13
|
+
view: "form" | "vca";
|
|
14
14
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
15
15
|
verify: () => void;
|
|
16
16
|
reset: () => void;
|
package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/useOnlineBankDeposit.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Deposit } from '@opexa/portal-sdk-core';
|
|
2
2
|
export type UseOnlineBankDepositReturn = ReturnType<typeof useOnlineBankDeposit>;
|
|
3
3
|
export declare function useOnlineBankDeposit(): {
|
|
4
|
-
view: "
|
|
4
|
+
view: "form" | "vca";
|
|
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: "form" | "qrCode";
|
|
3
3
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
4
4
|
verify: () => void;
|
|
5
5
|
reset: () => void;
|
|
@@ -10,7 +10,7 @@ export declare const QRPHDepositContext: import("react").Context<{
|
|
|
10
10
|
}) => void;
|
|
11
11
|
} | null>;
|
|
12
12
|
export declare const useQRPHDepositContext: () => {
|
|
13
|
-
view: "
|
|
13
|
+
view: "form" | "qrCode";
|
|
14
14
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
15
15
|
verify: () => void;
|
|
16
16
|
reset: () => void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Deposit } from '@opexa/portal-sdk-core';
|
|
2
2
|
export type UseQRPHDepositReturn = ReturnType<typeof useQRPHDeposit>;
|
|
3
3
|
export declare function useQRPHDeposit(): {
|
|
4
|
-
view: "
|
|
4
|
+
view: "form" | "qrCode";
|
|
5
5
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
6
6
|
verify: () => void;
|
|
7
7
|
reset: () => void;
|
|
@@ -13,8 +13,9 @@ export function DepositWithdrawalTrigger(props) {
|
|
|
13
13
|
: globalStore.depositWithdrawal.open
|
|
14
14
|
? true
|
|
15
15
|
: props.disabled;
|
|
16
|
-
return (_jsx(ark.button, { type: "button", ...props, onClick: async (e) => {
|
|
16
|
+
return (_jsx(ark.button, { type: "button", "aria-label": "Deposit or Withdraw", "data-state": globalStore.depositWithdrawal.open ? 'open' : 'closed', ...props, disabled: disabled, onClick: async (e) => {
|
|
17
17
|
props.onClick?.(e);
|
|
18
|
+
globalStore.depositWithdrawal.setTab('DEPOSIT');
|
|
18
19
|
globalStore.depositWithdrawal.setOpen(true);
|
|
19
|
-
}
|
|
20
|
+
} }));
|
|
20
21
|
}
|
|
@@ -16,10 +16,16 @@ export function GameLaunchTrigger(props) {
|
|
|
16
16
|
: globalStore.gameLaunch.details.status !== 'WAITING'
|
|
17
17
|
? true
|
|
18
18
|
: props.disabled;
|
|
19
|
-
return (_jsx(ark.button, { type: "button",
|
|
20
|
-
|
|
19
|
+
return (_jsx(ark.button, { type: "button", "aria-label": `Play ${props.game.name}`, "data-state": sessionQuery.data?.status === 'unauthenticated'
|
|
20
|
+
? globalStore.signIn.open
|
|
21
|
+
? 'open'
|
|
22
|
+
: 'closed'
|
|
23
|
+
: globalStore.gameLaunch.details.status === 'WAITING'
|
|
24
|
+
? 'closed'
|
|
25
|
+
: 'open', ...props, disabled: disabled, onClick: async (e) => {
|
|
21
26
|
if (sessionQuery.data?.status === 'unauthenticated') {
|
|
22
|
-
|
|
27
|
+
globalStore.signIn.setOpen(true);
|
|
28
|
+
return props.onClick?.(e);
|
|
23
29
|
}
|
|
24
30
|
globalStore.gameLaunch.setDetails({
|
|
25
31
|
game: props.game,
|
|
@@ -44,11 +50,8 @@ export function GameLaunchTrigger(props) {
|
|
|
44
50
|
description: error instanceof Error ? error.message : 'Failed to launch game',
|
|
45
51
|
});
|
|
46
52
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
: globalStore.gameLaunch.details.status === 'WAITING'
|
|
52
|
-
? 'closed'
|
|
53
|
-
: 'open' }));
|
|
53
|
+
finally {
|
|
54
|
+
return props.onClick?.(e);
|
|
55
|
+
}
|
|
56
|
+
} }));
|
|
54
57
|
}
|
|
@@ -17,7 +17,7 @@ export function Game(props) {
|
|
|
17
17
|
const markGameAsFavoriteMutation = useMarkGameAsFavoriteMutation();
|
|
18
18
|
const unmarkGameAsFavoriteMutation = useUnmarkGameAsFavoriteMutation();
|
|
19
19
|
const markedAsFavorite = favoriteGames.some((favoriteGame) => favoriteGame.id === game.id);
|
|
20
|
-
return (_jsxs(GameLaunchTrigger, { game: game, className: "relative block w-full shadow-sm", children: [props.badge === 'new' && (_jsx(BadgeNew, { className: "absolute left-0 top-0 size-[3.75rem]" })), props.badge === 'top' && (_jsx(BadgeTop, { className: "absolute left-0 top-0 size-[3.75rem]" })), props.badge === 'popular' && (_jsx(BadgePopular, { className: "absolute left-0 top-0 size-[3.75rem]" })), session?.status === 'authenticated' && (_jsx("div", { role: "button", onClick: (e) => {
|
|
20
|
+
return (_jsxs(GameLaunchTrigger, { game: game, className: "animate-scale-in relative block w-full shadow-sm", children: [props.badge === 'new' && (_jsx(BadgeNew, { className: "absolute left-0 top-0 size-[3.75rem]" })), props.badge === 'top' && (_jsx(BadgeTop, { className: "absolute left-0 top-0 size-[3.75rem]" })), props.badge === 'popular' && (_jsx(BadgePopular, { className: "absolute left-0 top-0 size-[3.75rem]" })), session?.status === 'authenticated' && (_jsx("div", { role: "button", onClick: (e) => {
|
|
21
21
|
e.preventDefault();
|
|
22
22
|
e.stopPropagation();
|
|
23
23
|
if (markGameAsFavoriteMutation.isPending)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { GamesInput } from '@opexa/portal-sdk-core';
|
|
2
2
|
interface GamesSearchProps {
|
|
3
|
-
|
|
3
|
+
first?: number;
|
|
4
|
+
filter?: GamesInput['filter'];
|
|
5
|
+
className?: string;
|
|
4
6
|
}
|
|
5
7
|
export declare function GamesSearch(props: GamesSearchProps): import("react/jsx-runtime").JSX.Element;
|
|
6
8
|
export {};
|
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { Portal } from '@ark-ui/react';
|
|
4
|
-
import Image
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import providerHacksaw from '../../images/hacksaw-gaming.png';
|
|
10
|
-
import { Button, Dialog, Field, IconButton, Presence } from '../../ui/index.js';
|
|
3
|
+
import { createListCollection, Portal } from '@ark-ui/react';
|
|
4
|
+
import Image from 'next/image';
|
|
5
|
+
import { useState } from 'react';
|
|
6
|
+
import { useGamesQuery } from '../../client/hooks/index.js';
|
|
7
|
+
import { SearchLgIcon } from '../../icons/index.js';
|
|
8
|
+
import { Button, Combobox, Presence } from '../../ui/index.js';
|
|
11
9
|
import { GameLaunchTrigger } from '../GameLaunch/index.js';
|
|
12
10
|
export function GamesSearch(props) {
|
|
13
|
-
const globalStore = useGlobalStore(useShallow((ctx) => ({
|
|
14
|
-
gamesSearch: ctx.gamesSearch,
|
|
15
|
-
})));
|
|
16
|
-
const inputRef = useRef(null);
|
|
17
11
|
const [search, setSearch] = useState('');
|
|
18
12
|
const gamesQuery = useGamesQuery({
|
|
19
|
-
first: 18,
|
|
13
|
+
first: props.first ?? 18,
|
|
14
|
+
filter: props.filter,
|
|
20
15
|
search,
|
|
21
16
|
}, {
|
|
22
17
|
enabled: search.length >= 3,
|
|
@@ -24,14 +19,26 @@ export function GamesSearch(props) {
|
|
|
24
19
|
const games = gamesQuery.data?.pages
|
|
25
20
|
.map((page) => page.edges.map((edge) => edge.node))
|
|
26
21
|
.flat() ?? [];
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
22
|
+
const collection = createListCollection({
|
|
23
|
+
items: games,
|
|
24
|
+
itemToValue: (item) => item.id,
|
|
25
|
+
itemToString: (item) => item.name,
|
|
26
|
+
});
|
|
27
|
+
return (_jsx("div", { className: props.className, children: _jsxs(Combobox.Root, { collection: collection, positioning: {
|
|
28
|
+
sameWidth: true,
|
|
29
|
+
placement: 'bottom',
|
|
30
|
+
}, inputValue: search, onInputValueChange: (details) => {
|
|
31
|
+
setSearch(details.inputValue);
|
|
32
|
+
}, selectionBehavior: "preserve", allowCustomValue: true, children: [_jsxs(Combobox.Control, { children: [_jsx(Combobox.Input, {}), _jsx(Combobox.Context, { children: (api) => {
|
|
33
|
+
if (api.inputValue.length <= 0)
|
|
34
|
+
return null;
|
|
35
|
+
return (_jsx("span", { className: "text-text-secondary-700 px-3.5 font-semibold", tabIndex: 0, onClick: () => {
|
|
36
|
+
api.setInputValue('');
|
|
37
|
+
api.focus();
|
|
38
|
+
}, children: "Clear" }));
|
|
39
|
+
} })] }), _jsx(Portal, { children: _jsx(Combobox.Positioner, { children: search.trim().length > 0 && (_jsx(Combobox.Content, { className: "max-h-[33.25rem] overflow-y-auto p-0", children: search.length >= 1 && search.length <= 2 ? (_jsx(Alert, { message: "Search requires at least 3 characters." })) : (_jsxs(_Fragment, { children: [games.length <= 0 && _jsx(Alert, { message: "No results found" }), games.length > 0 && (_jsxs("div", { className: "p-xl", children: [_jsx(Combobox.Context, { children: (api) => (_jsx("div", { className: "grid grid-cols-9 gap-3.5", children: games.map((game) => (_jsxs(GameLaunchTrigger, { game: game, onClick: () => {
|
|
40
|
+
api.setOpen(false);
|
|
41
|
+
}, className: "block w-full shadow-sm", children: [_jsx(Image, { src: game.image, alt: "", width: 200, height: 200, priority: true, className: "aspect-square w-full rounded-t-md object-cover" }), _jsx("span", { className: "bg-bg-tertiary text-text-primary-brand block w-full truncate rounded-b-md px-2 py-2.5 text-center text-xs font-semibold", children: game.name })] }, game.id))) })) }), _jsx(Presence, { present: gamesQuery.hasNextPage, children: _jsx(Button, { variant: "outline", className: "mx-auto mt-4xl w-fit", onClick: () => gamesQuery.fetchNextPage(), children: "Load More" }) })] }))] })) })) }) })] }) }));
|
|
35
42
|
}
|
|
36
43
|
function Alert({ message }) {
|
|
37
44
|
return (_jsxs("div", { className: "py-lg", role: "alert", "aria-live": "polite", children: [_jsx("div", { className: "bg-bg-secondary shadow-xs border-border-primary mx-auto flex size-12 items-center justify-center rounded-lg border", children: _jsx(SearchLgIcon, { className: "text-text-secondary-700 size-6" }) }), _jsx("p", { className: "text-text-secondary-700 mt-4 text-center", children: message })] }));
|
|
@@ -7,8 +7,8 @@ export function MessagesTrigger(props) {
|
|
|
7
7
|
const globalStore = useGlobalStore(useShallow((ctx) => ({
|
|
8
8
|
messages: ctx.messages,
|
|
9
9
|
})));
|
|
10
|
-
return (_jsx(ark.button, { type: "button", ...props, onClick: (e) => {
|
|
10
|
+
return (_jsx(ark.button, { type: "button", "aria-label": "Toggle messages panel", "data-state": globalStore.messages.open ? 'open' : 'closed', ...props, onClick: (e) => {
|
|
11
11
|
globalStore.messages.setOpen(!globalStore.messages.open);
|
|
12
12
|
return props.onClick?.(e);
|
|
13
|
-
}
|
|
13
|
+
} }));
|
|
14
14
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
type TimeLeft = {
|
|
3
|
+
days: number;
|
|
4
|
+
hours: number;
|
|
5
|
+
minutes: number;
|
|
6
|
+
seconds: number;
|
|
7
|
+
};
|
|
8
|
+
interface CountdownTimerProps {
|
|
9
|
+
startDateTime?: string;
|
|
10
|
+
endDateTime?: string;
|
|
11
|
+
renderAction: (timeLeft: TimeLeft) => ReactNode;
|
|
12
|
+
onEnd?: () => void;
|
|
13
|
+
}
|
|
14
|
+
export default function CountdownTimer({ startDateTime, endDateTime, renderAction, onEnd, }: CountdownTimerProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { differenceInSeconds, parseISO } from 'date-fns';
|
|
4
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
5
|
+
export default function CountdownTimer({ startDateTime, endDateTime, renderAction, onEnd, }) {
|
|
6
|
+
const calculateTimeLeft = useCallback(() => {
|
|
7
|
+
const start = startDateTime ? parseISO(startDateTime) : new Date();
|
|
8
|
+
const end = endDateTime ? parseISO(endDateTime) : new Date();
|
|
9
|
+
const totalSeconds = Math.max(differenceInSeconds(end, start), 0);
|
|
10
|
+
const days = Math.floor(totalSeconds / (60 * 60 * 24));
|
|
11
|
+
const hours = Math.floor((totalSeconds % (60 * 60 * 24)) / (60 * 60));
|
|
12
|
+
const minutes = Math.floor((totalSeconds % (60 * 60)) / 60);
|
|
13
|
+
const seconds = totalSeconds % 60;
|
|
14
|
+
return { days, hours, minutes, seconds };
|
|
15
|
+
}, [startDateTime, endDateTime]);
|
|
16
|
+
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const interval = setInterval(() => {
|
|
19
|
+
const newTimeLeft = calculateTimeLeft();
|
|
20
|
+
setTimeLeft(newTimeLeft);
|
|
21
|
+
const isZero = newTimeLeft.days === 0 &&
|
|
22
|
+
newTimeLeft.hours === 0 &&
|
|
23
|
+
newTimeLeft.minutes === 0 &&
|
|
24
|
+
newTimeLeft.seconds === 0;
|
|
25
|
+
if (isZero) {
|
|
26
|
+
clearInterval(interval);
|
|
27
|
+
onEnd?.();
|
|
28
|
+
}
|
|
29
|
+
}, 1000);
|
|
30
|
+
return () => clearInterval(interval);
|
|
31
|
+
}, [calculateTimeLeft, onEnd]);
|
|
32
|
+
return _jsx(_Fragment, { children: renderAction(timeLeft) });
|
|
33
|
+
}
|
|
@@ -2,54 +2,69 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useState } from 'react';
|
|
4
4
|
import { twMerge } from 'tailwind-merge';
|
|
5
|
-
import { CalendarIcon, ClockStopWatchIcon, InfoCircleIcon, } from '../../../icons/index.js';
|
|
5
|
+
import { CalendarIcon, CheckIcon, ClockStopWatchIcon, InfoCircleIcon, } from '../../../icons/index.js';
|
|
6
6
|
import { Button } from '../../../ui/index.js';
|
|
7
7
|
import { DailyCheckInQuestModal } from './DailyCheckInQuestModal.js';
|
|
8
|
-
|
|
8
|
+
import CountdownTimer from '../CountdownTimer.js';
|
|
9
|
+
import { addDays, isEqual, startOfDay } from 'date-fns';
|
|
10
|
+
import { getAvailableQuestsQueryKey, getQueryClient } from '../../../utils/index.js';
|
|
11
|
+
import { useCheckInDailyCheckInQuestMutation } from '../../../client/hooks/index.js';
|
|
12
|
+
import { toaster } from '../../../client/utils/index.js';
|
|
13
|
+
export default function DailyCheckInQuest({ quest }) {
|
|
14
|
+
const queryClient = getQueryClient();
|
|
9
15
|
const [showRules, setShowRules] = useState(false);
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
const [isExpired, setIsExpired] = useState(false);
|
|
17
|
+
const { name, description, status, lastCheckInDate, progressPercentage, checkInStreak, thirdDayBonusAmount, sixthDayBonusAmount, seventhDayBonusAmount, endDateTime, id, } = quest;
|
|
18
|
+
const today = startOfDay(new Date());
|
|
19
|
+
const hasCheckedInToday = lastCheckInDate
|
|
20
|
+
? isEqual(today, startOfDay(new Date(lastCheckInDate)))
|
|
21
|
+
: false;
|
|
22
|
+
const checkedInRewards = {
|
|
23
|
+
3: thirdDayBonusAmount,
|
|
24
|
+
6: sixthDayBonusAmount,
|
|
25
|
+
7: seventhDayBonusAmount,
|
|
26
|
+
};
|
|
27
|
+
const dailyCheckedInData = Array.from({ length: 7 }, (_, i) => {
|
|
28
|
+
const day = i + 1;
|
|
29
|
+
return {
|
|
30
|
+
day,
|
|
31
|
+
reward: checkedInRewards[day] ?? 0,
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
const { mutate } = useCheckInDailyCheckInQuestMutation({
|
|
35
|
+
onSuccess() {
|
|
36
|
+
toaster.success({
|
|
37
|
+
title: 'Check-in successful 🎉',
|
|
38
|
+
description: 'You’ve successfully checked in for today! Keep it up to maintain your streak!',
|
|
39
|
+
});
|
|
40
|
+
queryClient.invalidateQueries({
|
|
41
|
+
queryKey: getAvailableQuestsQueryKey(),
|
|
42
|
+
});
|
|
15
43
|
},
|
|
16
|
-
{
|
|
17
|
-
|
|
18
|
-
|
|
44
|
+
onError(e) {
|
|
45
|
+
toaster.error({
|
|
46
|
+
title: 'Check-in successful 🎉',
|
|
47
|
+
description: e.message ?? 'Check-In Failed',
|
|
48
|
+
});
|
|
19
49
|
},
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
reward: 5,
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
day: 4,
|
|
26
|
-
reward: 0,
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
day: 5,
|
|
30
|
-
reward: 10,
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
day: 6,
|
|
34
|
-
reward: 0,
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
day: 7,
|
|
38
|
-
reward: 20,
|
|
39
|
-
},
|
|
40
|
-
];
|
|
41
|
-
const checkedInDays = 4;
|
|
42
|
-
const totalDays = 7;
|
|
43
|
-
const progressPercent = (checkedInDays / totalDays) * 100;
|
|
50
|
+
});
|
|
51
|
+
const handleCheckIn = async () => mutate(id);
|
|
44
52
|
return (_jsxs(_Fragment, { children: [_jsx(DailyCheckInQuestModal, { modalState: {
|
|
45
53
|
isOpen: showRules,
|
|
46
54
|
setIsOpen: setShowRules,
|
|
47
|
-
} }), _jsxs("div", { className: "border-border-primary bg-bg-tertiary flex h-full w-full min-w-[343px] flex-col space-y-6 rounded-2xl border px-4 pb-6 pt-5", children: [_jsxs("div", { className: "flex flex-col space-y-2", children: [_jsxs("div", { className: "flex max-h-7.5 items-start justify-between", children: [_jsxs("div", { className: "border-utility-brand-200 bg-utility-brand-50 rounded-xs flex items-center space-x-1 border py-1 pl-2 pr-2.5", children: [_jsx(ClockStopWatchIcon, { className: "text-brand-400" }),
|
|
55
|
+
} }), _jsxs("div", { className: "border-border-primary bg-bg-tertiary flex h-full w-full min-w-[343px] flex-col space-y-6 rounded-2xl border px-4 pb-6 pt-5", children: [_jsxs("div", { className: "flex flex-col space-y-2", children: [_jsxs("div", { className: "flex max-h-7.5 items-start justify-between", children: [_jsx(CountdownTimer, { endDateTime: endDateTime, renderAction: (timeLeft) => (_jsxs("div", { className: "border-utility-brand-200 bg-utility-brand-50 rounded-xs flex items-center space-x-1 border py-1 pl-2 pr-2.5", children: [_jsx(ClockStopWatchIcon, { className: "text-brand-400" }), _jsxs("p", { className: "text-utility-brand-700 text-sm font-medium", children: [timeLeft.days, "d:", timeLeft.hours, "h:", timeLeft.minutes, "m:", timeLeft.seconds, "s"] })] })), onEnd: () => setIsExpired(true) }), _jsx("div", { role: "button", className: "bg-bg-primary border-border-secondary cursor-pointer rounded-md border p-2", onClick: () => setShowRules((prev) => !prev), children: _jsx(InfoCircleIcon, { className: "text-text-disabled" }) })] }), _jsx("p", { className: "text-xl font-semibold", children: name }), _jsx("p", { className: "text-text-secondary-700 text-wrap text-sm font-normal", dangerouslySetInnerHTML: { __html: description } })] }), _jsxs("div", { className: "flex w-full flex-col space-y-2", children: [_jsx("div", { className: "grid grid-cols-7", children: dailyCheckedInData.map((item) => {
|
|
48
56
|
const reward = item.reward ? `+₱${item.reward}` : '-';
|
|
49
|
-
return (_jsx("div", { className: twMerge('flex items-center justify-center', item.day <=
|
|
57
|
+
return (_jsx("div", { className: twMerge('flex items-center justify-center', item.day <= (checkInStreak || 0)
|
|
50
58
|
? 'text-brand-400'
|
|
51
59
|
: 'text-text-secondary-700'), children: _jsx("p", { children: reward }) }, item.day));
|
|
52
|
-
}) }), _jsx("div", { className: "bg-bg-primary h-2 w-full overflow-hidden rounded-full", children: _jsx("div", { className: "bg-utility-brand-600 h-full rounded-full transition-all duration-300", style: { width: `${
|
|
60
|
+
}) }), _jsx("div", { className: "bg-bg-primary h-2 w-full overflow-hidden rounded-full", children: _jsx("div", { className: "bg-utility-brand-600 h-full rounded-full transition-all duration-300", style: { width: `${progressPercentage}%` } }) }), _jsx("div", { className: "grid grid-cols-7", children: dailyCheckedInData.map((item) => (_jsx("div", { className: "flex items-center justify-center", children: _jsx(CalendarWithDayNumber, { day: item.day, currentCheckedInDays: checkInStreak || 0 }, item.day) }, item.day))) })] }), _jsx(Button, { onClick: handleCheckIn, className: "disabled:bg-bg-primary disabled:text-text-disabled", disabled: isExpired ||
|
|
61
|
+
status === 'COMPLETED' ||
|
|
62
|
+
status === 'FAILED' ||
|
|
63
|
+
hasCheckedInToday, children: hasCheckedInToday && status === 'IN_PROGRESS' ? (_jsx(CountdownTimer, { endDateTime: startOfDay(addDays(new Date(), 1)).toISOString(), renderAction: (timeLeft) => (_jsxs("div", { className: "flex items-center space-x-0.5", children: [_jsx(CheckIcon, {}), _jsxs("p", { children: [timeLeft.hours, "h:", timeLeft.minutes, "m:", timeLeft.seconds, "s"] })] })), onEnd: () => {
|
|
64
|
+
queryClient.invalidateQueries({
|
|
65
|
+
queryKey: getAvailableQuestsQueryKey(),
|
|
66
|
+
});
|
|
67
|
+
} })) : ('Check-In') })] })] }));
|
|
53
68
|
}
|
|
54
69
|
function CalendarWithDayNumber({ day, currentCheckedInDays, }) {
|
|
55
70
|
return (_jsxs("div", { className: twMerge('group relative h-fit w-fit', day <= currentCheckedInDays
|
|
@@ -1,6 +1,30 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import Image from 'next/image';
|
|
4
|
+
import { useAvailableQuestsQuery } from '../../client/hooks/index.js';
|
|
5
|
+
import { SpinnerIcon } from '../../icons/index.js';
|
|
6
|
+
import closeChest from '../../images/close-chest.png';
|
|
2
7
|
import DailyCheckInQuest from './DailyCheckInQuest/DailyCheckInQuest.js';
|
|
3
8
|
import WageringQuest from './WageringQuest/WageringQuest.js';
|
|
9
|
+
function OnboardingQuest(props) {
|
|
10
|
+
console.log('OnboardingQuest not implemented', props.quest);
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
const QUEST_COMPONENT_MAP = {
|
|
14
|
+
DAILY_CHECKIN: DailyCheckInQuest,
|
|
15
|
+
ONBOARDING: OnboardingQuest,
|
|
16
|
+
WAGERING: WageringQuest,
|
|
17
|
+
};
|
|
4
18
|
export function Quests() {
|
|
5
|
-
|
|
19
|
+
const query = useAvailableQuestsQuery();
|
|
20
|
+
if (query.isLoading) {
|
|
21
|
+
return (_jsxs("div", { className: "mt-6 flex w-full flex-col px-4 lg:px-0", children: [_jsx("h3", { className: "mb-3 text-lg", children: "Quests" }), _jsx(SpinnerIcon, { className: "mx-auto size-5 h-[50vh]" })] }));
|
|
22
|
+
}
|
|
23
|
+
if (!query.data?.length) {
|
|
24
|
+
return (_jsxs("div", { className: "mt-6 flex w-full flex-col px-4 lg:px-0", children: [_jsx("h3", { className: "mb-3 text-lg", children: "Quests" }), _jsxs("div", { className: "mt-11 flex flex-col items-center justify-center", children: [_jsx(Image, { src: closeChest, width: 100, height: 100, alt: "No Quests Available", className: "mix-blend-luminosity", quality: 100 }), _jsx("div", { className: "text-text-primary-900 mt-4 text-base font-semibold", children: "Quests" }), _jsx("div", { className: "text-text-tertiary-600 mt-1 text-center text-sm", children: "No available quests. Please check back later!" })] })] }));
|
|
25
|
+
}
|
|
26
|
+
return (_jsxs("div", { className: "mt-6 flex w-full flex-col px-4 lg:px-0", children: [_jsx("h3", { className: "mb-3 text-lg", children: "Quests" }), _jsx("div", { className: "grid grid-cols-1 gap-3xl lg:grid-cols-3", children: query.data.map((quest, index) => {
|
|
27
|
+
const QuestComponent = QUEST_COMPONENT_MAP[quest.type];
|
|
28
|
+
return _jsx(QuestComponent, { quest: quest }, index);
|
|
29
|
+
}) })] }));
|
|
6
30
|
}
|