@opexa/portal-components 0.0.78 → 0.0.80

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 (36) hide show
  1. package/dist/client/hooks/index.d.ts +1 -0
  2. package/dist/client/hooks/index.js +1 -0
  3. package/dist/client/hooks/useChunk.d.ts +8 -0
  4. package/dist/client/hooks/useChunk.js +26 -0
  5. package/dist/components/BetRecords/BetRecords.js +3 -3
  6. package/dist/components/Cashback/Cashback.client.js +1 -1
  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/GameProviders/GameProviders.d.ts +3 -24
  12. package/dist/components/GameProviders/GameProviders.js +9 -41
  13. package/dist/components/GameProviders/GameProvidersCarousel.d.ts +31 -0
  14. package/dist/components/GameProviders/GameProvidersCarousel.js +47 -0
  15. package/dist/components/GameProviders/GameProvidersList.d.ts +27 -0
  16. package/dist/components/GameProviders/GameProvidersList.js +25 -0
  17. package/dist/components/Games/Game.d.ts +6 -1
  18. package/dist/components/Games/Game.js +7 -3
  19. package/dist/components/Games/Games.d.ts +1 -5
  20. package/dist/components/Games/GamesCarousel.client.js +10 -3
  21. package/dist/components/Games/GamesCarousel.d.ts +7 -2
  22. package/dist/components/Games/GamesContext.d.ts +4 -0
  23. package/dist/components/Games/GamesContext.js +3 -0
  24. package/dist/components/Games/GamesList.client.js +10 -4
  25. package/dist/components/Games/GamesList.d.ts +7 -2
  26. package/dist/components/Jackpots/JackpotGameProviders.js +4 -1
  27. package/dist/components/Jackpots/Jackpots.d.ts +2 -0
  28. package/dist/components/Promo/Promo.client.js +1 -1
  29. package/dist/components/Promos/Promos.d.ts +3 -14
  30. package/dist/components/Promos/PromosCarousel.d.ts +13 -2
  31. package/dist/components/Promos/PromosGrid.d.ts +11 -2
  32. package/dist/components/Search/Search.d.ts +1 -0
  33. package/dist/components/Search/Search.js +2 -1
  34. package/dist/components/TransactionRecords/TransactionRecords.js +1 -1
  35. package/dist/constants/gameProviders.js +1 -1
  36. package/package.json +1 -1
@@ -10,6 +10,7 @@ export * from './useCashbackBonusQuery';
10
10
  export * from './useCashbackQuery';
11
11
  export * from './useCashbacksQuery';
12
12
  export * from './useCheckInDailyCheckInQuestMutation';
13
+ export * from './useChunk';
13
14
  export * from './useClaimCashbackBonusMutation';
14
15
  export * from './useClaimSpotBonusMutation';
15
16
  export * from './useControllableState';
@@ -10,6 +10,7 @@ export * from './useCashbackBonusQuery.js';
10
10
  export * from './useCashbackQuery.js';
11
11
  export * from './useCashbacksQuery.js';
12
12
  export * from './useCheckInDailyCheckInQuestMutation.js';
13
+ export * from './useChunk.js';
13
14
  export * from './useClaimCashbackBonusMutation.js';
14
15
  export * from './useClaimSpotBonusMutation.js';
15
16
  export * from './useControllableState.js';
@@ -0,0 +1,8 @@
1
+ export declare function useChunk<T>(items: T[], size: number): {
2
+ totalItems: number;
3
+ currentItems: T[];
4
+ loadedItems: T[];
5
+ totalLoadedItems: number;
6
+ hasNext: boolean;
7
+ next: () => void;
8
+ };
@@ -0,0 +1,26 @@
1
+ import { chunk } from 'lodash-es';
2
+ import { useState } from 'react';
3
+ export function useChunk(items, size) {
4
+ const chunks = chunk(items, size);
5
+ const [currentIndex, setCurrentIndex] = useState(0);
6
+ const currentItems = chunks.at(currentIndex) ?? [];
7
+ const loadedItems = (() => {
8
+ return chunks.filter((_, index) => index <= currentIndex).flat();
9
+ })();
10
+ const next = () => {
11
+ if (currentIndex >= chunks.length - 1)
12
+ return;
13
+ setCurrentIndex((prevIndex) => prevIndex + 1);
14
+ };
15
+ const totalItems = items.length;
16
+ const totalLoadedItems = loadedItems.length;
17
+ const hasNext = currentIndex < chunks.length - 1;
18
+ return {
19
+ totalItems,
20
+ currentItems,
21
+ loadedItems,
22
+ totalLoadedItems,
23
+ hasNext,
24
+ next,
25
+ };
26
+ }
@@ -22,7 +22,7 @@ export function BetRecords(props) {
22
22
  }), {
23
23
  page: 1,
24
24
  pageSize: 10,
25
- type: gameTypes[0].id,
25
+ type: null,
26
26
  });
27
27
  const localeInfo = useLocaleInfo();
28
28
  const providerCollection = createListCollection({
@@ -59,12 +59,12 @@ export function BetRecords(props) {
59
59
  }),
60
60
  },
61
61
  });
62
- return (_jsxs("div", { className: props.className, children: [_jsx("h2", { className: "text-sm font-semibold leading-tight lg:text-lg", children: "Bet Records" }), _jsx("p", { className: "text-text-tertiary-600 mt-xs text-sm leading-tight", children: "Review your betting history" }), _jsx("div", { className: "mt-lg lg:mt-2xl", children: _jsxs(SegmentGroup.Root, { value: state.type, onValueChange: (details) => {
62
+ return (_jsxs("div", { className: props.className, children: [_jsx("h2", { className: "text-sm font-semibold leading-tight lg:text-lg", children: "Bet Records" }), _jsx("p", { className: "text-text-tertiary-600 mt-xs text-sm leading-tight", children: "Review your betting history" }), _jsx("div", { className: "mt-lg lg:mt-2xl", children: _jsxs(SegmentGroup.Root, { value: state.type ?? 'all', onValueChange: (details) => {
63
63
  firstPage();
64
64
  setState({
65
65
  type: z.enum(GAME_TYPES).safeParse(details.value).data ?? null,
66
66
  });
67
- }, children: [gameTypes.map((type) => (_jsxs(SegmentGroup.Item, { value: type.id, children: [_jsx(SegmentGroup.ItemText, { children: type.name }), _jsx(SegmentGroup.ItemControl, {}), _jsx(SegmentGroup.ItemHiddenInput, {})] }, type.id))), _jsx(SegmentGroup.Indicator, {})] }) }), _jsx("div", { className: "border-border-secondary mt-2xl hidden border-t lg:block" }), _jsx("h3", { className: "text-text-secondary-700 mt-3xl text-sm font-semibold", children: "Table" }), _jsxs("div", { className: "mt-xl flex flex-col gap-lg lg:flex-row lg:items-center", children: [_jsxs(DatePicker.Root, { lazyMount: true, unmountOnExit: true, value: [state.timestamp?.start, state.timestamp?.end]
67
+ }, children: [_jsxs(SegmentGroup.Item, { value: "all", children: [_jsx(SegmentGroup.ItemText, { children: "All" }), _jsx(SegmentGroup.ItemControl, {}), _jsx(SegmentGroup.ItemHiddenInput, {})] }), gameTypes.map((type) => (_jsxs(SegmentGroup.Item, { value: type.id, children: [_jsx(SegmentGroup.ItemText, { children: type.name }), _jsx(SegmentGroup.ItemControl, {}), _jsx(SegmentGroup.ItemHiddenInput, {})] }, type.id))), _jsx(SegmentGroup.Indicator, {})] }) }), _jsx("div", { className: "border-border-secondary mt-2xl hidden border-t lg:block" }), _jsx("h3", { className: "text-text-secondary-700 mt-3xl text-sm font-semibold", children: "Table" }), _jsxs("div", { className: "mt-xl flex flex-col gap-lg lg:flex-row lg:items-center", children: [_jsxs(DatePicker.Root, { lazyMount: true, unmountOnExit: true, value: [state.timestamp?.start, state.timestamp?.end]
68
68
  .filter(Boolean)
69
69
  .map((d) => parseDate(d)), onValueChange: (details) => {
70
70
  firstPage();
@@ -27,5 +27,5 @@ export function Cashback__client(props) {
27
27
  in: tz(localeInfo.timezone),
28
28
  })] }), _jsx(Prose, { className: "mt-2xl lg:mt-6", dangerouslySetInnerHTML: {
29
29
  __html: cashback.description,
30
- } }), _jsxs(Prose, { className: "bg-bg-secondary mt-xl rounded-2xl p-2xl lg:mt-16 lg:p-4xl", children: [_jsx("h2", { children: "Conclusion" }), _jsx("p", { children: "Morbi sed imperdiet in ipsum, adipiscing elit dui lectus. Tellus id scelerisque est ultricies ultricies. Duis est sit sed leo nisl, blandit elit sagittis. Quisque tristique consequat quam sed. Nisl at scelerisque amet nulla purus habitasse." }), _jsx("p", { children: "Nunc sed faucibus bibendum feugiat sed interdum. Ipsum egestas condimentum mi massa. In tincidunt pharetra consectetur sed duis facilisis metus. Etiam egestas in nec sed et. Quis lobortis at sit dictum eget nibh tortor commodo cursus." }), _jsx("p", { children: "Odio felis sagittis, morbi feugiat tortor vitae feugiat fusce aliquet. Nam elementum urna nisi aliquet erat dolor enim. Ornare id morbi eget ipsum. Aliquam senectus neque ut id eget consectetur dictum. Donec posuere pharetra odio consequat scelerisque et, nunc tortor." })] })] }));
30
+ } })] }));
31
31
  }
@@ -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;
@@ -9,7 +9,7 @@ export declare const OnlineBankDepositContext: import("react").Context<{
9
9
  promo?: string | null;
10
10
  }) => void;
11
11
  }>, useOnlineBankDepositContext: () => {
12
- view: "vca" | "form";
12
+ view: "form" | "vca";
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 '@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;
@@ -9,7 +9,7 @@ export declare const QRPHDepositContext: import("react").Context<{
9
9
  promo?: string | null;
10
10
  }) => void;
11
11
  }>, useQRPHDepositContext: () => {
12
- view: "qrCode" | "form";
12
+ view: "form" | "qrCode";
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 '@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;
@@ -1,25 +1,4 @@
1
- import type { GameProvider } from '@opexa/portal-sdk-core';
2
- import type { GameProviderData } from '../../types';
3
- export interface GameProvidersProps {
4
- gameProviders: GameProvider[];
5
- heading?: string;
6
- /**
7
- * @default '/providers'
8
- */
9
- viewAllUrl?: string;
10
- /**
11
- * @default '/providers/<slug>'
12
- * @example
13
- * ```ts
14
- * '/bingo/:slug' // '/bingo/jili'
15
- * '/bingo/:id' // '/bingo/JILI'
16
- * // or using a function
17
- * ({slug}) => `/bingo/${slug}`
18
- * ```
19
- */
20
- viewGamesUrl?: string | ((gameProvider: GameProviderData) => string);
21
- className?: string;
22
- gameProviderContainerClass?: string;
23
- gameProviderImageClass?: string;
24
- }
1
+ import { type GameProvidersCarouselProps } from './GameProvidersCarousel';
2
+ import { type GameProvidersListProps } from './GameProvidersList';
3
+ export type GameProvidersProps = GameProvidersCarouselProps | GameProvidersListProps;
25
4
  export declare function GameProviders(props: GameProvidersProps): import("react/jsx-runtime").JSX.Element;
@@ -1,43 +1,11 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import useEmblaCarousel from 'embla-carousel-react';
4
- import Image from 'next/image';
5
- import Link from 'next/link';
6
- import { useCallback, useEffect, useState } from 'react';
7
- import { twMerge } from 'tailwind-merge';
8
- import { GAME_PROVIDER_DATA } from '../../constants/index.js';
9
- import { ArrowLeftIcon, ArrowRightIcon, ChevronRightIcon } from '../../icons/index.js';
10
- import { Button } from '../../ui/index.js';
11
- import { callIfFn } from '../../utils/index.js';
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { GameProvidersCarousel, } from './GameProvidersCarousel.js';
3
+ import { GameProvidersList, } from './GameProvidersList.js';
12
4
  export function GameProviders(props) {
13
- const [emblaRef, emblaApi] = useEmblaCarousel({
14
- align: 'start',
15
- slidesToScroll: 1,
16
- });
17
- const [prevBtnDisabled, setPrevBtnDisabled] = useState(true);
18
- const [nextBtnDisabled, setNextBtnDisabled] = useState(true);
19
- const onPrevButtonClick = useCallback(() => emblaApi?.scrollPrev(), [emblaApi]);
20
- const onNextButtonClick = useCallback(async () => {
21
- emblaApi?.scrollNext();
22
- }, [emblaApi]);
23
- const onSelect = useCallback((emblaApi) => {
24
- setPrevBtnDisabled(!emblaApi?.canScrollPrev());
25
- setNextBtnDisabled(!emblaApi?.canScrollNext());
26
- }, []);
27
- useEffect(() => {
28
- if (!emblaApi)
29
- return;
30
- onSelect(emblaApi);
31
- emblaApi.on('reInit', onSelect).on('select', onSelect);
32
- }, [emblaApi, onSelect]);
33
- const viewAllUrl = props.viewAllUrl ?? '/providers';
34
- const viewGamesUrl = (data) => {
35
- return props.viewGamesUrl
36
- ? callIfFn(props.viewGamesUrl, data)
37
- .replace(':id', data.id)
38
- .replace(':slug', data.slug)
39
- : `/providers/${data.slug}`;
40
- };
41
- const gameProviders = props.gameProviders.map((provider) => GAME_PROVIDER_DATA[provider]);
42
- return (_jsxs("div", { className: props.className, children: [_jsxs("div", { className: "flex items-center", children: [_jsx("h2", { className: "text-lg font-semibold", children: props.heading ?? 'Providers' }), _jsx("div", { className: "grow" }), _jsxs("div", { className: "flex items-center justify-center gap-xl", children: [_jsxs(Link, { href: viewAllUrl, className: "text-button-tertiary-fg flex gap-sm text-sm font-semibold", children: ["See All", _jsx(ChevronRightIcon, { className: "size-5 lg:hidden" })] }), _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: "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: gameProviders.map((provider) => (_jsx(Link, { href: viewGamesUrl(provider), className: twMerge('bg-gray-800 flex h-full w-full items-center overflow-hidden rounded-md lg:h-[5.75rem]', props.gameProviderContainerClass), "aria-label": `View ${provider.name} games`, children: _jsx(Image, { src: provider.logo, alt: "", width: 300, height: 150, className: twMerge('mx-auto h-auto w-full', props.gameProviderImageClass) }) }, provider.id))) }) })] }));
5
+ if (props.layout === 'list') {
6
+ return _jsx(GameProvidersList, { ...props });
7
+ }
8
+ else {
9
+ return _jsx(GameProvidersCarousel, { ...props });
10
+ }
43
11
  }
@@ -0,0 +1,31 @@
1
+ import type { GameProvider } from '@opexa/portal-sdk-core';
2
+ import { type ImageProps } from 'next/image';
3
+ import type { GameProviderData } from '../../types';
4
+ export interface ClassNameEntries {
5
+ root?: string;
6
+ thumbnailRoot?: string;
7
+ thumbnailImage?: string;
8
+ }
9
+ export interface GameProvidersCarouselProps {
10
+ layout: 'carousel';
11
+ gameProviders: GameProvider[];
12
+ heading?: string;
13
+ /**
14
+ * @default '/providers'
15
+ */
16
+ viewAllUrl?: string;
17
+ /**
18
+ * @default '/providers/<slug>'
19
+ * @example
20
+ * ```ts
21
+ * '/bingo/:slug' // '/bingo/jili'
22
+ * '/bingo/:id' // '/bingo/JILI'
23
+ * // or using a function
24
+ * ({slug}) => `/bingo/${slug}`
25
+ * ```
26
+ */
27
+ viewGamesUrl?: string | ((gameProvider: GameProviderData) => string);
28
+ gameProviderImages?: Partial<Record<GameProvider, ImageProps['src']>>;
29
+ className?: string | ClassNameEntries;
30
+ }
31
+ export declare function GameProvidersCarousel(props: GameProvidersCarouselProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,47 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import useEmblaCarousel from 'embla-carousel-react';
4
+ import { isString } from 'lodash-es';
5
+ import Image, {} from 'next/image';
6
+ import Link from 'next/link';
7
+ import { useCallback, useEffect, useState } from 'react';
8
+ import { twMerge } from 'tailwind-merge';
9
+ import { GAME_PROVIDER_DATA } from '../../constants/index.js';
10
+ import { ArrowLeftIcon, ArrowRightIcon, ChevronRightIcon } from '../../icons/index.js';
11
+ import { Button } from '../../ui/index.js';
12
+ import { callIfFn } from '../../utils/index.js';
13
+ export function GameProvidersCarousel(props) {
14
+ const [emblaRef, emblaApi] = useEmblaCarousel({
15
+ align: 'start',
16
+ slidesToScroll: 1,
17
+ });
18
+ const [prevBtnDisabled, setPrevBtnDisabled] = useState(true);
19
+ const [nextBtnDisabled, setNextBtnDisabled] = useState(true);
20
+ const onPrevButtonClick = useCallback(() => emblaApi?.scrollPrev(), [emblaApi]);
21
+ const onNextButtonClick = useCallback(async () => {
22
+ emblaApi?.scrollNext();
23
+ }, [emblaApi]);
24
+ const onSelect = useCallback((emblaApi) => {
25
+ setPrevBtnDisabled(!emblaApi?.canScrollPrev());
26
+ setNextBtnDisabled(!emblaApi?.canScrollNext());
27
+ }, []);
28
+ useEffect(() => {
29
+ if (!emblaApi)
30
+ return;
31
+ onSelect(emblaApi);
32
+ emblaApi.on('reInit', onSelect).on('select', onSelect);
33
+ }, [emblaApi, onSelect]);
34
+ const viewAllUrl = props.viewAllUrl ?? '/providers';
35
+ const viewGamesUrl = (data) => {
36
+ return props.viewGamesUrl
37
+ ? callIfFn(props.viewGamesUrl, data)
38
+ .replace(':id', data.id)
39
+ .replace(':slug', data.slug)
40
+ : `/providers/${data.slug}`;
41
+ };
42
+ const gameProviders = props.gameProviders.map((provider) => GAME_PROVIDER_DATA[provider]);
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 ?? 'Providers' }), _jsx("div", { className: "grow" }), _jsxs("div", { className: "flex items-center justify-center gap-xl", children: [_jsxs(Link, { href: viewAllUrl, className: "text-button-tertiary-fg flex gap-sm text-sm font-semibold", children: ["See All", _jsx(ChevronRightIcon, { className: "size-5 lg:hidden" })] }), _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: "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: gameProviders.map((provider) => (_jsx(Link, { href: viewGamesUrl(provider), className: twMerge('bg-gray-800 flex h-full w-full items-center overflow-hidden rounded-md lg:h-[5.75rem]', classNames.thumbnailRoot), "aria-label": `View ${provider.name} games`, children: _jsx(Image, { src: props.gameProviderImages?.[provider.id] ?? provider.logo, alt: "", width: 300, height: 150, className: twMerge('mx-auto h-auto w-full', classNames.thumbnailImage) }) }, provider.id))) }) })] }));
47
+ }
@@ -0,0 +1,27 @@
1
+ import type { GameProvider } from '@opexa/portal-sdk-core';
2
+ import { type ImageProps } from 'next/image';
3
+ import type { GameProviderData } from '../../types';
4
+ export interface ClassNameEntries {
5
+ root?: string;
6
+ thumbnailRoot?: string;
7
+ thumbnailImage?: string;
8
+ }
9
+ export interface GameProvidersListProps {
10
+ layout: 'list';
11
+ gameProviders: GameProvider[];
12
+ heading?: string;
13
+ /**
14
+ * @default '/providers/<slug>'
15
+ * @example
16
+ * ```ts
17
+ * '/bingo/:slug' // '/bingo/jili'
18
+ * '/bingo/:id' // '/bingo/JILI'
19
+ * // or using a function
20
+ * ({slug}) => `/bingo/${slug}`
21
+ * ```
22
+ */
23
+ viewGamesUrl?: string | ((gameProvider: GameProviderData) => string);
24
+ gameProviderImages?: Partial<Record<GameProvider, ImageProps['src']>>;
25
+ className?: string | ClassNameEntries;
26
+ }
27
+ export declare function GameProvidersList(props: GameProvidersListProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,25 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { isString, noop } from 'lodash-es';
4
+ import Image, {} from 'next/image';
5
+ import Link from 'next/link';
6
+ import { twMerge } from 'tailwind-merge';
7
+ import { useChunk } from '../../client/hooks/index.js';
8
+ import { GAME_PROVIDER_DATA } from '../../constants/index.js';
9
+ import { Button, Progress } from '../../ui/index.js';
10
+ import { callIfFn } from '../../utils/index.js';
11
+ export function GameProvidersList(props) {
12
+ const viewGamesUrl = (data) => {
13
+ return props.viewGamesUrl
14
+ ? callIfFn(props.viewGamesUrl, data)
15
+ .replace(':id', data.id)
16
+ .replace(':slug', data.slug)
17
+ : `/providers/${data.slug}`;
18
+ };
19
+ const gameProviders = props.gameProviders.map((provider) => GAME_PROVIDER_DATA[provider]);
20
+ const classNames = isString(props.className)
21
+ ? { root: props.className }
22
+ : (props.className ?? {});
23
+ const chunked = useChunk(gameProviders, 18);
24
+ return (_jsxs("div", { className: classNames.root, children: [_jsx("h2", { className: "text-lg font-semibold", children: props.heading ?? 'Providers' }), _jsx("div", { className: "mt-lg grid grid-cols-3 gap-1.5 lg:grid-cols-6 lg:gap-2.5", children: chunked.loadedItems.map((provider) => (_jsx(Link, { href: viewGamesUrl(provider), className: twMerge('bg-gray-800 flex h-full w-full items-center overflow-hidden rounded-md lg:h-[5.75rem]', classNames.thumbnailRoot), "aria-label": `View ${provider.name} games`, children: _jsx(Image, { src: props.gameProviderImages?.[provider.id] ?? provider.logo, alt: "", width: 300, height: 150, className: twMerge('mx-auto h-auto w-full', classNames.thumbnailImage) }) }, provider.id))) }), _jsxs("div", { className: "mt-2xl flex flex-col items-center lg:mt-3xl", children: [_jsx(Progress.Root, { min: 0, max: chunked.totalItems, value: chunked.totalLoadedItems, onValueChange: noop, className: "w-[12.5rem]", children: _jsx(Progress.Track, { className: "bg-bg-tertiary", children: _jsx(Progress.Range, {}) }) }), _jsx("p", { className: "text-button-tertiary-fg mt-md text-sm", children: `Displaying ${chunked.totalLoadedItems} of ${chunked.totalItems}` }), chunked.hasNext && (_jsx(Button, { size: "sm", variant: "outline", fullWidth: false, onClick: chunked.next, className: "mt-lg", children: "Load More" }))] })] }));
25
+ }
@@ -1,5 +1,10 @@
1
+ interface ClassNameEntries {
2
+ root?: string;
3
+ title?: string;
4
+ }
1
5
  export interface GameProps {
2
6
  badge?: 'top' | 'new' | 'popular';
3
- gameNameClass?: string;
7
+ className?: string | ClassNameEntries;
4
8
  }
5
9
  export declare function Game(props: GameProps): import("react/jsx-runtime").JSX.Element;
10
+ export {};
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { isString } from 'lodash-es';
2
3
  import Image from 'next/image';
3
4
  import { twMerge } from 'tailwind-merge';
4
5
  import { useFavoriteGamesQuery, useMarkGameAsFavoriteMutation, useSessionQuery, useUnmarkGameAsFavoriteMutation, } from '../../client/hooks/index.js';
@@ -7,7 +8,7 @@ import { GameLaunchTrigger } from '../GameLaunch/index.js';
7
8
  import { BadgeNew } from './BadgeNew.js';
8
9
  import { BadgePopular } from './BadgePopular.js';
9
10
  import { BadgeTop } from './BadgeTop.js';
10
- import { useGameContext } from './GameContext.js';
11
+ import { useGameContext } from './GamesContext.js';
11
12
  export function Game(props) {
12
13
  const game = useGameContext();
13
14
  const sessionQuery = useSessionQuery();
@@ -17,7 +18,10 @@ export function Game(props) {
17
18
  const markGameAsFavoriteMutation = useMarkGameAsFavoriteMutation();
18
19
  const unmarkGameAsFavoriteMutation = useUnmarkGameAsFavoriteMutation();
19
20
  const markedAsFavorite = favoriteGames.some((favoriteGame) => favoriteGame.id === game.id);
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
+ const classNames = isString(props.className)
22
+ ? { root: props.className }
23
+ : (props.className ?? {});
24
+ return (_jsxs(GameLaunchTrigger, { game: game, className: twMerge('animate-scale-in relative block w-full shadow-sm', classNames.root), 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
25
  e.preventDefault();
22
26
  e.stopPropagation();
23
27
  if (markGameAsFavoriteMutation.isPending)
@@ -33,5 +37,5 @@ export function Game(props) {
33
37
  }, "aria-disabled": markGameAsFavoriteMutation.isPending ||
34
38
  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: twMerge('size-5', markedAsFavorite
35
39
  ? 'fill-yellow-400 text-yellow-400'
36
- : 'text-white') }) })), _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: 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', props.gameNameClass), children: game.name })] }));
40
+ : 'text-white') }) })), _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: 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', classNames.title), children: game.name })] }));
37
41
  }
@@ -1,8 +1,4 @@
1
1
  import { type GamesCarouselProps } from './GamesCarousel';
2
2
  import { type GamesListProps } from './GamesList';
3
- export type GamesProps = ({
4
- layout: 'list';
5
- } & GamesListProps) | ({
6
- layout?: 'carousel';
7
- } & GamesCarouselProps);
3
+ export type GamesProps = GamesListProps | GamesCarouselProps;
8
4
  export declare function Games(props: GamesProps): Promise<import("react/jsx-runtime").JSX.Element>;
@@ -1,6 +1,7 @@
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 Link from 'next/link';
5
6
  import { useCallback, useEffect, useState } from 'react';
6
7
  import { twMerge } from 'tailwind-merge';
@@ -9,7 +10,7 @@ import { ArrowLeftIcon, ArrowRightIcon, ChevronRightIcon, GamingPad01Icon, Spinn
9
10
  import { Button } from '../../ui/index.js';
10
11
  import { Empty } from '../Empty.js';
11
12
  import { Game } from './Game.js';
12
- import { GameContext } from './GameContext.js';
13
+ import { GameContext } from './GamesContext.js';
13
14
  export function GamesCarousel__client(props) {
14
15
  const numOfRows = props.numOfRows ?? 1;
15
16
  const gamesQuery = useGamesQuery({
@@ -51,11 +52,17 @@ export function GamesCarousel__client(props) {
51
52
  onSelect(emblaApi);
52
53
  emblaApi.on('reInit', onSelect).on('select', onSelect);
53
54
  }, [emblaApi, onSelect]);
54
- return (_jsxs("div", { className: props.className, children: [_jsxs("div", { className: "flex items-center", children: [_jsx("h2", { className: "text-lg font-semibold", children: props.heading ?? 'Games' }), _jsx("div", { className: "grow" }), _jsxs("div", { className: "flex items-center justify-center gap-xl", children: [_jsxs(Link, { href: props.viewAllUrl ?? '/games', className: "text-button-tertiary-fg flex gap-sm text-sm font-semibold", children: ["See All", _jsx(ChevronRightIcon, { className: "size-5 lg:hidden" })] }), _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 && !gamesQuery.hasNextPage
55
+ const classNames = isString(props.className)
56
+ ? { root: props.className }
57
+ : (props.className ?? {});
58
+ return (_jsxs("div", { className: classNames.root, children: [_jsxs("div", { className: "flex items-center", children: [_jsx("h2", { className: "text-lg font-semibold", children: props.heading ?? 'Games' }), _jsx("div", { className: "grow" }), _jsxs("div", { className: "flex items-center justify-center gap-xl", children: [_jsxs(Link, { href: props.viewAllUrl ?? '/games', className: "text-button-tertiary-fg flex gap-sm text-sm font-semibold", children: ["See All", _jsx(ChevronRightIcon, { className: "size-5 lg:hidden" })] }), _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 && !gamesQuery.hasNextPage
55
59
  ? true
56
60
  : gamesQuery.isFetchingNextPage, "aria-label": "Next", children: gamesQuery.isFetchingNextPage ? (_jsx(SpinnerIcon, { className: "size-5" })) : (_jsx(ArrowRightIcon, { className: "size-5" })) })] })] })] }), games.length <= 0 && (_jsx(Empty, { icon: GamingPad01Icon, title: "No games", message: "No game is currently available. Please check back later", className: "mt-lg" })), games.length >= 1 && (_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 gap-sm lg:auto-cols-[calc((100%-(0.5rem*5))/6)] lg:gap-md', numOfRows === 3
57
61
  ? 'grid-rows-3'
58
62
  : numOfRows === 2
59
63
  ? 'grid-rows-2'
60
- : 'grid-rows-1'), children: games.map((game) => (_jsx(GameContext, { value: game, children: _jsx(Game, { badge: props.badge, gameNameClass: props.gameNameClass }) }, game.id))) }) }))] }));
64
+ : 'grid-rows-1'), children: games.map((game) => (_jsx(GameContext, { value: game, children: _jsx(Game, { badge: props.badge, className: {
65
+ root: classNames.thumbnailRoot,
66
+ title: classNames.thumbnailTitle,
67
+ } }) }, game.id))) }) }))] }));
61
68
  }
@@ -1,5 +1,11 @@
1
1
  import type { GamesInput__Next } from '@opexa/portal-sdk-core';
2
+ export interface ClassNameEntries {
3
+ root?: string;
4
+ thumbnailRoot?: string;
5
+ thumbnailTitle?: string;
6
+ }
2
7
  export interface GamesCarouselProps {
8
+ layout: 'carousel';
3
9
  /** @default "Games" */
4
10
  heading?: string;
5
11
  /**
@@ -13,7 +19,6 @@ export interface GamesCarouselProps {
13
19
  filter?: GamesInput__Next['filter'];
14
20
  search?: string;
15
21
  sort?: GamesInput__Next['sort'];
16
- className?: string;
17
- gameNameClass?: string;
22
+ className?: string | ClassNameEntries;
18
23
  }
19
24
  export declare function GamesCarousel(props: GamesCarouselProps): Promise<import("react/jsx-runtime").JSX.Element>;
@@ -0,0 +1,4 @@
1
+ import type { Game } from '@opexa/portal-sdk-core';
2
+ import type { GamesProps } from './Games';
3
+ export declare const GamesPropsContext: import("react").Context<GamesProps>, useGamesPropsContext: () => GamesProps;
4
+ export declare const GameContext: import("react").Context<Game>, useGameContext: () => Game;
@@ -0,0 +1,3 @@
1
+ import { createContext } from '../../client/utils/index.js';
2
+ export const [GamesPropsContext, useGamesPropsContext] = createContext();
3
+ export const [GameContext, useGameContext] = createContext();
@@ -1,12 +1,12 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { noop } from 'lodash-es';
3
+ import { isString, noop } from 'lodash-es';
4
4
  import { useGamesQuery, useInfiniteQueryHelper } from '../../client/hooks/index.js';
5
5
  import { GamingPad01Icon, SpinnerIcon } from '../../icons/index.js';
6
6
  import { Button, Progress } from '../../ui/index.js';
7
7
  import { Empty } from '../Empty.js';
8
8
  import { Game } from './Game.js';
9
- import { GameContext } from './GameContext.js';
9
+ import { GameContext } from './GamesContext.js';
10
10
  export function GamesList__client(props) {
11
11
  const { loading, availableRows, totalRows, totalAvailableRows, hasNextPage, next, } = useInfiniteQueryHelper(useGamesQuery, {
12
12
  first: props.first ?? 24,
@@ -14,7 +14,13 @@ export function GamesList__client(props) {
14
14
  search: props.search,
15
15
  sort: props.sort,
16
16
  });
17
- return (_jsxs("div", { className: props.className, children: [_jsx("h2", { className: "text-lg font-semibold", children: props.heading ?? 'Games' }), totalRows <= 0 && (_jsx(Empty, { icon: loading ? SpinnerIcon : GamingPad01Icon, title: loading ? 'Just a moment' : 'No games', message: loading
17
+ const classNames = isString(props.className)
18
+ ? { root: props.className }
19
+ : (props.className ?? {});
20
+ return (_jsxs("div", { className: classNames.root, children: [_jsx("h2", { className: "text-lg font-semibold", children: props.heading ?? 'Games' }), totalRows <= 0 && (_jsx(Empty, { icon: loading ? SpinnerIcon : GamingPad01Icon, title: loading ? 'Just a moment' : 'No games', message: loading
18
21
  ? 'Fetching latest games...'
19
- : 'No game is currently available. Please check back later', className: "mt-lg" })), totalRows >= 1 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "mt-lg grid grid-cols-3 gap-1.5 lg:grid-cols-6 lg:gap-2.5", children: availableRows.map((game) => (_jsx(GameContext, { value: game, children: _jsx(Game, { badge: props.badge, gameNameClass: props.gameNameClass }) }, game.id))) }), _jsxs("div", { className: "mt-3xl flex flex-col items-center", children: [_jsx(Progress.Root, { min: 0, max: totalRows, value: totalAvailableRows, onValueChange: noop, className: "w-[12.5rem]", children: _jsx(Progress.Track, { className: "bg-bg-tertiary", children: _jsx(Progress.Range, {}) }) }), _jsx("p", { className: "text-button-tertiary-fg mt-md text-sm", children: `Displaying ${totalAvailableRows} of ${totalRows}` }), hasNextPage && (_jsx(Button, { size: "sm", variant: "outline", fullWidth: false, onClick: next, className: "mt-lg", children: "Load More" }))] })] }))] }));
22
+ : 'No game is currently available. Please check back later', className: "mt-lg" })), totalRows >= 1 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "mt-lg grid grid-cols-3 gap-1.5 lg:grid-cols-6 lg:gap-2.5", children: availableRows.map((game) => (_jsx(GameContext, { value: game, children: _jsx(Game, { badge: props.badge, className: {
23
+ root: classNames.thumbnailRoot,
24
+ title: classNames.thumbnailTitle,
25
+ } }) }, game.id))) }), _jsxs("div", { className: "mt-2xl flex flex-col items-center lg:mt-3xl", children: [_jsx(Progress.Root, { min: 0, max: totalRows, value: totalAvailableRows, onValueChange: noop, className: "w-[12.5rem]", children: _jsx(Progress.Track, { className: "bg-bg-tertiary", children: _jsx(Progress.Range, {}) }) }), _jsx("p", { className: "text-button-tertiary-fg mt-md text-sm", children: `Displaying ${totalAvailableRows} of ${totalRows}` }), hasNextPage && (_jsx(Button, { size: "sm", variant: "outline", fullWidth: false, onClick: next, className: "mt-lg", children: "Load More" }))] })] }))] }));
20
26
  }
@@ -1,5 +1,11 @@
1
1
  import type { GamesInput__Next } from '@opexa/portal-sdk-core';
2
+ export interface ClassNameEntries {
3
+ root?: string;
4
+ thumbnailRoot?: string;
5
+ thumbnailTitle?: string;
6
+ }
2
7
  export interface GamesListProps {
8
+ layout: 'list';
3
9
  badge?: 'top' | 'new' | 'popular';
4
10
  /** @default 24 */
5
11
  first?: number;
@@ -8,7 +14,6 @@ export interface GamesListProps {
8
14
  search?: string;
9
15
  /** @default "Games"*/
10
16
  heading?: string;
11
- className?: string;
12
- gameNameClass?: string;
17
+ className?: string | ClassNameEntries;
13
18
  }
14
19
  export declare function GamesList(props: GamesListProps): Promise<import("react/jsx-runtime").JSX.Element>;
@@ -6,6 +6,7 @@ import Link from 'next/link';
6
6
  import { useCallback, useEffect, useState } from 'react';
7
7
  import { ArrowLeftIcon, ArrowRightIcon } from '../../icons/index.js';
8
8
  import { Button } from '../../ui/index.js';
9
+ import { useJackpotsPropsContext } from './JackpotsContext.js';
9
10
  export function JackpotGameProviders({ gameProviders, }) {
10
11
  const [emblaRef, emblaApi] = useEmblaCarousel({
11
12
  align: 'start',
@@ -34,5 +35,7 @@ export function JackpotGameProviders({ gameProviders, }) {
34
35
  emblaApi.on('select', onSelect);
35
36
  emblaApi.on('reInit', onSelect);
36
37
  }, [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: "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: "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" }) }, i))) }) })] }));
38
+ const jackpotsProps = useJackpotsPropsContext();
39
+ 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: "bg-gray-800 lg:bg-bg-primary-900 min-w-27.5 rounded-md", children: _jsx(Image, { src: jackpotsProps.gameProviderImages?.[provider.id] ??
40
+ provider.logo, alt: "provider", className: "size-full" }) }, i))) }) })] }));
38
41
  }
@@ -1,8 +1,10 @@
1
1
  import type { GameProvider } from '@opexa/portal-sdk-core';
2
+ import type { ImageProps } from 'next/image';
2
3
  export interface JackpotsProps {
3
4
  /** @default "Jackpots" */
4
5
  heading?: string;
5
6
  className?: string;
6
7
  gameProviders: GameProvider[];
8
+ gameProviderImages?: Partial<Record<GameProvider, ImageProps['src']>>;
7
9
  }
8
10
  export declare function Jackpots(props: JackpotsProps): Promise<import("react/jsx-runtime").JSX.Element>;
@@ -27,5 +27,5 @@ export function Promo__client(props) {
27
27
  in: tz(localeInfo.timezone),
28
28
  })] }), _jsx(Prose, { className: "mt-2xl lg:mt-6", dangerouslySetInnerHTML: {
29
29
  __html: promo.description,
30
- } }), _jsxs(Prose, { className: "bg-bg-secondary mt-xl rounded-2xl p-2xl lg:mt-16 lg:p-4xl", children: [_jsx("h2", { children: "Conclusion" }), _jsx("p", { children: "Morbi sed imperdiet in ipsum, adipiscing elit dui lectus. Tellus id scelerisque est ultricies ultricies. Duis est sit sed leo nisl, blandit elit sagittis. Quisque tristique consequat quam sed. Nisl at scelerisque amet nulla purus habitasse." }), _jsx("p", { children: "Nunc sed faucibus bibendum feugiat sed interdum. Ipsum egestas condimentum mi massa. In tincidunt pharetra consectetur sed duis facilisis metus. Etiam egestas in nec sed et. Quis lobortis at sit dictum eget nibh tortor commodo cursus." }), _jsx("p", { children: "Odio felis sagittis, morbi feugiat tortor vitae feugiat fusce aliquet. Nam elementum urna nisi aliquet erat dolor enim. Ornare id morbi eget ipsum. Aliquam senectus neque ut id eget consectetur dictum. Donec posuere pharetra odio consequat scelerisque et, nunc tortor." })] })] }));
30
+ } })] }));
31
31
  }
@@ -1,15 +1,4 @@
1
- export interface PromosProps {
2
- /** @default "Promotions" */
3
- heading?: string;
4
- /** @default "/promos" */
5
- viewAllUrl?: string;
6
- /** @default "/promos" */
7
- viewPromoDetailsUrl?: string;
8
- /** @default "/promos/cashback" */
9
- viewCashbackDetailsUrl?: string;
10
- /** @default 1 */
11
- className?: string;
12
- /** @default 'carousel' */
13
- layout?: 'carousel' | 'grid';
14
- }
1
+ import { type PromosCarouselProps } from './PromosCarousel';
2
+ import { type PromosGridProps } from './PromosGrid';
3
+ export type PromosProps = PromosCarouselProps | PromosGridProps;
15
4
  export declare function Promos(props: PromosProps): Promise<import("react/jsx-runtime").JSX.Element>;
@@ -1,2 +1,13 @@
1
- import type { PromosProps } from './Promos';
2
- export declare function PromosCarousel(props: PromosProps): import("react/jsx-runtime").JSX.Element;
1
+ export interface PromosCarouselProps {
2
+ layout: 'carousel';
3
+ /** @default "Promotions" */
4
+ heading?: string;
5
+ /** @default "/promos" */
6
+ viewAllUrl?: string;
7
+ /** @default "/promos" */
8
+ viewPromoDetailsUrl?: string;
9
+ /** @default "/promos/cashback" */
10
+ viewCashbackDetailsUrl?: string;
11
+ className?: string;
12
+ }
13
+ export declare function PromosCarousel(props: PromosCarouselProps): import("react/jsx-runtime").JSX.Element;
@@ -1,2 +1,11 @@
1
- import type { PromosProps } from './Promos';
2
- export declare function PromosGrid(props: PromosProps): import("react/jsx-runtime").JSX.Element;
1
+ export interface PromosGridProps {
2
+ layout: 'grid';
3
+ /** @default "Promotions" */
4
+ heading?: string;
5
+ /** @default "/promos" */
6
+ viewPromoDetailsUrl?: string;
7
+ /** @default "/promos/cashback" */
8
+ viewCashbackDetailsUrl?: string;
9
+ className?: string;
10
+ }
11
+ export declare function PromosGrid(props: PromosGridProps): import("react/jsx-runtime").JSX.Element;
@@ -16,6 +16,7 @@ interface SearchProps {
16
16
  * ```
17
17
  */
18
18
  viewGamesUrl?: string | ((gameProvider: GameProviderData) => string);
19
+ gameProviderImages?: Partial<Record<GameProvider, ImageProps['src']>>;
19
20
  }
20
21
  export declare function Search(props: SearchProps): import("react/jsx-runtime").JSX.Element;
21
22
  export {};
@@ -56,7 +56,8 @@ export function Search(props) {
56
56
  }, 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: () => {
57
57
  setSearch('');
58
58
  inputRef.current?.focus();
59
- }, 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: [empty && _jsx(Alert, { message: "No results found" }), !empty && (_jsxs(_Fragment, { children: [gameProviders.length > 0 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "text-lg font-semibold", children: "Providers" }), _jsx("div", { className: "mt-3.5 grid grid-cols-3 gap-1.5 lg:grid-cols-9 lg:gap-3.5", children: gameProviders.map((provider) => (_jsx(Link, { href: viewGamesUrl(provider), "aria-label": `View ${provider.name} games`, className: "bg-gray-800 flex h-14 w-full items-center rounded-md", children: _jsx(Image, { src: provider.logo, alt: "", width: 100, height: 50, className: "mx-auto h-auto w-full" }) }, provider.id))) })] })), games.length > 0 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "mt-3xl 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: () => {
59
+ }, 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: [empty && _jsx(Alert, { message: "No results found" }), !empty && (_jsxs(_Fragment, { children: [gameProviders.length > 0 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "text-lg font-semibold", children: "Providers" }), _jsx("div", { className: "mt-3.5 grid grid-cols-3 gap-1.5 lg:grid-cols-9 lg:gap-3.5", children: gameProviders.map((provider) => (_jsx(Link, { href: viewGamesUrl(provider), "aria-label": `View ${provider.name} games`, className: "bg-gray-800 flex h-14 w-full items-center rounded-md", children: _jsx(Image, { src: props.gameProviderImages?.[provider.id] ??
60
+ provider.logo, alt: "", width: 100, height: 50, className: "mx-auto h-auto w-full" }) }, provider.id))) })] })), games.length > 0 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "mt-3xl 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: () => {
60
61
  globalStore.search.setOpen(false);
61
62
  }, 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" }) })] }))] })) })] }) })] }) }));
62
63
  }
@@ -4,5 +4,5 @@ import { DepositRecordsTable } from './DepositRecordsTable.js';
4
4
  import { TransactionRecordsTable } from './TransactionRecordsTable.js';
5
5
  import { WithdrawalRecordsTable } from './WithdrawalRecordsTable.js';
6
6
  export function TransactionRecords(props) {
7
- return (_jsxs("div", { className: props.className, children: [_jsx("h2", { className: "text-sm font-semibold leading-tight lg:text-lg", children: "Transactions" }), _jsx("p", { className: "text-text-tertiary-600 mt-xs text-sm leading-tight", children: "View your transaction records" }), _jsxs(Tabs.Root, { className: "mt-lg lg:mt-2xl", defaultValue: "transactions", lazyMount: true, unmountOnExit: true, children: [_jsxs(Tabs.List, { children: [_jsx(Tabs.Trigger, { value: "transactions", children: "Transactions" }), _jsx(Tabs.Trigger, { value: "deposits", children: "Deposits" }), _jsx(Tabs.Trigger, { value: "withdrawals", children: "Withdrawals" }), _jsx(Tabs.Indicator, {})] }), _jsx("div", { className: "border-border-secondary mt-2xl hidden border-t lg:block" }), _jsx("h3", { className: "text-text-secondary-700 mt-3xl text-sm font-semibold", children: "Table" }), _jsx(Tabs.Content, { value: "transactions", className: "mt-xl", children: _jsx(TransactionRecordsTable, {}) }), _jsx(Tabs.Content, { value: "deposits", className: "mt-xl", children: _jsx(DepositRecordsTable, {}) }), _jsx(Tabs.Content, { value: "withdrawals", className: "mt-xl", children: _jsx(WithdrawalRecordsTable, {}) })] })] }));
7
+ return (_jsxs("div", { className: props.className, children: [_jsx("h2", { className: "text-sm font-semibold leading-tight lg:text-lg", children: "Transactions" }), _jsx("p", { className: "text-text-tertiary-600 mt-xs text-sm leading-tight", children: "View your transaction records" }), _jsxs(Tabs.Root, { className: "mt-lg lg:mt-2xl", defaultValue: "transactions", lazyMount: true, unmountOnExit: true, children: [_jsxs(Tabs.List, { children: [_jsx(Tabs.Trigger, { value: "transactions", children: "All Transactions" }), _jsx(Tabs.Trigger, { value: "deposits", children: "Deposits" }), _jsx(Tabs.Trigger, { value: "withdrawals", children: "Withdrawals" }), _jsx(Tabs.Indicator, {})] }), _jsx("div", { className: "border-border-secondary mt-2xl hidden border-t lg:block" }), _jsx("h3", { className: "text-text-secondary-700 mt-3xl text-sm font-semibold", children: "Table" }), _jsx(Tabs.Content, { value: "transactions", className: "mt-xl", children: _jsx(TransactionRecordsTable, {}) }), _jsx(Tabs.Content, { value: "deposits", className: "mt-xl", children: _jsx(DepositRecordsTable, {}) }), _jsx(Tabs.Content, { value: "withdrawals", className: "mt-xl", children: _jsx(WithdrawalRecordsTable, {}) })] })] }));
8
8
  }
@@ -101,7 +101,7 @@ export const GAME_PROVIDER_DATA = {
101
101
  id: 'ETENGJUE',
102
102
  name: 'Etengjue',
103
103
  slug: 'etengjue',
104
- logo: '' /* FIXME */,
104
+ logo: '',
105
105
  },
106
106
  EVOLUTION: {
107
107
  id: 'EVOLUTION',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opexa/portal-components",
3
- "version": "0.0.78",
3
+ "version": "0.0.80",
4
4
  "exports": {
5
5
  ".": {
6
6
  "types": "./dist/components/index.d.ts",