@opexa/portal-components 0.0.633 → 0.0.634

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.
@@ -5,6 +5,8 @@ export interface ClassNameEntries {
5
5
  root?: string;
6
6
  thumbnailRoot?: string;
7
7
  thumbnailImage?: string;
8
+ thumbnailContainer?: string;
9
+ thumbnailRootContainer?: string;
8
10
  }
9
11
  export interface GameProvidersCarouselProps {
10
12
  layout: 'carousel';
@@ -28,5 +30,6 @@ export interface GameProvidersCarouselProps {
28
30
  gameProviderImages?: Partial<Record<GameProvider, ImageProps['src']>>;
29
31
  className?: string | ClassNameEntries;
30
32
  futureGameProviders?: GameProvider[];
33
+ hasSeeAll?: boolean;
31
34
  }
32
- export declare function GameProvidersCarousel(props: GameProvidersCarouselProps): import("react/jsx-runtime").JSX.Element;
35
+ export declare function GameProvidersCarousel({ hasSeeAll, ...props }: GameProvidersCarouselProps): import("react/jsx-runtime").JSX.Element;
@@ -13,7 +13,7 @@ import { ArrowRightIcon } from '../../icons/ArrowRightIcon.js';
13
13
  import { ChevronRightIcon } from '../../icons/ChevronRightIcon.js';
14
14
  import { Button } from '../../ui/Button/index.js';
15
15
  import { callIfFn } from '../../utils/callIfFn.js';
16
- export function GameProvidersCarousel(props) {
16
+ export function GameProvidersCarousel({ hasSeeAll = true, ...props }) {
17
17
  const [emblaRef, emblaApi] = useEmblaCarousel({
18
18
  align: 'start',
19
19
  slidesToScroll: 3,
@@ -56,5 +56,5 @@ export function GameProvidersCarousel(props) {
56
56
  const classNames = isString(props.className)
57
57
  ? { root: props.className }
58
58
  : (props.className ?? {});
59
- return (_jsxs("div", { className: classNames.root, children: [_jsxs("div", { className: "flex items-center", children: [_jsx("h2", { className: "font-semibold text-lg", children: props.heading ?? 'Providers' }), _jsx("div", { className: "grow" }), _jsxs("div", { className: "flex items-center justify-center gap-xl", children: [_jsxs(Link, { href: viewAllUrl, className: "flex gap-sm font-semibold text-button-tertiary-fg text-sm", 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 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('flex h-full w-full items-center overflow-hidden rounded-md bg-brand-800 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))) }) })] }));
59
+ return (_jsxs("div", { className: classNames.root, children: [_jsxs("div", { className: "flex items-center", children: [_jsx("h2", { className: "font-semibold text-lg", children: props.heading ?? 'Providers' }), _jsx("div", { className: "grow" }), _jsxs("div", { className: "flex items-center justify-center gap-xl", children: [hasSeeAll && (_jsxs(Link, { href: viewAllUrl, className: "flex gap-sm font-semibold text-button-tertiary-fg text-sm", 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: twMerge('relative mt-lg overflow-hidden', classNames.thumbnailRootContainer), children: _jsx("div", { className: twMerge('grid auto-cols-[calc((100%-(0.375rem*2))/3)] grid-flow-col grid-rows-1 gap-sm lg:auto-cols-[calc((100%-(0.5rem*5))/6)] lg:gap-md', classNames.thumbnailContainer), children: gameProviders.map((provider) => (_jsx(Link, { href: viewGamesUrl(provider), className: twMerge('flex h-full w-full items-center overflow-hidden rounded-md bg-brand-800 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))) }) })] }));
60
60
  }
@@ -28,6 +28,10 @@ export const PushNotification = () => {
28
28
  await registerFCMDevice({
29
29
  type: platform === 'android' ? 'ANDROID' : 'IOS',
30
30
  token: value,
31
+ }, {
32
+ headers: {
33
+ Authorization: `Bearer ${session.data.token}`,
34
+ },
31
35
  });
32
36
  }
33
37
  });
@@ -18,5 +18,6 @@ export interface QuestsProps {
18
18
  showTurnoverDecimals?: boolean;
19
19
  /** Optional styling hook for checkbox control inside specific quests */
20
20
  checkboxControlStyle?: CSSProperties;
21
+ gameProviderCarousel?: ReactNode;
21
22
  }
22
23
  export declare function Quests__client(props: QuestsProps): import("react/jsx-runtime").JSX.Element;
@@ -61,7 +61,9 @@ export function Quests__client(props) {
61
61
  ? classNames?.journeyQuest
62
62
  : '', uncompletedIcon: props.uncompletedIcon, customComplete: quest.type === 'WAGERING'
63
63
  ? props.customComplete
64
- : undefined, showTurnoverDecimals: props.showTurnoverDecimals, ...(quest.type === 'JOURNEY' || quest.type === 'ONBOARDING'
64
+ : undefined, ...(quest.type === 'WAGERING' && {
65
+ gameProviderCarousel: props.gameProviderCarousel,
66
+ }), showTurnoverDecimals: props.showTurnoverDecimals, ...(quest.type === 'JOURNEY' || quest.type === 'ONBOARDING'
65
67
  ? {
66
68
  checkboxControlStyle: props.checkboxControlStyle,
67
69
  }
@@ -1,4 +1,4 @@
1
- import { type ReactNode } from 'react';
1
+ import type { ReactNode } from 'react';
2
2
  export interface ClassNameEntries {
3
3
  root?: string;
4
4
  progressBarContainer?: string;
@@ -11,4 +11,5 @@ export declare function WageringQuest(props: {
11
11
  className?: string | ClassNameEntries;
12
12
  customComplete?: ReactNode;
13
13
  showTurnoverDecimals?: boolean;
14
+ gameProviderCarousel?: ReactNode;
14
15
  }): import("react/jsx-runtime").JSX.Element;
@@ -1,26 +1,18 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import useEmblaCarousel, {} from 'embla-carousel-react';
4
3
  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
4
  import { twMerge } from 'tailwind-merge';
9
5
  import { useControllableState } from '../../client/hooks/useControllableState.js';
10
6
  import { useDisclosure } from '../../client/hooks/useDisclosure.js';
11
7
  import { useFeatureFlag } from '../../client/hooks/useFeatureFlag.js';
12
8
  import { useLocaleInfo } from '../../client/hooks/useLocaleInfo.js';
13
9
  import { useRemainingTime } from '../../client/hooks/useRemainingTime.js';
14
- import { GAME_PROVIDER_DATA } from '../../constants/index.js';
15
- import { ArrowLeftIcon } from '../../icons/ArrowLeftIcon.js';
16
- import { ArrowRightIcon } from '../../icons/ArrowRightIcon.js';
17
10
  import { InfoCircleIcon } from '../../icons/InfoCircleIcon.js';
18
11
  import { XIcon } from '../../icons/XIcon.js';
19
12
  import { Button } from '../../ui/Button/index.js';
20
13
  import { Dialog } from '../../ui/Dialog/index.js';
21
14
  import { Portal } from '../../ui/Portal/index.js';
22
15
  import { Prose } from '../../ui/Prose/index.js';
23
- import { callIfFn } from '../../utils/callIfFn.js';
24
16
  import { parseDecimal } from '../../utils/parseDecimal.js';
25
17
  import { useQuestContext } from './QuestsContext.js';
26
18
  import { RemainingTime } from './RemainingTime.js';
@@ -43,7 +35,7 @@ export function WageringQuest(props) {
43
35
  return (_jsxs(_Fragment, { children: [_jsxs("div", { className: twMerge('flex h-full w-full flex-col space-y-6 rounded-2xl border border-border-primary bg-bg-tertiary px-4 pt-5 pb-6', classNames?.root), 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(RemainingTime, {}), _jsx("button", { type: "button", className: "flex size-9 cursor-pointer items-center justify-center rounded-md border border-border-secondary bg-bg-primary", onClick: () => disclosure.setOpen(true), "aria-label": "View Rules", children: _jsx(InfoCircleIcon, { className: "size-5 text-text-disabled" }) })] }), _jsx("p", { className: "font-semibold text-xl", children: name }), _jsx(Prose, { className: "text-wrap font-normal text-sm text-text-secondary-700", dangerouslySetInnerHTML: { __html: description } })] }), _jsxs("div", { className: "flex w-full flex-col space-y-2", children: [_jsxs("div", { className: "group flex items-center justify-between text-text-primary-brand", children: [_jsxs("p", { children: ["Progress ", parseDecimal(progressPercentage, 0).toFixed(2), "%"] }), _jsxs("p", { children: [formatTurnover(turnover), _jsxs("span", { className: "text-text-quarterary-brand", children: ["/", targetTurnover, " ", localeInfo.currency.code] })] })] }), _jsx("div", { className: twMerge('h-2 w-full overflow-hidden rounded-full bg-bg-primary', classNames?.progressBarContainer), children: _jsx("div", { className: twMerge('h-full rounded-full bg-utility-brand-600 transition-all duration-300', classNames?.progressBar), style: { width: `${progressPercentage}%` } }) })] }), _jsx("div", { className: "flex h-full items-end", children: _jsx("div", { className: twMerge('w-full rounded-md border border-bg-primary-hover bg-button-secondary-bg px-3.5 py-2.5 text-center', classNames?.bonusContainer), children: status === 'COMPLETED' && customComplete ? (_jsx("div", { className: twMerge(classNames?.bonusText), children: customComplete })) : (_jsxs("p", { className: twMerge((remainingTime.expired ||
44
36
  status === 'COMPLETED' ||
45
37
  status === 'FAILED') &&
46
- 'opacity-50 grayscale', classNames?.bonusText), children: ["Complete to get", ' ', _jsxs("span", { className: twMerge('text-brand-400', classNames?.bonusAmount), children: ["\u20B1", bonus] }), ' ', "bonus!"] })) }) })] }), _jsx(Rules, { open: disclosure.open, onOpenChange: disclosure.setOpen })] }));
38
+ 'opacity-50 grayscale', classNames?.bonusText), children: ["Complete to get", ' ', _jsxs("span", { className: twMerge('text-brand-400', classNames?.bonusAmount), children: ["\u20B1", bonus] }), ' ', "bonus!"] })) }) })] }), _jsx(Rules, { open: disclosure.open, onOpenChange: disclosure.setOpen, gameProviderCarousel: props.gameProviderCarousel })] }));
47
39
  }
48
40
  function Rules(props) {
49
41
  const quest = useQuestContext();
@@ -53,61 +45,5 @@ function Rules(props) {
53
45
  defaultValue: props.defaultOpen ?? false,
54
46
  onChange: props.onOpenChange,
55
47
  });
56
- return (_jsx(Dialog.Root, { lazyMount: true, unmountOnExit: true, open: open, onOpenChange: (details) => setOpen(details.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: "mx-auto min-h-auto max-w-[21.438rem] overflow-y-auto rounded-xl px-4 pt-5 pb-0", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsxs("div", { className: "flex flex-col space-y-5", children: [_jsx("h2", { className: "font-semibold text-lg text-text-primary-900", children: quest.name }), _jsxs("ol", { className: "group list-disc text-wrap pl-4 font-normal text-sm text-text-tertiary-600", 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." })] })] }), featureFlag.enabled && (_jsx(GameProvidersCarousel, { layout: "carousel", gameProviders: [
57
- 'JILI',
58
- 'PRAGMATICPLAY',
59
- 'HOLLYWOODTV',
60
- 'ALIZE',
61
- 'BTI',
62
- 'CQ9',
63
- 'DARWIN',
64
- 'DG',
65
- 'EVOLUTION_NETENT',
66
- 'EVOLUTION_REDTIGER',
67
- 'EZUGI',
68
- ] })), _jsx("div", { className: "pt-6 pb-4", children: _jsx(Button, { onClick: () => setOpen(false), children: "Ok" }) })] }) })] }) }));
69
- }
70
- function GameProvidersCarousel(props) {
71
- const [emblaRef, emblaApi] = useEmblaCarousel({
72
- align: 'start',
73
- slidesToScroll: 3,
74
- breakpoints: {
75
- '(min-width: 1024px)': {
76
- align: 'start',
77
- slidesToScroll: 6,
78
- },
79
- },
80
- });
81
- const [prevBtnDisabled, setPrevBtnDisabled] = useState(true);
82
- const [nextBtnDisabled, setNextBtnDisabled] = useState(true);
83
- const onPrevButtonClick = useCallback(() => emblaApi?.scrollPrev(), [emblaApi]);
84
- const onNextButtonClick = useCallback(async () => {
85
- emblaApi?.scrollNext();
86
- }, [emblaApi]);
87
- const onSelect = useCallback((emblaApi) => {
88
- setPrevBtnDisabled(!emblaApi?.canScrollPrev());
89
- setNextBtnDisabled(!emblaApi?.canScrollNext());
90
- }, []);
91
- useEffect(() => {
92
- if (!emblaApi)
93
- return;
94
- onSelect(emblaApi);
95
- emblaApi.on('reInit', onSelect).on('select', onSelect);
96
- }, [emblaApi, onSelect]);
97
- const viewGamesUrl = (data) => {
98
- return props.viewGamesUrl
99
- ? callIfFn(props.viewGamesUrl, data)
100
- .replace(':id', data?.id)
101
- .replace(':slug', data?.slug)
102
- : `/providers/${data.slug}`;
103
- };
104
- const { enabled } = useFeatureFlag();
105
- const combinedProviders = enabled
106
- ? [...props.gameProviders, ...(props.futureGameProviders ?? [])]
107
- : props.gameProviders;
108
- const gameProviders = combinedProviders.map((provider) => GAME_PROVIDER_DATA[provider]);
109
- const classNames = isString(props.className)
110
- ? { root: props.className }
111
- : (props.className ?? {});
112
- return (_jsxs("div", { className: "mt-6", children: [_jsxs("div", { className: "flex items-center", children: [_jsx("h2", { className: "font-semibold text-lg", children: props.heading ?? 'Providers' }), _jsx("div", { className: "grow" }), _jsx("div", { className: "flex items-center justify-center gap-xl", children: _jsxs("div", { className: "hidden lg:flex", children: [_jsx(Button, { variant: "outline", colorScheme: "gray", className: "rounded-r-none border-r-0", onClick: onPrevButtonClick, disabled: prevBtnDisabled, "aria-label": "Previous", children: _jsx(ArrowLeftIcon, { className: "size-5" }) }), _jsx(Button, { variant: "outline", colorScheme: "gray", className: "rounded-l-none", onClick: onNextButtonClick, disabled: nextBtnDisabled, "aria-label": "Next", children: _jsx(ArrowRightIcon, { className: "size-5" }) })] }) })] }), _jsx("div", { ref: emblaRef, className: "relative mt-lg overflow-hidden", children: _jsx("div", { className: "grid grid-flow-col grid-rows-1 gap-md", children: gameProviders.map((provider) => (_jsx(Link, { href: viewGamesUrl(provider), className: twMerge('flex h-[3.5rem] w-[110px] items-center overflow-hidden rounded-md bg-brand-800', 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))) }) })] }));
48
+ return (_jsx(Dialog.Root, { lazyMount: true, unmountOnExit: true, open: open, onOpenChange: (details) => setOpen(details.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: "mx-auto min-h-auto max-w-[21.438rem] overflow-y-auto rounded-xl px-4 pt-5 pb-0", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsxs("div", { className: "flex flex-col space-y-5", children: [_jsx("h2", { className: "font-semibold text-lg text-text-primary-900", children: quest.name }), _jsxs("ol", { className: "group list-disc text-wrap pl-4 font-normal text-sm text-text-tertiary-600", 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." })] })] }), featureFlag.enabled && props?.gameProviderCarousel, _jsx("div", { className: "pt-6 pb-4", children: _jsx(Button, { onClick: () => setOpen(false), children: "Ok" }) })] }) })] }) }));
113
49
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opexa/portal-components",
3
- "version": "0.0.633",
3
+ "version": "0.0.634",
4
4
  "exports": {
5
5
  "./ui/*": {
6
6
  "types": "./dist/ui/*/index.d.ts",