@opexa/portal-components 0.0.828 → 0.0.830
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/hooks/useBypassKycChecker.d.ts +5 -0
- package/dist/client/hooks/useBypassKycChecker.js +14 -0
- package/dist/components/DepositWithdrawal/Deposit/QRPHDeposit/QRPHDepositContext.d.ts +2 -2
- package/dist/components/DepositWithdrawal/Deposit/QRPHDeposit/useQRPHDeposit.d.ts +1 -1
- package/dist/components/DepositWithdrawal/DepositWithdrawal.lazy.d.ts +5 -1
- package/dist/components/DepositWithdrawal/DepositWithdrawal.lazy.js +3 -0
- package/dist/components/DepositWithdrawal/DepositWithdrawalContext.d.ts +3 -3
- package/dist/components/FavoriteGames/FavoriteGames.client.d.ts +2 -1
- package/dist/components/FavoriteGames/FavoriteGames.client.js +3 -1
- package/dist/components/Games/GamesCarousel.client.d.ts +2 -1
- package/dist/components/Games/GamesCarousel.client.js +3 -1
- package/dist/components/Games/GamesList.client.d.ts +2 -1
- package/dist/components/Games/GamesList.client.js +3 -1
- package/dist/components/GamesSearch/GamesSearch.d.ts +2 -1
- package/dist/components/GamesSearch/GamesSearch.js +3 -1
- package/dist/components/MixpanelTracking/get-utm.d.ts +18 -0
- package/dist/components/MixpanelTracking/get-utm.js +44 -0
- package/dist/components/MixpanelTracking/index.d.ts +5 -0
- package/dist/components/MixpanelTracking/index.js +109 -0
- package/dist/components/Search/Search.lazy.d.ts +2 -1
- package/dist/components/Search/Search.lazy.js +3 -1
- package/dist/next.config.js +3 -0
- package/package.json +2 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
export function useBypassKycChecker(bypassDomains) {
|
|
4
|
+
const isBypassKyc = useMemo(() => {
|
|
5
|
+
if (typeof window === 'undefined' ||
|
|
6
|
+
!bypassDomains ||
|
|
7
|
+
bypassDomains.length === 0) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
const host = window.location.hostname;
|
|
11
|
+
return bypassDomains.some(({ domain, isBypass }) => isBypass && host === domain);
|
|
12
|
+
}, [bypassDomains]);
|
|
13
|
+
return isBypassKyc;
|
|
14
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const QRPHDepositContext: (props: {
|
|
2
2
|
value: {
|
|
3
|
-
status: "
|
|
3
|
+
status: "idle" | "confirmed" | "failed" | "generating-qr-code" | "qr-code-generated";
|
|
4
4
|
deposit: import("../../../../types").Deposit | null;
|
|
5
5
|
generateQRCode: (input: import("./useQRPHDeposit").GenerateQRCodeInput) => Promise<void>;
|
|
6
6
|
regenerateQRCode: () => Promise<void>;
|
|
@@ -9,7 +9,7 @@ export declare const QRPHDepositContext: (props: {
|
|
|
9
9
|
} & {
|
|
10
10
|
children?: import("react").ReactNode | undefined;
|
|
11
11
|
}) => React.ReactNode, useQRPHDepositContext: () => {
|
|
12
|
-
status: "
|
|
12
|
+
status: "idle" | "confirmed" | "failed" | "generating-qr-code" | "qr-code-generated";
|
|
13
13
|
deposit: import("../../../../types").Deposit | null;
|
|
14
14
|
generateQRCode: (input: import("./useQRPHDeposit").GenerateQRCodeInput) => Promise<void>;
|
|
15
15
|
regenerateQRCode: () => Promise<void>;
|
|
@@ -5,7 +5,7 @@ export interface GenerateQRCodeInput {
|
|
|
5
5
|
promo?: string | null;
|
|
6
6
|
}
|
|
7
7
|
export declare function useQRPHDeposit(): {
|
|
8
|
-
status: "
|
|
8
|
+
status: "idle" | "confirmed" | "failed" | "generating-qr-code" | "qr-code-generated";
|
|
9
9
|
deposit: Deposit | null;
|
|
10
10
|
generateQRCode: (input: GenerateQRCodeInput) => Promise<void>;
|
|
11
11
|
regenerateQRCode: () => Promise<void>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type BypassDomainConfig } from '../../client/hooks/useBypassKycChecker';
|
|
1
2
|
export interface DepositWithdrawalProps {
|
|
2
3
|
/** @default "/terms-of-use" */
|
|
3
4
|
termsOfUseUrl?: string;
|
|
@@ -8,6 +9,9 @@ export interface DepositWithdrawalProps {
|
|
|
8
9
|
allowUnverifiedAccounts?: boolean;
|
|
9
10
|
libanganRedirectionUrl?: string;
|
|
10
11
|
hasPrivacyPolicyAndTermsOfUse?: boolean;
|
|
11
|
-
|
|
12
|
+
bypassDomains?: BypassDomainConfig[];
|
|
13
|
+
}
|
|
14
|
+
export interface ExtendedDepositWithdrawalProps extends DepositWithdrawalProps {
|
|
15
|
+
bypassDepositKycCheck: boolean;
|
|
12
16
|
}
|
|
13
17
|
export declare function DepositWithdrawal(props: DepositWithdrawalProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -4,6 +4,7 @@ import { useEffect } from 'react';
|
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { useShallow } from 'zustand/shallow';
|
|
6
6
|
import { useBonusesQuery } from '../../client/hooks/useBonusesQuery.js';
|
|
7
|
+
import { useBypassKycChecker, } from '../../client/hooks/useBypassKycChecker.js';
|
|
7
8
|
import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
|
|
8
9
|
import { useLocaleInfo } from '../../client/hooks/useLocaleInfo.js';
|
|
9
10
|
import { useWalletQuery } from '../../client/hooks/useWalletQuery.js';
|
|
@@ -19,10 +20,12 @@ import { DepositWithdrawalPropsProvider } from './DepositWithdrawalContext.js';
|
|
|
19
20
|
import { HasPendingBonuses } from './HasPendingBonuses.js';
|
|
20
21
|
import { Withdrawal } from './Withdrawal/Withdrawal.js';
|
|
21
22
|
export function DepositWithdrawal(props) {
|
|
23
|
+
const bypassDepositKycCheck = useBypassKycChecker(props.bypassDomains);
|
|
22
24
|
const { hasPrivacyPolicyAndTermsOfUse = true, ...restProps } = props;
|
|
23
25
|
const mergedProps = {
|
|
24
26
|
...restProps,
|
|
25
27
|
hasPrivacyPolicyAndTermsOfUse,
|
|
28
|
+
bypassDepositKycCheck,
|
|
26
29
|
};
|
|
27
30
|
const globalStore = useGlobalStore(useShallow((ctx) => ({
|
|
28
31
|
depositWithdrawal: ctx.depositWithdrawal,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ExtendedDepositWithdrawalProps } from './DepositWithdrawal.lazy';
|
|
2
2
|
export declare const DepositWithdrawalPropsProvider: (props: {
|
|
3
|
-
value:
|
|
3
|
+
value: ExtendedDepositWithdrawalProps;
|
|
4
4
|
} & {
|
|
5
5
|
children?: import("react").ReactNode | undefined;
|
|
6
|
-
}) => React.ReactNode, useDepositWithdrawalPropsContext: () =>
|
|
6
|
+
}) => React.ReactNode, useDepositWithdrawalPropsContext: () => ExtendedDepositWithdrawalProps;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
+
import { type BypassDomainConfig } from '../../client/hooks/useBypassKycChecker';
|
|
2
3
|
interface ClassNameEntries {
|
|
3
4
|
root?: string;
|
|
4
5
|
thumbnailRoot?: string;
|
|
@@ -8,7 +9,7 @@ export interface FavoriteGamesProps {
|
|
|
8
9
|
className?: string | ClassNameEntries;
|
|
9
10
|
/** @default 'Favorite Games' */
|
|
10
11
|
heading?: string | ReactNode;
|
|
11
|
-
|
|
12
|
+
bypassDomains?: BypassDomainConfig[];
|
|
12
13
|
}
|
|
13
14
|
export declare function FavoriteGames__client(props: FavoriteGamesProps): import("react/jsx-runtime").JSX.Element | null;
|
|
14
15
|
export {};
|
|
@@ -6,6 +6,7 @@ import Image from 'next/image';
|
|
|
6
6
|
import { useCallback, useEffect, useState } from 'react';
|
|
7
7
|
import { twMerge } from 'tailwind-merge';
|
|
8
8
|
import { useAccountQuery } from '../../client/hooks/useAccountQuery.js';
|
|
9
|
+
import { useBypassKycChecker, } from '../../client/hooks/useBypassKycChecker.js';
|
|
9
10
|
import { useFavoriteGamesQuery } from '../../client/hooks/useFavoriteGamesQuery.js';
|
|
10
11
|
import { useFeatureFlag } from '../../client/hooks/useFeatureFlag.js';
|
|
11
12
|
import { useSessionQuery } from '../../client/hooks/useSessionQuery.js';
|
|
@@ -18,6 +19,7 @@ import { Button } from '../../ui/Button/index.js';
|
|
|
18
19
|
import { getGameImageUrl } from '../../utils/getGameImageUrl.js';
|
|
19
20
|
import { GameLaunchTrigger } from '../GameLaunch/index.js';
|
|
20
21
|
export function FavoriteGames__client(props) {
|
|
22
|
+
const isBypass = useBypassKycChecker(props.bypassDomains);
|
|
21
23
|
const [emblaRef, emblaApi] = useEmblaCarousel({
|
|
22
24
|
align: 'start',
|
|
23
25
|
slidesToScroll: 3,
|
|
@@ -50,7 +52,7 @@ export function FavoriteGames__client(props) {
|
|
|
50
52
|
const classNames = isString(props.className)
|
|
51
53
|
? { root: props.className }
|
|
52
54
|
: (props.className ?? {});
|
|
53
|
-
return (_jsxs("div", { className: classNames.root, children: [_jsxs("div", { className: "flex items-center", children: [_jsx("h2", { className: "font-semibold text-lg", children: props.heading ?? 'Favorite Games' }), _jsx("div", { className: "grow" }), _jsx("div", { className: "flex items-center justify-center gap-xl", children: _jsxs("div", { className: "hidden lg:flex", children: [_jsx(Button, { variant: "outline", colorScheme: "gray", className: "rounded-r-none border-r-0", onClick: onPrevButtonClick, disabled: prevBtnDisabled, "aria-label": "Previous", children: _jsx(ArrowLeftIcon, { className: "size-5" }) }), _jsx(Button, { variant: "outline", colorScheme: "gray", className: "rounded-l-none", onClick: onNextButtonClick, disabled: nextBtnDisabled, "aria-label": "Next", children: _jsx(ArrowRightIcon, { className: "size-5" }) })] }) })] }), _jsx("div", { ref: emblaRef, className: "relative mt-lg lg:overflow-hidden", children: _jsx("div", { className: twMerge('grid auto-cols-[calc((100%-(0.375rem*2))/3)] grid-flow-col grid-rows-1 gap-sm lg:auto-cols-[calc((100%-(0.5rem*5))/6)] lg:gap-md'), children: games.map((game) => (_jsx(Item, { bypassKycCheck:
|
|
55
|
+
return (_jsxs("div", { className: classNames.root, children: [_jsxs("div", { className: "flex items-center", children: [_jsx("h2", { className: "font-semibold text-lg", children: props.heading ?? 'Favorite Games' }), _jsx("div", { className: "grow" }), _jsx("div", { className: "flex items-center justify-center gap-xl", children: _jsxs("div", { className: "hidden lg:flex", children: [_jsx(Button, { variant: "outline", colorScheme: "gray", className: "rounded-r-none border-r-0", onClick: onPrevButtonClick, disabled: prevBtnDisabled, "aria-label": "Previous", children: _jsx(ArrowLeftIcon, { className: "size-5" }) }), _jsx(Button, { variant: "outline", colorScheme: "gray", className: "rounded-l-none", onClick: onNextButtonClick, disabled: nextBtnDisabled, "aria-label": "Next", children: _jsx(ArrowRightIcon, { className: "size-5" }) })] }) })] }), _jsx("div", { ref: emblaRef, className: "relative mt-lg lg:overflow-hidden", children: _jsx("div", { className: twMerge('grid auto-cols-[calc((100%-(0.375rem*2))/3)] grid-flow-col grid-rows-1 gap-sm lg:auto-cols-[calc((100%-(0.5rem*5))/6)] lg:gap-md'), children: games.map((game) => (_jsx(Item, { bypassKycCheck: isBypass, game: game, className: {
|
|
54
56
|
thumbnailRoot: classNames.thumbnailRoot,
|
|
55
57
|
thumbnailTitle: classNames.thumbnailTitle,
|
|
56
58
|
} }, game.id))) }) })] }));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ImageProps } from 'next/image';
|
|
2
2
|
import { type ReactNode } from 'react';
|
|
3
|
+
import { type BypassDomainConfig } from '../../client/hooks/useBypassKycChecker';
|
|
3
4
|
import type { GamesInput__Next } from '../../services/cmsPortal';
|
|
4
5
|
import type { GameProvider } from '../../types';
|
|
5
6
|
interface ClassNameEntries {
|
|
@@ -24,7 +25,7 @@ export interface GamesCarouselProps {
|
|
|
24
25
|
sort?: GamesInput__Next['sort'];
|
|
25
26
|
className?: string | ClassNameEntries;
|
|
26
27
|
fallbackThumbnails?: Partial<Record<GameProvider, ImageProps['src']>>;
|
|
27
|
-
|
|
28
|
+
bypassDomains?: BypassDomainConfig[];
|
|
28
29
|
}
|
|
29
30
|
export declare function GamesCarousel__client(props: GamesCarouselProps): import("react/jsx-runtime").JSX.Element;
|
|
30
31
|
export {};
|
|
@@ -5,6 +5,7 @@ import { isString } from 'lodash-es';
|
|
|
5
5
|
import Link from 'next/link';
|
|
6
6
|
import { useCallback, useEffect, useState } from 'react';
|
|
7
7
|
import { twMerge } from 'tailwind-merge';
|
|
8
|
+
import { useBypassKycChecker, } from '../../client/hooks/useBypassKycChecker.js';
|
|
8
9
|
import { useGamesQuery } from '../../client/hooks/useGamesQuery.js';
|
|
9
10
|
import { ArrowLeftIcon } from '../../icons/ArrowLeftIcon.js';
|
|
10
11
|
import { ArrowRightIcon } from '../../icons/ArrowRightIcon.js';
|
|
@@ -16,6 +17,7 @@ import { Empty } from '../shared/Empty.js';
|
|
|
16
17
|
import { Game } from './Game.js';
|
|
17
18
|
import { GameContext, GamesPropsContext } from './GamesContext.js';
|
|
18
19
|
export function GamesCarousel__client(props) {
|
|
20
|
+
const isBypass = useBypassKycChecker(props.bypassDomains);
|
|
19
21
|
const numOfRows = props.numOfRows ?? 1;
|
|
20
22
|
const gamesQuery = useGamesQuery({
|
|
21
23
|
first: (numOfRows + 1) * 6,
|
|
@@ -63,7 +65,7 @@ export function GamesCarousel__client(props) {
|
|
|
63
65
|
? 'grid-rows-3'
|
|
64
66
|
: numOfRows === 2
|
|
65
67
|
? 'grid-rows-2'
|
|
66
|
-
: 'grid-rows-1'), children: games.map((game) => (_jsx(GameContext, { value: game, children: _jsx(Game, { bypassKycCheck:
|
|
68
|
+
: 'grid-rows-1'), children: games.map((game) => (_jsx(GameContext, { value: game, children: _jsx(Game, { bypassKycCheck: isBypass, badge: props.badge, className: {
|
|
67
69
|
root: classNames.thumbnailRoot,
|
|
68
70
|
title: classNames.thumbnailTitle,
|
|
69
71
|
} }) }, game.id))) }) }))] }) }));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ImageProps } from 'next/image';
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
|
+
import { type BypassDomainConfig } from '../../client/hooks/useBypassKycChecker';
|
|
3
4
|
import type { GamesInput__Next } from '../../services/cmsPortal';
|
|
4
5
|
import type { GameProvider } from '../../types';
|
|
5
6
|
interface ClassNameEntries {
|
|
@@ -24,7 +25,7 @@ export interface GamesListProps {
|
|
|
24
25
|
className?: string | ClassNameEntries;
|
|
25
26
|
pagination?: 'lazy-load' | 'paginated';
|
|
26
27
|
fallbackThumbnails?: Partial<Record<GameProvider, ImageProps['src']>>;
|
|
27
|
-
|
|
28
|
+
bypassDomains?: BypassDomainConfig[];
|
|
28
29
|
}
|
|
29
30
|
export declare function GamesList__client(props: GamesListProps): import("react/jsx-runtime").JSX.Element;
|
|
30
31
|
export {};
|
|
@@ -4,6 +4,7 @@ import { isString, noop } from 'lodash-es';
|
|
|
4
4
|
import Link from 'next/link';
|
|
5
5
|
import { useEffect, useState } from 'react';
|
|
6
6
|
import { twMerge } from 'tailwind-merge';
|
|
7
|
+
import { useBypassKycChecker, } from '../../client/hooks/useBypassKycChecker.js';
|
|
7
8
|
import { useGamesQuery } from '../../client/hooks/useGamesQuery.js';
|
|
8
9
|
import { useInfiniteQueryHelper } from '../../client/hooks/useInfiniteQueryHelper.js';
|
|
9
10
|
import { ChevronLeftIcon } from '../../icons/ChevronLeftIcon.js';
|
|
@@ -16,6 +17,7 @@ import { Game } from './Game.js';
|
|
|
16
17
|
import { GameContext, GamesPropsContext } from './GamesContext.js';
|
|
17
18
|
import { GamesPagination } from './GamesPagination.js';
|
|
18
19
|
export function GamesList__client(props) {
|
|
20
|
+
const isBypass = useBypassKycChecker(props.bypassDomains);
|
|
19
21
|
const { pagination = 'lazy-load' } = props;
|
|
20
22
|
const perPage = props.first ?? 24;
|
|
21
23
|
const { loading, availableRows, totalRows, totalAvailableRows, hasNextPage, next, } = useInfiniteQueryHelper(useGamesQuery, {
|
|
@@ -50,7 +52,7 @@ export function GamesList__client(props) {
|
|
|
50
52
|
? props.heading.replaceAll('OneAPI', '')
|
|
51
53
|
: (props.heading ?? 'Games') }), props.viewGameProvidersUrl && (_jsxs(Link, { href: props.viewGameProvidersUrl, className: "order-1 flex items-center gap-sm font-semibold text-button-tertiary-fg text-lg lg:order-none lg:text-sm", children: [_jsx(ChevronLeftIcon, { className: "size-5" }), "Back to all Providers"] }))] }), totalRows <= 0 && (_jsx(Empty, { icon: loading ? SpinnerIcon : GamingPad01Icon, title: loading ? 'Just a moment' : 'No games', message: loading
|
|
52
54
|
? 'Fetching latest games...'
|
|
53
|
-
: '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: (pagination === 'paginated' ? paginatedRows : availableRows).map((game) => (_jsx(GameContext, { value: game, children: _jsx(Game, { bypassKycCheck:
|
|
55
|
+
: '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: (pagination === 'paginated' ? paginatedRows : availableRows).map((game) => (_jsx(GameContext, { value: game, children: _jsx(Game, { bypassKycCheck: isBypass, badge: props.badge, className: {
|
|
54
56
|
root: classNames.thumbnailRoot,
|
|
55
57
|
title: classNames.thumbnailTitle,
|
|
56
58
|
} }) }, game.id))) }), _jsx("div", { className: "mt-2xl flex flex-col items-center lg:mt-3xl", children: pagination === 'paginated' && totalRows > 0 ? (_jsx(GamesPagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (page) => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type BypassDomainConfig } from '../../client/hooks/useBypassKycChecker';
|
|
1
2
|
import type { GamesInput__Next } from '../../services/cmsPortal';
|
|
2
3
|
export interface ClassNameEntries {
|
|
3
4
|
root?: string;
|
|
@@ -11,7 +12,7 @@ interface GamesSearchProps {
|
|
|
11
12
|
sort?: GamesInput__Next['sort'];
|
|
12
13
|
className?: string | ClassNameEntries;
|
|
13
14
|
placeholder?: string;
|
|
14
|
-
|
|
15
|
+
bypassDomains?: BypassDomainConfig[];
|
|
15
16
|
}
|
|
16
17
|
export declare function GamesSearch(props: GamesSearchProps): import("react/jsx-runtime").JSX.Element;
|
|
17
18
|
export {};
|
|
@@ -5,6 +5,7 @@ import { isString } from 'lodash-es';
|
|
|
5
5
|
import Image from 'next/image';
|
|
6
6
|
import { useState } from 'react';
|
|
7
7
|
import { twMerge } from 'tailwind-merge';
|
|
8
|
+
import { useBypassKycChecker, } from '../../client/hooks/useBypassKycChecker.js';
|
|
8
9
|
import { useGamesQuery } from '../../client/hooks/useGamesQuery.js';
|
|
9
10
|
import { SearchLgIcon } from '../../icons/SearchLgIcon.js';
|
|
10
11
|
import { Button } from '../../ui/Button/index.js';
|
|
@@ -14,6 +15,7 @@ import { Presence } from '../../ui/Presence/index.js';
|
|
|
14
15
|
import { getGameImageUrl } from '../../utils/getGameImageUrl.js';
|
|
15
16
|
import { GameLaunchTrigger } from '../GameLaunch/index.js';
|
|
16
17
|
export function GamesSearch(props) {
|
|
18
|
+
const isBypass = useBypassKycChecker(props.bypassDomains);
|
|
17
19
|
const [search, setSearch] = useState('');
|
|
18
20
|
const gamesQuery = useGamesQuery({
|
|
19
21
|
first: props.first ?? 18,
|
|
@@ -44,7 +46,7 @@ export function GamesSearch(props) {
|
|
|
44
46
|
api.setInputValue('');
|
|
45
47
|
api.focus();
|
|
46
48
|
}, children: "Clear" }));
|
|
47
|
-
} })] }), _jsx(Portal, { children: _jsx(Combobox.Context, { children: (api) => (_jsxs(_Fragment, { children: [_jsx(Presence, { present: api.open, children: _jsx("div", { className: "fixed inset-0 z-40 bg-black/50 backdrop-blur-sm", onClick: () => api.setOpen(false) }) }), _jsx(Combobox.Positioner, { children: search.trim().length > 0 && (_jsx(Combobox.Content, { className: "z-50 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-3 gap-1.5 lg:grid-cols-9 lg:gap-3.5", children: games.map((game) => (_jsxs(GameLaunchTrigger, { bypassKycCheck:
|
|
49
|
+
} })] }), _jsx(Portal, { children: _jsx(Combobox.Context, { children: (api) => (_jsxs(_Fragment, { children: [_jsx(Presence, { present: api.open, children: _jsx("div", { className: "fixed inset-0 z-40 bg-black/50 backdrop-blur-sm", onClick: () => api.setOpen(false) }) }), _jsx(Combobox.Positioner, { children: search.trim().length > 0 && (_jsx(Combobox.Content, { className: "z-50 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-3 gap-1.5 lg:grid-cols-9 lg:gap-3.5", children: games.map((game) => (_jsxs(GameLaunchTrigger, { bypassKycCheck: isBypass, game: game, onClick: () => {
|
|
48
50
|
api.setOpen(false);
|
|
49
51
|
}, className: twMerge('block w-full shadow-sm', classNames.thumbnailRoot), children: [_jsx(Image, { src: getGameImageUrl({
|
|
50
52
|
reference: game.reference,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare function getUTMParams(): {
|
|
2
|
+
utm_source: string;
|
|
3
|
+
utm_medium: string;
|
|
4
|
+
utm_campaign: string;
|
|
5
|
+
fbclid: string;
|
|
6
|
+
cxd: string;
|
|
7
|
+
gclid: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function getSourceData(): {
|
|
10
|
+
utm_source: string;
|
|
11
|
+
utm_medium: string;
|
|
12
|
+
utm_campaign: string;
|
|
13
|
+
fbclid: string;
|
|
14
|
+
cxd: string;
|
|
15
|
+
gclid: string;
|
|
16
|
+
referrer: string;
|
|
17
|
+
source: string;
|
|
18
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export function getUTMParams() {
|
|
2
|
+
const params = new URLSearchParams(window.location.search);
|
|
3
|
+
return {
|
|
4
|
+
utm_source: params.get('utm_source') || 'unknown',
|
|
5
|
+
utm_medium: params.get('utm_medium') || 'unknown',
|
|
6
|
+
utm_campaign: params.get('utm_campaign') || 'unknown',
|
|
7
|
+
fbclid: params.get('fbclid') || 'unknown',
|
|
8
|
+
cxd: params.get('cxd') || 'unknown',
|
|
9
|
+
gclid: params.get('gclid') || 'unknown',
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export function getSourceData() {
|
|
13
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
14
|
+
const utmSource = urlParams.get('utm_source');
|
|
15
|
+
const utmMedium = urlParams.get('utm_medium');
|
|
16
|
+
const utmCampaign = urlParams.get('utm_campaign');
|
|
17
|
+
const fbclid = urlParams.get('fbclid');
|
|
18
|
+
const cxd = urlParams.get('cxd');
|
|
19
|
+
const gclid = urlParams.get('gclid');
|
|
20
|
+
const referrer = document.referrer || 'direct';
|
|
21
|
+
let source = 'direct';
|
|
22
|
+
if (utmSource)
|
|
23
|
+
source = utmSource;
|
|
24
|
+
else if (fbclid)
|
|
25
|
+
source = 'facebook';
|
|
26
|
+
else if (gclid)
|
|
27
|
+
source = 'google';
|
|
28
|
+
else if (referrer.includes('facebook'))
|
|
29
|
+
source = 'facebook';
|
|
30
|
+
else if (referrer.includes('google'))
|
|
31
|
+
source = 'google';
|
|
32
|
+
else if (referrer !== 'direct')
|
|
33
|
+
source = referrer;
|
|
34
|
+
return {
|
|
35
|
+
utm_source: utmSource || 'none',
|
|
36
|
+
utm_medium: utmMedium || 'none',
|
|
37
|
+
utm_campaign: utmCampaign || 'none',
|
|
38
|
+
fbclid: fbclid || 'none',
|
|
39
|
+
cxd: cxd || 'none',
|
|
40
|
+
gclid: gclid || 'none',
|
|
41
|
+
referrer,
|
|
42
|
+
source,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { Capacitor } from '@capacitor/core';
|
|
3
|
+
import mixpanel from 'mixpanel-browser';
|
|
4
|
+
import { useEffect, useRef } from 'react';
|
|
5
|
+
import { useAccountQuery } from '../../client/hooks/useAccountQuery.js';
|
|
6
|
+
import { useDepositsCountQuery } from '../../client/hooks/useDepositsCountQuery.js';
|
|
7
|
+
import { useSessionQuery } from '../../client/hooks/useSessionQuery.js';
|
|
8
|
+
import { getSourceData, getUTMParams } from './get-utm.js';
|
|
9
|
+
export const MixpanelTracking = ({ mixpanelId }) => {
|
|
10
|
+
const initializedRef = useRef(false);
|
|
11
|
+
const session = useSessionQuery();
|
|
12
|
+
const btag = session.data?.btag;
|
|
13
|
+
const isAuthenticated = session.data?.status === 'authenticated';
|
|
14
|
+
const accountQuery = useAccountQuery();
|
|
15
|
+
const account = accountQuery.data;
|
|
16
|
+
const kycStatus = account?.verificationStatus;
|
|
17
|
+
const depositCountQuery = useDepositsCountQuery();
|
|
18
|
+
const depositTotalCount = depositCountQuery.data;
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (initializedRef.current)
|
|
21
|
+
return;
|
|
22
|
+
initializedRef.current = true;
|
|
23
|
+
console.log('MIXPANEL ID:', mixpanelId);
|
|
24
|
+
mixpanel.init(mixpanelId, {
|
|
25
|
+
autocapture: false,
|
|
26
|
+
autotrack: false,
|
|
27
|
+
record_sessions_percent: 0,
|
|
28
|
+
persistence: 'localStorage',
|
|
29
|
+
});
|
|
30
|
+
const distinctId = mixpanel.get_distinct_id();
|
|
31
|
+
mixpanel.identify(distinctId);
|
|
32
|
+
const { source, utm_source, utm_medium, utm_campaign, referrer } = getSourceData();
|
|
33
|
+
mixpanel.people.set({
|
|
34
|
+
platform: Capacitor.getPlatform() === 'android'
|
|
35
|
+
? 'Android'
|
|
36
|
+
: Capacitor.getPlatform() === 'ios'
|
|
37
|
+
? 'iOS'
|
|
38
|
+
: 'Web',
|
|
39
|
+
first_seen: new Date().toISOString(),
|
|
40
|
+
source,
|
|
41
|
+
utm_source,
|
|
42
|
+
utm_medium,
|
|
43
|
+
utm_campaign,
|
|
44
|
+
referrer,
|
|
45
|
+
isLoggedIn: isAuthenticated,
|
|
46
|
+
lastLoggedIn: isAuthenticated ? new Date().toISOString() : null,
|
|
47
|
+
});
|
|
48
|
+
if (typeof window !== 'undefined') {
|
|
49
|
+
const SESSION_KEY = 'last_mixpanel_session_tracked';
|
|
50
|
+
const ONE_DAY = 24 * 60 * 60 * 1000;
|
|
51
|
+
const last = window.localStorage.getItem(SESSION_KEY);
|
|
52
|
+
const now = Date.now();
|
|
53
|
+
const oneDayPassed = last && now - new Date(last).getTime() >= ONE_DAY;
|
|
54
|
+
if (!last || oneDayPassed) {
|
|
55
|
+
const isWeb = !Capacitor.getPlatform().includes('android') &&
|
|
56
|
+
!Capacitor.getPlatform().includes('ios');
|
|
57
|
+
const resolvedSource = isWeb
|
|
58
|
+
? window.location.pathname
|
|
59
|
+
: Capacitor.getPlatform().includes('android')
|
|
60
|
+
? 'android'
|
|
61
|
+
: Capacitor.getPlatform().includes('ios')
|
|
62
|
+
? 'ios'
|
|
63
|
+
: 'mobile web';
|
|
64
|
+
mixpanel.track('Session Start', {
|
|
65
|
+
...getUTMParams(),
|
|
66
|
+
source: resolvedSource,
|
|
67
|
+
referrer: (typeof document !== 'undefined' && document.referrer) || 'direct',
|
|
68
|
+
btag: btag || 'organic',
|
|
69
|
+
});
|
|
70
|
+
window.localStorage.setItem(SESSION_KEY, new Date().toISOString());
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}, [isAuthenticated, btag, mixpanelId]);
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
if (!initializedRef.current)
|
|
76
|
+
return;
|
|
77
|
+
if (!isAuthenticated)
|
|
78
|
+
return;
|
|
79
|
+
mixpanel.people.set({
|
|
80
|
+
isLoggedIn: true,
|
|
81
|
+
lastLoggedIn: new Date().toISOString(),
|
|
82
|
+
});
|
|
83
|
+
}, [isAuthenticated]);
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
if (depositTotalCount == null)
|
|
86
|
+
return;
|
|
87
|
+
mixpanel.people.set({
|
|
88
|
+
totalDeposits: depositTotalCount,
|
|
89
|
+
});
|
|
90
|
+
}, [depositTotalCount]);
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
if (!kycStatus)
|
|
93
|
+
return;
|
|
94
|
+
mixpanel.people.set({
|
|
95
|
+
kycStatus,
|
|
96
|
+
});
|
|
97
|
+
}, [kycStatus]);
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (!account)
|
|
100
|
+
return;
|
|
101
|
+
mixpanel.people.set({
|
|
102
|
+
email: account.emailAddress,
|
|
103
|
+
name: account.realName,
|
|
104
|
+
username: account.name,
|
|
105
|
+
});
|
|
106
|
+
}, [account]);
|
|
107
|
+
return null;
|
|
108
|
+
};
|
|
109
|
+
export default MixpanelTracking;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ImageProps } from 'next/image';
|
|
2
|
+
import { type BypassDomainConfig } from '../../client/hooks/useBypassKycChecker';
|
|
2
3
|
import type { GameProvider, GameProviderData, GameType } from '../../types';
|
|
3
4
|
export interface ClassNameEntries {
|
|
4
5
|
root?: string;
|
|
@@ -26,6 +27,6 @@ export interface SearchProps {
|
|
|
26
27
|
viewGamesUrl?: string | ((gameProvider: GameProviderData) => string);
|
|
27
28
|
gameProviderImages?: Partial<Record<GameProvider, ImageProps['src']>>;
|
|
28
29
|
placeholder?: string;
|
|
29
|
-
|
|
30
|
+
bypassDomains?: BypassDomainConfig[];
|
|
30
31
|
}
|
|
31
32
|
export declare function Search(props: SearchProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -7,6 +7,7 @@ import { useEffect, useRef, useState } from 'react';
|
|
|
7
7
|
import { twMerge } from 'tailwind-merge';
|
|
8
8
|
import { useDebounceCallback } from 'usehooks-ts';
|
|
9
9
|
import { useShallow } from 'zustand/shallow';
|
|
10
|
+
import { useBypassKycChecker, } from '../../client/hooks/useBypassKycChecker.js';
|
|
10
11
|
import { useControllableState } from '../../client/hooks/useControllableState.js';
|
|
11
12
|
import { useGamesQuery } from '../../client/hooks/useGamesQuery.js';
|
|
12
13
|
import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
|
|
@@ -29,6 +30,7 @@ function lookup(value, compare) {
|
|
|
29
30
|
.includes(compare.toLowerCase().replace(/\s+/g, ''));
|
|
30
31
|
}
|
|
31
32
|
export function Search(props) {
|
|
33
|
+
const isBypass = useBypassKycChecker(props.bypassDomains);
|
|
32
34
|
const globalStore = useGlobalStore(useShallow((ctx) => ({
|
|
33
35
|
search: ctx.search,
|
|
34
36
|
})));
|
|
@@ -77,7 +79,7 @@ export function Search(props) {
|
|
|
77
79
|
}, children: "Clear" }) })] }) }), _jsx("div", { className: "flex max-h-[85dvh] min-h-0 flex-1 flex-col", children: _jsx("div", { className: "mt-2xl p-xl pb-3xl lg:mt-2 lg:max-h-[41rem] lg:overflow-y-auto lg:rounded-xl lg:border lg:border-border-primary lg:bg-bg-primary", children: search.length <= 0 ? (_jsx(Alert, { message: "Search for your favorite game or provider." })) : search.length === 1 ? (_jsx(Alert, { message: "Search requires at least 2 characters." })) : (_jsxs(_Fragment, { children: [empty && _jsx(Alert, { message: "No results found" }), !empty && (_jsxs(_Fragment, { children: [gameProviders.length > 0 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "font-semibold text-lg", children: "Providers" }), _jsx("div", { className: "mt-3.5 mb-3xl 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: twMerge('flex h-14 w-full items-center rounded-md bg-brand-800', classNames.providerThumbnailRoot), onClick: () => {
|
|
78
80
|
globalStore.search.setOpen(false);
|
|
79
81
|
}, children: _jsx(Image, { src: props.gameProviderImages?.[provider.id] ??
|
|
80
|
-
provider.logo, alt: "", width: 100, height: 50, className: twMerge('mx-auto h-auto w-full', classNames.providerThumbnailImage) }) }, provider.id))) })] })), games.length > 0 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "font-semibold text-lg", 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, { bypassKycCheck:
|
|
82
|
+
provider.logo, alt: "", width: 100, height: 50, className: twMerge('mx-auto h-auto w-full', classNames.providerThumbnailImage) }) }, provider.id))) })] })), games.length > 0 && (_jsxs(_Fragment, { children: [_jsx("h2", { className: "font-semibold text-lg", 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, { bypassKycCheck: isBypass, game: game, className: twMerge('block w-full shadow-sm', classNames.gameThumbnailRoot), onClick: () => {
|
|
81
83
|
globalStore.search.setOpen(false);
|
|
82
84
|
}, children: [_jsx(Image, { src: getGameImageUrl({
|
|
83
85
|
reference: game.reference,
|
package/dist/next.config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opexa/portal-components",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.830",
|
|
4
4
|
"exports": {
|
|
5
5
|
"./ui/*": {
|
|
6
6
|
"types": "./dist/ui/*/index.d.ts",
|
|
@@ -103,6 +103,7 @@
|
|
|
103
103
|
"is-mobile": "^5.0.0",
|
|
104
104
|
"latest": "^0.2.0",
|
|
105
105
|
"lodash-es": "^4.17.21",
|
|
106
|
+
"mixpanel-browser": "^2.71.0",
|
|
106
107
|
"next-recaptcha-v3": "^1.5.2",
|
|
107
108
|
"qrcode": "^1.5.4",
|
|
108
109
|
"tailwind-merge": "^3.3.1",
|