@opexa/portal-components 0.0.50 → 0.0.52

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 (45) hide show
  1. package/dist/client/hooks/useGlobalStore.d.ts +3 -3
  2. package/dist/client/hooks/useGlobalStore.js +3 -3
  3. package/dist/components/Account/AccountTrigger.d.ts +6 -0
  4. package/dist/components/Account/AccountTrigger.js +13 -0
  5. package/dist/components/Account/index.d.ts +1 -0
  6. package/dist/components/Account/index.js +1 -0
  7. package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/OnlineBankDepositContext.d.ts +2 -2
  8. package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/useOnlineBankDeposit.d.ts +1 -1
  9. package/dist/components/DepositWithdrawal/Deposit/QRPHDeposit/QRPHDepositContext.d.ts +2 -2
  10. package/dist/components/DepositWithdrawal/Deposit/QRPHDeposit/useQRPHDeposit.d.ts +1 -1
  11. package/dist/components/DepositWithdrawal/DepositWithdrawalTrigger.js +3 -2
  12. package/dist/components/GameLaunch/GameLaunchTrigger.js +13 -10
  13. package/dist/components/Games/Game.js +1 -1
  14. package/dist/components/GamesSearch/GamesSearch.d.ts +4 -2
  15. package/dist/components/GamesSearch/GamesSearch.js +28 -21
  16. package/dist/components/GamesSearch/index.d.ts +0 -1
  17. package/dist/components/GamesSearch/index.js +0 -1
  18. package/dist/components/Messages/MessagesTrigger.js +2 -2
  19. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuest.d.ts +1 -1
  20. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuest.js +9 -9
  21. package/dist/components/Quests/DailyCheckInQuest/DailyCheckInQuestModal.js +1 -1
  22. package/dist/components/Quests/OnboardingQuest/OnboardingQuest.d.ts +4 -0
  23. package/dist/components/Quests/OnboardingQuest/OnboardingQuest.js +4 -0
  24. package/dist/components/Quests/Quests.d.ts +6 -1
  25. package/dist/components/Quests/Quests.js +7 -10
  26. package/dist/components/Quests/WageringQuest/WageringQuest.d.ts +4 -1
  27. package/dist/components/Quests/WageringQuest/WageringQuest.js +10 -7
  28. package/dist/components/Quests/WageringQuest/WageringQuestModal.d.ts +1 -0
  29. package/dist/components/Quests/WageringQuest/WageringQuestModal.js +1 -1
  30. package/dist/components/Search/Search.d.ts +6 -0
  31. package/dist/components/Search/Search.js +38 -0
  32. package/dist/components/Search/SearchTrigger.d.ts +5 -0
  33. package/dist/components/Search/SearchTrigger.js +14 -0
  34. package/dist/components/Search/index.d.ts +2 -0
  35. package/dist/components/Search/index.js +2 -0
  36. package/dist/components/SignIn/SignInTrigger.js +2 -2
  37. package/dist/components/SignUp/SignUpTrigger.js +2 -2
  38. package/dist/components/index.d.ts +1 -0
  39. package/dist/components/index.js +1 -0
  40. package/dist/styles/theme.css +24 -0
  41. package/dist/tsconfig.build.tsbuildinfo +1 -1
  42. package/dist/ui/Combobox/Combobox.d.ts +840 -798
  43. package/dist/ui/Combobox/combobox.recipe.d.ts +54 -51
  44. package/dist/ui/Combobox/combobox.recipe.js +59 -1
  45. package/package.json +1 -1
@@ -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
- gamesSearch: GamesSearchStore;
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
- gamesSearch: {
129
+ search: {
130
130
  open: false,
131
131
  setOpen(open) {
132
132
  set((prev) => ({
133
- gamesSearch: {
134
- ...prev.gamesSearch,
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
+ }
@@ -1 +1,2 @@
1
1
  export * from './Account';
2
+ export * from './AccountTrigger';
@@ -1 +1,2 @@
1
1
  export * from './Account.js';
2
+ export * from './AccountTrigger.js';
@@ -1,5 +1,5 @@
1
1
  export declare const OnlineBankDepositContext: import("react").Context<{
2
- view: "vca" | "form";
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: "vca" | "form";
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;
@@ -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: "vca" | "form";
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: "qrCode" | "form";
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: "qrCode" | "form";
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: "qrCode" | "form";
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
- }, disabled: disabled, "data-state": globalStore.depositWithdrawal.open ? 'open' : 'closed' }));
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", ...props, onClick: async (e) => {
20
- props.onClick?.(e);
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
- return globalStore.signIn.setOpen(true);
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
- }, disabled: disabled, "data-state": sessionQuery.data?.status === 'unauthenticated'
48
- ? globalStore.signIn.open
49
- ? 'open'
50
- : 'closed'
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 { type ImageProps } from 'next/image';
1
+ import type { GamesInput } from '@opexa/portal-sdk-core';
2
2
  interface GamesSearchProps {
3
- logo: ImageProps['src'];
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, {} from 'next/image';
5
- import { useRef, useState } from 'react';
6
- import { useShallow } from 'zustand/shallow';
7
- import { useGamesQuery, useGlobalStore } from '../../client/hooks/index.js';
8
- import { SearchLgIcon, XIcon } from '../../icons/index.js';
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
- return (_jsx(Dialog.Root, { open: globalStore.gamesSearch.open, onOpenChange: (details) => globalStore.gamesSearch.setOpen(details.open), lazyMount: true, unmountOnExit: true, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, {}), _jsx(Dialog.Positioner, { children: _jsxs(Dialog.Content, { className: "bg-bg-primary lg:min-h-auto mx-auto min-h-full w-full pt-xl lg:mt-[132px] lg:max-w-[1136px] lg:bg-unset lg:pt-0", children: [_jsx(Dialog.Context, { children: (api) => (_jsxs("div", { className: "flex items-center justify-between px-4 lg:hidden", children: [_jsx(Image, { src: props.logo, alt: "", width: 200, height: 40, className: "h-8 w-auto" }), _jsx(IconButton, { size: "sm", colorScheme: "gray", onClick: () => api.setOpen(false), children: _jsx(XIcon, { className: "text-text-quinary size-6" }) })] })) }), _jsx("div", { className: "flex justify-end", children: _jsx(Dialog.Context, { children: (api) => (_jsx("button", { type: "button", onClick: () => api.setOpen(false), className: "hidden size-9 items-center justify-center rounded-md bg-white/20 lg:flex", children: _jsx(XIcon, { className: "size-5 text-white" }) })) }) }), _jsx("div", { className: "mt-2xl px-4 lg:mt-xl lg:px-0", children: _jsxs("div", { className: "relative", children: [_jsx(SearchLgIcon, { className: "text-text-quinary pointer-events-none absolute left-3.5 top-1/2 size-5 -translate-y-1/2" }), _jsx(Field.Input, { ref: inputRef, type: "search", value: search, onChange: (e) => {
28
- setSearch(e.target.value);
29
- }, className: "pl-10 pr-16", placeholder: "Search", autoComplete: "off" }), _jsx(Presence, { present: search.length > 0, asChild: true, lazyMount: true, children: _jsx("button", { type: "button", className: "text-text-secondary-700 absolute right-3.5 top-1/2 -translate-y-1/2 font-semibold", onClick: () => {
30
- setSearch('');
31
- inputRef.current?.focus();
32
- }, children: "Clear" }) })] }) }), _jsx("div", { className: "lg:bg-bg-primary lg:border-border-primary mt-2xl p-xl pb-3xl lg:mt-2 lg:rounded-xl lg:border", children: search.length <= 0 ? (_jsx(Alert, { message: "Search for your favorite game or provider." })) : 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(_Fragment, { children: [_jsx("h2", { className: "text-lg font-semibold", children: "Providers" }), _jsx("div", { className: "mb-3xl mt-3.5 grid grid-cols-3 gap-1.5 lg:grid-cols-9 lg:gap-3.5", children: _jsx("div", { className: "bg-gray-800 flex h-14 w-full items-center rounded-md", children: _jsx(Image, { src: providerHacksaw, alt: "", width: 100, height: 50, className: "mx-auto h-auto w-full" }) }) }), _jsx("h2", { className: "text-lg font-semibold", children: "Games" }), _jsx("div", { className: "mt-3.5 grid grid-cols-3 gap-1.5 lg:grid-cols-9 lg:gap-3.5", children: games.map((game) => (_jsxs(GameLaunchTrigger, { game: game, className: "block w-full shadow-sm", onClick: () => {
33
- globalStore.gamesSearch.setOpen(false);
34
- }, 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-12 w-fit", onClick: () => gamesQuery.fetchNextPage(), children: "Load More" }) })] }))] })) })] }) })] }) }));
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, { placeholder: "Search" }), _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 })] }));
@@ -1,2 +1 @@
1
1
  export * from './GamesSearch';
2
- export * from './GamesSearchTrigger';
@@ -1,2 +1 @@
1
1
  export * from './GamesSearch.js';
2
- export * from './GamesSearchTrigger.js';
@@ -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
- }, "data-state": globalStore.messages.open ? 'open' : 'closed' }));
13
+ } }));
14
14
  }
@@ -1,4 +1,4 @@
1
1
  import type { Quest } from '@opexa/portal-sdk-core';
2
- export default function DailyCheckInQuest({ quest }: {
2
+ export declare function DailyCheckInQuest({ quest }: {
3
3
  quest: Quest;
4
4
  }): import("react/jsx-runtime").JSX.Element;
@@ -1,16 +1,16 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { addDays, isEqual, startOfDay } from 'date-fns';
3
4
  import { useState } from 'react';
4
5
  import { twMerge } from 'tailwind-merge';
5
- import { CalendarIcon, CheckIcon, ClockStopWatchIcon, InfoCircleIcon, } from '../../../icons/index.js';
6
- import { Button } from '../../../ui/index.js';
7
- import { DailyCheckInQuestModal } from './DailyCheckInQuestModal.js';
8
- import CountdownTimer from '../CountdownTimer.js';
9
- import { addDays, isEqual, startOfDay } from 'date-fns';
10
- import { getAvailableQuestsQueryKey, getQueryClient } from '../../../utils/index.js';
11
6
  import { useCheckInDailyCheckInQuestMutation } from '../../../client/hooks/index.js';
12
7
  import { toaster } from '../../../client/utils/index.js';
13
- export default function DailyCheckInQuest({ quest }) {
8
+ import { CalendarIcon, CheckIcon, ClockStopWatchIcon, InfoCircleIcon, } from '../../../icons/index.js';
9
+ import { Badge, Button } from '../../../ui/index.js';
10
+ import { getAvailableQuestsQueryKey, getQueryClient } from '../../../utils/index.js';
11
+ import CountdownTimer from '../CountdownTimer.js';
12
+ import { DailyCheckInQuestModal } from './DailyCheckInQuestModal.js';
13
+ export function DailyCheckInQuest({ quest }) {
14
14
  const queryClient = getQueryClient();
15
15
  const [showRules, setShowRules] = useState(false);
16
16
  const [isExpired, setIsExpired] = useState(false);
@@ -52,7 +52,7 @@ export default function DailyCheckInQuest({ quest }) {
52
52
  return (_jsxs(_Fragment, { children: [_jsx(DailyCheckInQuestModal, { modalState: {
53
53
  isOpen: showRules,
54
54
  setIsOpen: setShowRules,
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) => {
55
+ } }), _jsxs("div", { className: "border-border-primary bg-bg-tertiary flex h-full w-full flex-col space-y-6 rounded-2xl border px-4 pb-6 pt-5", children: [_jsxs("div", { className: "flex flex-col space-y-2", children: [_jsxs("div", { className: "flex max-h-7.5 items-start justify-between", children: [_jsx(CountdownTimer, { endDateTime: endDateTime, renderAction: (timeLeft) => (_jsxs(Badge.Root, { size: "lg", colorScheme: "brand", round: false, children: [_jsx(Badge.Icon, { children: _jsx(ClockStopWatchIcon, {}) }), _jsxs(Badge.Label, { children: [timeLeft.days, "d:", timeLeft.hours, "h:", timeLeft.minutes, "m:", timeLeft.seconds, "s"] })] })), onEnd: () => setIsExpired(true) }), _jsx("div", { role: "button", className: "bg-bg-primary border-border-secondary flex size-9 cursor-pointer items-center justify-center rounded-md border", onClick: () => setShowRules((prev) => !prev), children: _jsx(InfoCircleIcon, { className: "text-text-disabled size-5" }) })] }), _jsx("p", { className: "text-xl font-semibold", children: name }), _jsx("p", { className: "text-text-secondary-700 text-wrap text-sm font-normal", dangerouslySetInnerHTML: { __html: description } })] }), _jsxs("div", { className: "flex w-full flex-col space-y-2", children: [_jsx("div", { className: "grid grid-cols-7", children: dailyCheckedInData.map((item) => {
56
56
  const reward = item.reward ? `+₱${item.reward}` : '-';
57
57
  return (_jsx("div", { className: twMerge('flex items-center justify-center', item.day <= (checkInStreak || 0)
58
58
  ? 'text-brand-400'
@@ -69,5 +69,5 @@ export default function DailyCheckInQuest({ quest }) {
69
69
  function CalendarWithDayNumber({ day, currentCheckedInDays, }) {
70
70
  return (_jsxs("div", { className: twMerge('group relative h-fit w-fit', day <= currentCheckedInDays
71
71
  ? 'text-brand-400'
72
- : 'text-text-secondary-700'), children: [_jsx(CalendarIcon, {}), _jsx("div", { className: "absolute inset-0 mt-[4px] flex items-center justify-center text-2xs lg:mt-[2px]", children: _jsx("p", { className: "text-center", children: day }) })] }));
72
+ : 'text-text-secondary-700'), children: [_jsx(CalendarIcon, {}), _jsx("div", { className: "absolute inset-0 mt-1 flex items-center justify-center text-2xs lg:mt-[2px]", children: _jsx("p", { className: "text-center", children: day }) })] }));
73
73
  }
@@ -4,5 +4,5 @@ import { Portal } from '@ark-ui/react';
4
4
  import { XIcon } from '../../../icons/index.js';
5
5
  import { Button, Dialog } from '../../../ui/index.js';
6
6
  export function DailyCheckInQuestModal(props) {
7
- return (_jsx(Dialog.Root, { lazyMount: true, unmountOnExit: true, open: props.modalState.isOpen, onOpenChange: ({ open }) => props.modalState.setIsOpen(open), closeOnEscape: false, closeOnInteractOutside: false, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, { className: "!z-[calc(var(--z-dialog)+1)]" }), _jsx(Dialog.Positioner, { className: "!z-[calc(var(--z-dialog)+2)] flex items-center justify-center", children: _jsxs(Dialog.Content, { className: "min-h-auto mx-auto max-w-[343px] rounded-xl px-4 pb-0 pt-5", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsxs("div", { className: "flex flex-col space-y-5", children: [_jsx("p", { className: "text-text-primary-900 text-[18px] font-semibold", children: "Daily Check-In Rules" }), _jsxs("ul", { className: "text-text-tertiary-600 group list-disc text-wrap pl-4 text-sm font-normal", children: [_jsx("li", { children: "Earn rewards just for checking in each day!" }), _jsx("li", { children: "Stay consistent to unlock special rewards on the 3rd, 5th, and 7th day." }), _jsx("li", { children: "Missing a day will reset your streak, starting again from Day 1." }), _jsx("li", { children: "Each check-in unlocks the next one on the following day." }), _jsx("li", { children: "Successfully check in for 7 consecutive days to complete the quest and reset the cycle." })] })] }), _jsx("div", { className: "pb-4 pt-6", children: _jsx(Button, { onClick: () => props.modalState.setIsOpen(false), children: "Ok" }) })] }) })] }) }));
7
+ return (_jsx(Dialog.Root, { lazyMount: true, unmountOnExit: true, open: props.modalState.isOpen, onOpenChange: ({ open }) => props.modalState.setIsOpen(open), closeOnEscape: false, closeOnInteractOutside: false, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, { className: "!z-[calc(var(--z-dialog)+1)]" }), _jsx(Dialog.Positioner, { className: "!z-[calc(var(--z-dialog)+2)] flex items-center justify-center", children: _jsxs(Dialog.Content, { className: "min-h-auto mx-auto max-w-[343px] rounded-xl px-4 pb-0 pt-5", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsxs("div", { className: "flex flex-col space-y-5", children: [_jsx("p", { className: "text-text-primary-900 text-lg font-semibold", children: "Daily Check-In Rules" }), _jsxs("ul", { className: "text-text-tertiary-600 group list-disc text-wrap pl-4 text-sm font-normal", children: [_jsx("li", { children: "Earn rewards just for checking in each day!" }), _jsx("li", { children: "Stay consistent to unlock special rewards on the 3rd, 5th, and 7th day." }), _jsx("li", { children: "Missing a day will reset your streak, starting again from Day 1." }), _jsx("li", { children: "Each check-in unlocks the next one on the following day." }), _jsx("li", { children: "Successfully check in for 7 consecutive days to complete the quest and reset the cycle." })] })] }), _jsx("div", { className: "pb-4 pt-6", children: _jsx(Button, { onClick: () => props.modalState.setIsOpen(false), children: "Ok" }) })] }) })] }) }));
8
8
  }
@@ -0,0 +1,4 @@
1
+ import type { Quest } from '@opexa/portal-sdk-core';
2
+ export declare function OnboardingQuest(props: {
3
+ quest: Quest;
4
+ }): null;
@@ -0,0 +1,4 @@
1
+ export function OnboardingQuest(props) {
2
+ console.log('OnboardingQuest not implemented', props.quest);
3
+ return null;
4
+ }
@@ -1 +1,6 @@
1
- export declare function Quests(): import("react/jsx-runtime").JSX.Element;
1
+ export interface QuestsProps {
2
+ /** @default "Quests" */
3
+ heading?: string;
4
+ className?: string;
5
+ }
6
+ export declare function Quests(props: QuestsProps): import("react/jsx-runtime").JSX.Element;
@@ -4,26 +4,23 @@ import Image from 'next/image';
4
4
  import { useAvailableQuestsQuery } from '../../client/hooks/index.js';
5
5
  import { SpinnerIcon } from '../../icons/index.js';
6
6
  import closeChest from '../../images/close-chest.png';
7
- import DailyCheckInQuest from './DailyCheckInQuest/DailyCheckInQuest.js';
8
- import WageringQuest from './WageringQuest/WageringQuest.js';
9
- function OnboardingQuest(props) {
10
- console.log('OnboardingQuest not implemented', props.quest);
11
- return null;
12
- }
7
+ import { DailyCheckInQuest } from './DailyCheckInQuest/DailyCheckInQuest.js';
8
+ import { OnboardingQuest } from './OnboardingQuest/OnboardingQuest.js';
9
+ import { WageringQuest } from './WageringQuest/WageringQuest.js';
13
10
  const QUEST_COMPONENT_MAP = {
14
11
  DAILY_CHECKIN: DailyCheckInQuest,
15
12
  ONBOARDING: OnboardingQuest,
16
13
  WAGERING: WageringQuest,
17
14
  };
18
- export function Quests() {
15
+ export function Quests(props) {
19
16
  const query = useAvailableQuestsQuery();
20
17
  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]" })] }));
18
+ return (_jsxs("div", { className: props.className, children: [_jsx("h3", { className: "mb-3 text-lg font-semibold", children: props.heading ?? 'Quests' }), _jsx(SpinnerIcon, { className: "mx-auto size-5 h-[50vh]" })] }));
22
19
  }
23
20
  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!" })] })] }));
21
+ return (_jsxs("div", { className: props.className, children: [_jsx("h3", { className: "mb-3 text-lg font-semibold", children: props.heading ?? '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: props.heading ?? 'Quests' }), _jsx("div", { className: "text-text-tertiary-600 mt-1 text-center text-sm", children: "No available quests. Please check back later!" })] })] }));
25
22
  }
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) => {
23
+ return (_jsxs("div", { className: props.className, children: [_jsx("h3", { className: "mb-3 text-lg font-semibold", children: props.heading ?? 'Quests' }), _jsx("div", { className: "grid grid-cols-1 gap-3xl lg:grid-cols-3", children: query.data.map((quest, index) => {
27
24
  const QuestComponent = QUEST_COMPONENT_MAP[quest.type];
28
25
  return _jsx(QuestComponent, { quest: quest }, index);
29
26
  }) })] }));
@@ -1 +1,4 @@
1
- export default function WageringQuest(): import("react/jsx-runtime").JSX.Element;
1
+ import type { Quest } from '@opexa/portal-sdk-core';
2
+ export declare function WageringQuest({ quest }: {
3
+ quest: Quest;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -1,16 +1,19 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useState } from 'react';
4
+ import { twMerge } from 'tailwind-merge';
4
5
  import { ClockStopWatchIcon, InfoCircleIcon } from '../../../icons/index.js';
5
- import { Button } from '../../../ui/index.js';
6
+ import { Badge } from '../../../ui/index.js';
7
+ import CountdownTimer from '../CountdownTimer.js';
6
8
  import { WageringQuestModal } from './WageringQuestModal.js';
7
- export default function WageringQuest() {
9
+ export function WageringQuest({ quest }) {
8
10
  const [showRules, setShowRules] = useState(false);
9
- const totalBet = 200;
10
- const targetBet = 500;
11
- const progressPercent = (totalBet / targetBet) * 100;
12
- return (_jsxs(_Fragment, { children: [_jsx(WageringQuestModal, { modalState: {
11
+ const [isExpired, setIsExpired] = useState(false);
12
+ const { progressPercentage, turnover, targetTurnover, name, description, endDateTime, bonus, status, } = quest;
13
+ return (_jsxs(_Fragment, { children: [_jsx(WageringQuestModal, { questName: name, modalState: {
13
14
  isOpen: showRules,
14
15
  setIsOpen: setShowRules,
15
- } }), _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" }), _jsx("p", { className: "text-utility-brand-700 text-sm font-medium", children: "6d:10h:11m:10s" })] }), _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: "Slots - total bet of \u20B1500" }), _jsx("p", { className: "text-text-secondary-700 text-wrap text-sm font-normal", children: "Play any slot game and place a total of \u20B1500 in bets to claim your reward!" })] }), _jsxs("div", { className: "flex w-full flex-col space-y-2", children: [_jsxs("div", { className: "text-text-primary-brand group flex items-center justify-between", children: [_jsxs("p", { children: ["Progress ", progressPercent, "%"] }), _jsxs("p", { children: [totalBet, _jsxs("span", { className: "text-text-quarterary-brand", children: ["/", targetBet] })] })] }), _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: `${progressPercent}%` } }) })] }), _jsx("div", { className: "flex h-full items-end", children: _jsx(Button, { variant: "solid", className: "bg-button-secondary-bg border-bg-primary-hover border text-white", children: _jsxs("p", { children: ["Complete to get ", _jsx("span", { className: "text-brand-400", children: "\u20B150" }), " bonus!"] }) }) })] })] }));
16
+ } }), _jsxs("div", { className: "border-border-primary bg-bg-tertiary flex h-full w-full flex-col space-y-6 rounded-2xl border px-4 pb-6 pt-5", children: [_jsxs("div", { className: "flex flex-col space-y-2", children: [_jsxs("div", { className: "flex max-h-7.5 items-start justify-between", children: [_jsx(CountdownTimer, { endDateTime: endDateTime, renderAction: (timeLeft) => (_jsxs(Badge.Root, { size: "lg", colorScheme: "brand", round: false, children: [_jsx(Badge.Icon, { children: _jsx(ClockStopWatchIcon, {}) }), _jsxs(Badge.Label, { children: [timeLeft.days, "d:", timeLeft.hours, "h:", timeLeft.minutes, "m:", timeLeft.seconds, "s"] })] })), onEnd: () => setIsExpired(true) }), _jsx("div", { role: "button", className: "bg-bg-primary border-border-secondary flex size-9 cursor-pointer items-center justify-center rounded-md border", onClick: () => setShowRules((prev) => !prev), children: _jsx(InfoCircleIcon, { className: "text-text-disabled size-5" }) })] }), _jsx("p", { className: "text-xl font-semibold", children: name }), _jsx("p", { className: "text-text-secondary-700 text-wrap text-sm font-normal", dangerouslySetInnerHTML: { __html: description } })] }), _jsxs("div", { className: "flex w-full flex-col space-y-2", children: [_jsxs("div", { className: "text-text-primary-brand group flex items-center justify-between", children: [_jsxs("p", { children: ["Progress ", parseInt(progressPercentage).toFixed(2), "%"] }), _jsxs("p", { children: [turnover, _jsxs("span", { className: "text-text-quarterary-brand", children: ["/", targetTurnover, " PHP"] })] })] }), _jsx("div", { className: "bg-bg-primary h-2 w-full overflow-hidden rounded-full", children: _jsx("div", { className: "bg-utility-brand-600 h-full rounded-full transition-all duration-300", style: { width: `${progressPercentage}%` } }) })] }), _jsx("div", { className: "flex h-full items-end", children: _jsx("div", { className: "bg-button-secondary-bg border-bg-primary-hover w-full rounded-md border px-3.5 py-2.5 text-center text-white", children: _jsxs("p", { className: twMerge(isExpired || status === 'COMPLETED' || status === 'FAILED'
17
+ ? ['opacity-50 grayscale']
18
+ : ''), children: ["Complete to get ", _jsxs("span", { className: "text-brand-400", children: ["\u20B1", bonus] }), ' ', "bonus!"] }) }) })] })] }));
16
19
  }
@@ -1,4 +1,5 @@
1
1
  interface Props {
2
+ questName: string;
2
3
  modalState: {
3
4
  isOpen: boolean;
4
5
  setIsOpen: (isOpen: boolean) => void;
@@ -4,5 +4,5 @@ import { Portal } from '@ark-ui/react';
4
4
  import { XIcon } from '../../../icons/index.js';
5
5
  import { Button, Dialog } from '../../../ui/index.js';
6
6
  export function WageringQuestModal(props) {
7
- return (_jsx(Dialog.Root, { lazyMount: true, unmountOnExit: true, open: props.modalState.isOpen, onOpenChange: ({ open }) => props.modalState.setIsOpen(open), closeOnEscape: false, closeOnInteractOutside: false, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, { className: "!z-[calc(var(--z-dialog)+1)]" }), _jsx(Dialog.Positioner, { className: "!z-[calc(var(--z-dialog)+2)] flex items-center justify-center", children: _jsxs(Dialog.Content, { className: "min-h-auto mx-auto max-w-[343px] rounded-xl px-4 pb-0 pt-5", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsxs("div", { className: "flex flex-col space-y-5", children: [_jsx("p", { className: "text-text-primary-900 text-[18px] font-semibold", children: "Slots - total bet Rules" }), _jsxs("ul", { className: "text-text-tertiary-600 group list-disc text-wrap pl-4 text-sm font-normal", children: [_jsx("li", { children: "Earn extra rewards just by playing Slots, every bet counts, win or lose!" }), _jsx("li", { children: "Reach the wagering requirement in bets to complete the quest and claim your reward." })] })] }), _jsx("div", { className: "pb-4 pt-6", children: _jsx(Button, { onClick: () => props.modalState.setIsOpen(false), children: "Ok" }) })] }) })] }) }));
7
+ return (_jsx(Dialog.Root, { lazyMount: true, unmountOnExit: true, open: props.modalState.isOpen, onOpenChange: ({ open }) => props.modalState.setIsOpen(open), closeOnEscape: false, closeOnInteractOutside: false, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, { className: "!z-[calc(var(--z-dialog)+1)]" }), _jsx(Dialog.Positioner, { className: "!z-[calc(var(--z-dialog)+2)] flex items-center justify-center", children: _jsxs(Dialog.Content, { className: "min-h-auto mx-auto max-w-[343px] rounded-xl px-4 pb-0 pt-5", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsxs("div", { className: "flex flex-col space-y-5", children: [_jsx("p", { className: "text-text-primary-900 text-lg font-semibold", children: props.questName }), _jsxs("ul", { className: "text-text-tertiary-600 group list-disc text-wrap pl-4 text-sm font-normal", children: [_jsx("li", { children: "Earn extra rewards just by playing Slots, every bet counts, win or lose!" }), _jsx("li", { children: "Reach the wagering requirement in bets to complete the quest and claim your reward." })] })] }), _jsx("div", { className: "pb-4 pt-6", children: _jsx(Button, { onClick: () => props.modalState.setIsOpen(false), children: "Ok" }) })] }) })] }) }));
8
8
  }
@@ -0,0 +1,6 @@
1
+ import { type ImageProps } from 'next/image';
2
+ interface SearchProps {
3
+ logo: ImageProps['src'];
4
+ }
5
+ export declare function Search(props: SearchProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
@@ -0,0 +1,38 @@
1
+ 'use client';
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, {} from 'next/image';
5
+ import { useRef, useState } from 'react';
6
+ import { useShallow } from 'zustand/shallow';
7
+ import { useGamesQuery, useGlobalStore } from '../../client/hooks/index.js';
8
+ import { SearchLgIcon, XIcon } from '../../icons/index.js';
9
+ import providerHacksaw from '../../images/hacksaw-gaming.png';
10
+ import { Button, Dialog, Field, IconButton, Presence } from '../../ui/index.js';
11
+ import { GameLaunchTrigger } from '../GameLaunch/index.js';
12
+ export function Search(props) {
13
+ const globalStore = useGlobalStore(useShallow((ctx) => ({
14
+ search: ctx.search,
15
+ })));
16
+ const inputRef = useRef(null);
17
+ const [search, setSearch] = useState('');
18
+ const gamesQuery = useGamesQuery({
19
+ first: 18,
20
+ search,
21
+ }, {
22
+ enabled: search.length >= 3,
23
+ });
24
+ const games = gamesQuery.data?.pages
25
+ .map((page) => page.edges.map((edge) => edge.node))
26
+ .flat() ?? [];
27
+ return (_jsx(Dialog.Root, { open: globalStore.search.open, onOpenChange: (details) => globalStore.search.setOpen(details.open), lazyMount: true, unmountOnExit: true, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, {}), _jsx(Dialog.Positioner, { children: _jsxs(Dialog.Content, { className: "bg-bg-primary lg:min-h-auto mx-auto min-h-full w-full pt-xl lg:mt-[132px] lg:max-w-[1136px] lg:bg-unset lg:pt-0", children: [_jsx(Dialog.Context, { children: (api) => (_jsxs("div", { className: "flex items-center justify-between px-4 lg:hidden", children: [_jsx(Image, { src: props.logo, alt: "", width: 200, height: 40, className: "h-8 w-auto" }), _jsx(IconButton, { size: "sm", colorScheme: "gray", onClick: () => api.setOpen(false), children: _jsx(XIcon, { className: "text-text-quinary size-6" }) })] })) }), _jsx("div", { className: "flex justify-end", children: _jsx(Dialog.Context, { children: (api) => (_jsx("button", { type: "button", onClick: () => api.setOpen(false), className: "hidden size-9 items-center justify-center rounded-md bg-white/20 lg:flex", children: _jsx(XIcon, { className: "size-5 text-white" }) })) }) }), _jsx("div", { className: "mt-2xl px-4 lg:mt-xl lg:px-0", children: _jsxs("div", { className: "relative", children: [_jsx(SearchLgIcon, { className: "text-text-quinary pointer-events-none absolute left-3.5 top-1/2 size-5 -translate-y-1/2" }), _jsx(Field.Input, { ref: inputRef, type: "search", value: search, onChange: (e) => {
28
+ setSearch(e.target.value);
29
+ }, className: "pl-10 pr-16", placeholder: "Search", autoComplete: "off" }), _jsx(Presence, { present: search.length > 0, asChild: true, lazyMount: true, children: _jsx("button", { type: "button", className: "text-text-secondary-700 absolute right-3.5 top-1/2 -translate-y-1/2 font-semibold", onClick: () => {
30
+ setSearch('');
31
+ inputRef.current?.focus();
32
+ }, children: "Clear" }) })] }) }), _jsx("div", { className: "lg:bg-bg-primary lg:border-border-primary mt-2xl p-xl pb-3xl lg:mt-2 lg:rounded-xl lg:border", children: search.length <= 0 ? (_jsx(Alert, { message: "Search for your favorite game or provider." })) : 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(_Fragment, { children: [_jsx("h2", { className: "text-lg font-semibold", children: "Providers" }), _jsx("div", { className: "mb-3xl mt-3.5 grid grid-cols-3 gap-1.5 lg:grid-cols-9 lg:gap-3.5", children: _jsx("div", { className: "bg-gray-800 flex h-14 w-full items-center rounded-md", children: _jsx(Image, { src: providerHacksaw, alt: "", width: 100, height: 50, className: "mx-auto h-auto w-full" }) }) }), _jsx("h2", { className: "text-lg font-semibold", children: "Games" }), _jsx("div", { className: "mt-3.5 grid grid-cols-3 gap-1.5 lg:grid-cols-9 lg:gap-3.5", children: games.map((game) => (_jsxs(GameLaunchTrigger, { game: game, className: "block w-full shadow-sm", onClick: () => {
33
+ globalStore.search.setOpen(false);
34
+ }, 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-12 w-fit", onClick: () => gamesQuery.fetchNextPage(), children: "Load More" }) })] }))] })) })] }) })] }) }));
35
+ }
36
+ function Alert({ message }) {
37
+ 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 })] }));
38
+ }
@@ -0,0 +1,5 @@
1
+ import type { ComponentPropsWithRef } from 'react';
2
+ export interface SearchTriggerProps extends ComponentPropsWithRef<'button'> {
3
+ asChild?: boolean;
4
+ }
5
+ export declare function SearchTrigger(props: SearchTriggerProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
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 SearchTrigger(props) {
7
+ const globalStore = useGlobalStore(useShallow((ctx) => ({
8
+ search: ctx.search,
9
+ })));
10
+ return (_jsx(ark.button, { type: "button", "aria-label": "Search", "data-state": globalStore.search.open ? 'open' : 'closed', ...props, onClick: (e) => {
11
+ globalStore.search.setOpen(!globalStore.search.open);
12
+ return props.onClick?.(e);
13
+ } }));
14
+ }
@@ -0,0 +1,2 @@
1
+ export * from './Search';
2
+ export * from './SearchTrigger';
@@ -0,0 +1,2 @@
1
+ export * from './Search.js';
2
+ export * from './SearchTrigger.js';
@@ -7,8 +7,8 @@ export function SignInTrigger(props) {
7
7
  const globalStore = useGlobalStore(useShallow((ctx) => ({
8
8
  signIn: ctx.signIn,
9
9
  })));
10
- return (_jsx(ark.button, { type: "button", ...props, onClick: (e) => {
10
+ return (_jsx(ark.button, { type: "button", "aria-label": "Sign in", "data-state": globalStore.signIn.open ? 'open' : 'closed', ...props, onClick: (e) => {
11
11
  globalStore.signIn.setOpen(!globalStore.signIn.open);
12
12
  return props.onClick?.(e);
13
- }, "data-state": globalStore.signIn.open ? 'open' : 'closed' }));
13
+ } }));
14
14
  }