@opexa/portal-components 0.0.997 → 0.0.999

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.
@@ -48,7 +48,7 @@ export function AurixPayPayMayaDeposit() {
48
48
  kycVerificationStatus: ctx.kycVerificationStatus,
49
49
  })));
50
50
  const verificationQuery = useMemberVerificationQuery();
51
- const verificationStatus = verificationQuery.data?.status ?? 'UNVERIFIED';
51
+ const _verificationStatus = verificationQuery.data?.status ?? 'UNVERIFIED';
52
52
  const [status, setStatus] = useState('waiting');
53
53
  const [errorMessage, setErrorMessage] = useState(null);
54
54
  const createDepositMutation = useCreateAurixPayPayMayaDepositMutation({
@@ -1,6 +1,6 @@
1
1
  export declare const AurixPayQRPHDepositContext: (props: {
2
2
  value: {
3
- status: "idle" | "generating-qr-code" | "qr-code-generated" | "failed" | "confirmed";
3
+ status: "confirmed" | "failed" | "idle" | "generating-qr-code" | "qr-code-generated";
4
4
  deposit: import("../../../../types").Deposit | null;
5
5
  errorMessage: {
6
6
  name: string;
@@ -13,7 +13,7 @@ export declare const AurixPayQRPHDepositContext: (props: {
13
13
  } & {
14
14
  children?: import("react").ReactNode | undefined;
15
15
  }) => React.ReactNode, useAurixPayQRPHDepositContext: () => {
16
- status: "idle" | "generating-qr-code" | "qr-code-generated" | "failed" | "confirmed";
16
+ status: "confirmed" | "failed" | "idle" | "generating-qr-code" | "qr-code-generated";
17
17
  deposit: import("../../../../types").Deposit | null;
18
18
  errorMessage: {
19
19
  name: string;
@@ -5,7 +5,7 @@ export interface GenerateQRCodeInput {
5
5
  promo?: string | null;
6
6
  }
7
7
  export declare function useAurixPayQRPHDeposit(): {
8
- status: "idle" | "generating-qr-code" | "qr-code-generated" | "failed" | "confirmed";
8
+ status: "confirmed" | "failed" | "idle" | "generating-qr-code" | "qr-code-generated";
9
9
  deposit: Deposit | null;
10
10
  errorMessage: {
11
11
  name: string;
@@ -10,7 +10,7 @@ import { ObjectType } from '../../../../services/ObjectType.js';
10
10
  import { useDepositWithdrawalPropsContext } from '../../DepositWithdrawalContext.js';
11
11
  export function useAurixPayQRPHDeposit() {
12
12
  const depositWithdrawalProps = useDepositWithdrawalPropsContext();
13
- const globalStore = useGlobalStore(useShallow((ctx) => ({
13
+ const _globalStore = useGlobalStore(useShallow((ctx) => ({
14
14
  kycVerificationStatus: ctx.kycVerificationStatus,
15
15
  })));
16
16
  const inputRef = useRef(null);
@@ -18,7 +18,7 @@ export function useAurixPayQRPHDeposit() {
18
18
  const [status, setStatus] = useState('idle');
19
19
  const [errorMessage, setErrorMessage] = useState(null);
20
20
  const verificationQuery = useMemberVerificationQuery();
21
- const verificationStatus = verificationQuery.data?.status ?? 'UNVERIFIED';
21
+ const _verificationStatus = verificationQuery.data?.status ?? 'UNVERIFIED';
22
22
  const mutation = useCreateAurixPayQrphDepositMutation({
23
23
  onMutate() {
24
24
  setStatus('generating-qr-code');
@@ -44,7 +44,7 @@ export function GCashDeposit() {
44
44
  kycVerificationStatus: ctx.kycVerificationStatus,
45
45
  })));
46
46
  const verificationQuery = useMemberVerificationQuery();
47
- const verificationStatus = verificationQuery.data?.status ?? 'UNVERIFIED';
47
+ const _verificationStatus = verificationQuery.data?.status ?? 'UNVERIFIED';
48
48
  const [status, setStatus] = useState('waiting');
49
49
  const [errorMessage, setErrorMessage] = useState(null);
50
50
  const createDepositMutation = useCreateGCashDepositMutation({
@@ -44,7 +44,7 @@ export function GCashWebpayDeposit() {
44
44
  kycVerificationStatus: ctx.kycVerificationStatus,
45
45
  })));
46
46
  const verificationQuery = useMemberVerificationQuery();
47
- const verificationStatus = verificationQuery.data?.status ?? 'UNVERIFIED';
47
+ const _verificationStatus = verificationQuery.data?.status ?? 'UNVERIFIED';
48
48
  const [status, setStatus] = useState('waiting');
49
49
  const createDepositMutation = useCreateGCashWebpayDepositMutation({
50
50
  onMutate() {
@@ -32,7 +32,7 @@ export function MayaAppDeposit() {
32
32
  kycVerificationStatus: ctx.kycVerificationStatus,
33
33
  })));
34
34
  const verificationQuery = useMemberVerificationQuery();
35
- const verificationStatus = verificationQuery.data?.status ?? 'UNVERIFIED';
35
+ const _verificationStatus = verificationQuery.data?.status ?? 'UNVERIFIED';
36
36
  const [status, setStatus] = useState('waiting');
37
37
  const [errorMessage, setErrorMessage] = useState(null);
38
38
  const createDepositMutation = useCreateMayaAppDepositMutation({
@@ -171,7 +171,7 @@ function AccountVerificationRequired() {
171
171
  globalStore.depositWithdrawal.setOpen(false);
172
172
  }, children: "Verify Now" })] }));
173
173
  }
174
- function AccountVerificationPending() {
174
+ function _AccountVerificationPending() {
175
175
  return (_jsxs("div", { className: "pt-xl", children: [_jsx("div", { className: "mx-auto flex size-12 items-center justify-center rounded-full bg-bg-warning-secondary", children: _jsx(AlertCircleIcon, { className: "size-6 text-text-featured-icon-light-warning" }) }), _jsx("h2", { className: "mt-lg text-center font-semibold text-lg", children: "Verification Pending" }), _jsx("p", { className: "mx-auto mt-xs max-w-[25rem] text-center text-sm text-text-tertiary-600", children: "Your personal verification is currently under review. You will be able to withdraw funds once your account is approved." })] }));
176
176
  }
177
177
  function InsufficientBalance() {
@@ -1,48 +1,119 @@
1
1
  'use client';
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import isMobile from 'is-mobile';
4
4
  import { useRouter } from 'next/navigation';
5
- import { useEffect, useState } from 'react';
5
+ import { useEffect, useRef, useState } from 'react';
6
6
  import { twJoin } from 'tailwind-merge';
7
7
  import { useSessionQuery } from '../../client/hooks/useSessionQuery.js';
8
8
  import { toaster } from '../../client/utils/toaster.js';
9
9
  import { Fallback } from './Fallback.js';
10
10
  export function DigitainContainer(props) {
11
11
  const session = useSessionQuery();
12
- const [isLoading, setLoading] = useState(false);
12
+ const [isLoading, setLoading] = useState(true);
13
+ const [hasBooted, setHasBooted] = useState(false);
13
14
  const router = useRouter();
15
+ const hasBootedRef = useRef(false);
16
+ const containerRef = useRef(null);
14
17
  useEffect(() => {
15
18
  if (session.data?.status === 'authenticated') {
16
19
  router.refresh();
17
20
  }
18
21
  }, [session.data?.status, router]);
19
22
  useEffect(() => {
20
- setLoading(true);
23
+ if (hasBootedRef.current || typeof window === 'undefined') {
24
+ return;
25
+ }
21
26
  let attempts = 0;
22
- const maxAttempts = 5; // e.g. wait up to ~10 seconds
23
- function checkAndBoot() {
24
- if (typeof window !== 'undefined' && window.Bootstrapper) {
27
+ const maxAttempts = 5;
28
+ const intervalId = setInterval(() => {
29
+ if (window.Bootstrapper) {
25
30
  console.log('Bootstrapper found, booting with params:', props.params);
31
+ hasBootedRef.current = true;
26
32
  window.Bootstrapper.boot(props.params, {
27
33
  name: isMobile() ? 'Mobile' : 'AsianView',
28
34
  }).then(() => {
29
35
  console.log('Sportsbook booted!');
36
+ setHasBooted(true);
37
+ }).catch((error) => {
38
+ console.error('Sportsbook boot failed:', error);
39
+ setLoading(false);
40
+ toaster.error({
41
+ title: 'Error',
42
+ description: 'Failed to initialize sportsbook.',
43
+ });
30
44
  });
31
- setTimeout(() => setLoading(false), 1000); // Give some time for the UI to update
32
45
  clearInterval(intervalId);
33
46
  }
34
47
  else if (++attempts >= maxAttempts) {
48
+ console.warn('Bootstrapper did not load in time.');
35
49
  setLoading(false);
36
50
  toaster.error({
37
51
  title: 'Error',
38
52
  description: 'Sportsbook failed to load. Please try again later.',
39
53
  });
40
- console.warn('Bootstrapper did not load in time.');
41
54
  clearInterval(intervalId);
42
55
  }
43
- }
44
- const intervalId = setInterval(checkAndBoot, 500);
56
+ }, 500);
45
57
  return () => clearInterval(intervalId);
46
58
  }, [props.params]);
47
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: twJoin(!isLoading && 'hidden'), children: _jsx(Fallback, { type: "loading", fallbackBackgroundImage: props.fallbackBackgroundImage }) }), _jsx("div", { id: "digitain-container", className: twJoin(isLoading && 'hidden') })] }));
59
+ useEffect(() => {
60
+ if (!hasBooted || !containerRef.current) {
61
+ return;
62
+ }
63
+ const container = containerRef.current;
64
+ const handleIframeReady = (iframe) => {
65
+ const onLoad = () => {
66
+ console.log('Digitain iframe loaded successfully!');
67
+ setTimeout(() => setLoading(false), 300);
68
+ };
69
+ const onError = () => {
70
+ console.error('Digitain iframe failed to load');
71
+ setLoading(false);
72
+ toaster.error({
73
+ title: 'Error',
74
+ description: 'Failed to load sportsbook. Please try again.',
75
+ });
76
+ };
77
+ if (iframe.contentDocument?.readyState === 'complete') {
78
+ console.log('Iframe already loaded!');
79
+ setTimeout(() => setLoading(false), 300);
80
+ }
81
+ else {
82
+ iframe.addEventListener('load', onLoad, { once: true });
83
+ iframe.addEventListener('error', onError, { once: true });
84
+ }
85
+ };
86
+ const existingIframe = container.querySelector('iframe');
87
+ if (existingIframe) {
88
+ handleIframeReady(existingIframe);
89
+ return;
90
+ }
91
+ let iframeDetected = false;
92
+ const observer = new MutationObserver((mutations) => {
93
+ for (const mutation of mutations) {
94
+ for (const node of mutation.addedNodes) {
95
+ if (node.nodeName === 'IFRAME') {
96
+ console.log('Digitain iframe detected');
97
+ iframeDetected = true;
98
+ handleIframeReady(node);
99
+ observer.disconnect();
100
+ return;
101
+ }
102
+ }
103
+ }
104
+ });
105
+ observer.observe(container, { childList: true, subtree: true });
106
+ const fallbackTimeout = setTimeout(() => {
107
+ if (!iframeDetected) {
108
+ console.warn('No iframe detected after 10 seconds. Hiding loader.');
109
+ setLoading(false);
110
+ observer.disconnect();
111
+ }
112
+ }, 10000);
113
+ return () => {
114
+ observer.disconnect();
115
+ clearTimeout(fallbackTimeout);
116
+ };
117
+ }, [hasBooted]);
118
+ return (_jsxs("div", { className: "relative h-full min-h-screen w-full", children: [_jsx("div", { className: twJoin('absolute inset-0 transition-opacity duration-300', isLoading ? 'z-10 opacity-100' : 'pointer-events-none opacity-0'), children: _jsx(Fallback, { type: "loading", fallbackBackgroundImage: props.fallbackBackgroundImage }) }), _jsx("div", { ref: containerRef, id: "digitain-container", className: twJoin('absolute inset-0 transition-opacity duration-300', isLoading ? 'opacity-0' : 'opacity-100') })] }));
48
119
  }
@@ -8,7 +8,7 @@ export function Fallback({ type, signInUrl, fallbackBackgroundImage, }) {
8
8
  const globalStore = useGlobalStore(useShallow((ctx) => ({
9
9
  signIn: ctx.signIn,
10
10
  })));
11
- return (_jsxs("div", { className: "relative h-[459px] w-full lg:h-[829px]", children: [fallbackBackgroundImage && (_jsx(Image, { src: fallbackBackgroundImage, alt: "Background", fill: true, className: "rounded-xl object-cover" })), _jsx("div", { className: "absolute right-0 bottom-safe-area-inset-bottom left-0 h-1/2 rounded-xl bg-gradient-to-b from-[#00000000] to-bg-primary-alt" }), _jsx("div", { className: "absolute right-0 bottom-5 left-0 z-10 m-auto flex max-w-[42.5rem] flex-col items-center justify-center px-4 lg:bottom-15", children: type === 'loading' ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "mb-4 h-10 w-10 animate-spin rounded-full border-4 border-bg-tertiary border-t-button-tertiary-fg" }), _jsx("p", { className: "font-medium text-gray-700 text-lg", children: "Please wait while we load the Sports Book..." })] })) : (_jsx(_Fragment, { children: _jsxs("div", { className: "text-center", children: [_jsxs("div", { className: "mb-8 space-y-3", children: [_jsx("h2", { className: "font-bold text-gray-900 text-xl uppercase lg:text-[40px]", children: "Sports Book Login Required" }), _jsx("p", { className: "text-gray-600 text-xs leading-relaxed lg:text-lg", children: "The Sports Book is our online platform where you can explore real-time betting odds, place bets on a wide range of sports, and track your activity." }), _jsx("p", { className: "text-gray-600 text-xs leading-relaxed lg:text-lg", children: "Access is restricted to authenticated users. Please login to continue and unlock full access to the platform." })] }), _jsx(Button, { className: "mx-auto w-fit", onClick: () => {
11
+ return (_jsxs("div", { className: "relative h-full w-full", children: [fallbackBackgroundImage && (_jsx(Image, { src: fallbackBackgroundImage, alt: "Background", fill: true, className: "rounded-xl object-cover" })), _jsx("div", { className: "absolute right-0 bottom-safe-area-inset-bottom left-0 h-1/2 rounded-xl bg-gradient-to-b from-[#00000000] to-bg-primary-alt" }), _jsx("div", { className: "absolute right-0 bottom-5 left-0 z-10 m-auto flex max-w-[42.5rem] flex-col items-center justify-center px-4 lg:bottom-15", children: type === 'loading' ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "mb-4 h-10 w-10 animate-spin rounded-full border-4 border-bg-tertiary border-t-button-tertiary-fg" }), _jsx("p", { className: "font-medium text-gray-700 text-lg", children: "Please wait while we load the Sports Book..." })] })) : (_jsx(_Fragment, { children: _jsxs("div", { className: "text-center", children: [_jsxs("div", { className: "mb-8 space-y-3", children: [_jsx("h2", { className: "font-bold text-gray-900 text-xl uppercase lg:text-[40px]", children: "Sports Book Login Required" }), _jsx("p", { className: "text-gray-600 text-xs leading-relaxed lg:text-lg", children: "The Sports Book is our online platform where you can explore real-time betting odds, place bets on a wide range of sports, and track your activity." }), _jsx("p", { className: "text-gray-600 text-xs leading-relaxed lg:text-lg", children: "Access is restricted to authenticated users. Please login to continue and unlock full access to the platform." })] }), _jsx(Button, { className: "mx-auto w-fit", onClick: () => {
12
12
  if (signInUrl) {
13
13
  window.location.href = signInUrl;
14
14
  }
@@ -34,6 +34,10 @@ export const getDigitainLaunchToken = async () => {
34
34
  },
35
35
  });
36
36
  const digitainGame = digitainGameQuery.edges[0]?.node;
37
+ if (!digitainGame) {
38
+ console.warn('--SPORTS WARNING-- No Digitain game found in CMS. Please ensure a game with provider "DIGITAIN" is configured.');
39
+ return '';
40
+ }
37
41
  const sessionId = ObjectId.generate(ObjectType.GameSession).toString();
38
42
  try {
39
43
  await createGameSession({
@@ -17,7 +17,7 @@ import { getQueryClient } from '../../utils/getQueryClient.js';
17
17
  import { getSessionQueryKey } from '../../utils/queryKeys.js';
18
18
  import { LOCALSTORAGE_PUSH_NOTIFICATION_TOKEN_KEY } from '../PortalProvider/PushNotifications.js';
19
19
  export function GameLaunchTrigger(props) {
20
- const { game, bypassKycCheck, ...rest } = props;
20
+ const { game, bypassKycCheck: _bypassKycCheck, ...rest } = props;
21
21
  const sessionQuery = useSessionQuery();
22
22
  const createGameSessionMutation = useCreateGameSessionMutation();
23
23
  const globalStore = useGlobalStore(useShallow((ctx) => ({
@@ -52,7 +52,7 @@ export function IdentityVerification() {
52
52
  return prev;
53
53
  return {
54
54
  ...prev,
55
- status: 'UNVERIFIED',
55
+ status: 'CREATED',
56
56
  };
57
57
  });
58
58
  kyc.setStep(2);
@@ -76,7 +76,7 @@ export function IdentityVerification() {
76
76
  return prev;
77
77
  return {
78
78
  ...prev,
79
- status: 'UNVERIFIED',
79
+ status: 'CREATED',
80
80
  };
81
81
  });
82
82
  kyc.setStep(2);
@@ -1,23 +1,14 @@
1
1
  'use client';
2
- import { useIsMutating } from '@tanstack/react-query';
3
2
  import { useEffect } from 'react';
4
3
  import { useAccountQuery } from '../../client/hooks/useAccountQuery.js';
5
4
  import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
6
5
  import { useMemberVerificationQuery } from '../../client/hooks/useMemberVerificationQuery.js';
7
- import { getApproveMemberVerificationQueryKey, getCreateMemberVerificationQueryKey, } from '../../utils/mutationKeys.js';
8
6
  export function KycOpenOnHomeMount(props) {
9
7
  const setkycReminderOpen = useGlobalStore((s) => s.kycReminder.setOpen);
10
8
  const setkycOpen = useGlobalStore((s) => s.kyc.setOpen);
11
9
  const isSignUpOpen = useGlobalStore((s) => s.signUp.open);
12
- const { data: verification, isLoading: verificationLoading, isRefetching: verificationRefetching, } = useMemberVerificationQuery();
10
+ const { data: verification, isLoading: verificationLoading } = useMemberVerificationQuery();
13
11
  const { data: account, isLoading: accountLoading } = useAccountQuery();
14
- const isCreatingVerification = useIsMutating({
15
- mutationKey: getCreateMemberVerificationQueryKey(),
16
- });
17
- const isApprovingVerification = useIsMutating({
18
- mutationKey: getApproveMemberVerificationQueryKey(),
19
- });
20
- const isMutating = isCreatingVerification > 0 || isApprovingVerification > 0;
21
12
  const isVerificationLocked = account?.status === 'VERIFICATION_LOCKED';
22
13
  const isRejected = verification?.status === 'REJECTED';
23
14
  const isUnverified = verification === null ||
@@ -32,63 +23,53 @@ export function KycOpenOnHomeMount(props) {
32
23
  if (props.bypassKycCheck) {
33
24
  return;
34
25
  }
35
- const timeoutId = setTimeout(() => {
36
- if (!verificationLoading &&
37
- !accountLoading &&
38
- !verificationRefetching &&
39
- !isMutating &&
40
- !isSignUpOpen) {
41
- const shouldShowReminder = Boolean(props.isSkippable);
42
- const hasSeenKycModal = sessionStorage.getItem('hasSeenKycModal');
43
- const isFirstVisit = !hasSeenKycModal;
26
+ if (!verificationLoading && !accountLoading && !isSignUpOpen) {
27
+ const shouldShowReminder = Boolean(props.isSkippable);
28
+ const hasSeenKycModal = sessionStorage.getItem('hasSeenKycModal');
29
+ const isFirstVisit = !hasSeenKycModal;
30
+ if (isKycCompleted) {
31
+ setkycReminderOpen(false);
32
+ setkycOpen(false);
44
33
  if (isKycCompleted) {
34
+ sessionStorage.removeItem('hasSeenKycModal');
35
+ }
36
+ return;
37
+ }
38
+ // Handle rejected verification status
39
+ else if (isRejected) {
40
+ if (isFirstVisit) {
45
41
  setkycReminderOpen(false);
46
- setkycOpen(false);
47
- if (isKycCompleted) {
48
- sessionStorage.removeItem('hasSeenKycModal');
49
- }
50
- return;
42
+ setkycOpen(true);
43
+ sessionStorage.setItem('hasSeenKycModal', 'true');
51
44
  }
52
- // 2. Handle member verification locked
53
- if (isVerificationLocked) {
54
- setkycReminderOpen(true);
55
- setkycOpen(false);
56
- return;
45
+ else {
46
+ setkycReminderOpen(shouldShowReminder);
47
+ setkycOpen(!shouldShowReminder);
57
48
  }
58
- // Handle rejected verification status
59
- else if (isRejected) {
60
- if (isFirstVisit) {
61
- setkycReminderOpen(false);
62
- setkycOpen(true);
63
- sessionStorage.setItem('hasSeenKycModal', 'true');
64
- }
65
- else {
66
- setkycReminderOpen(shouldShowReminder);
67
- setkycOpen(!shouldShowReminder);
68
- }
49
+ }
50
+ // Handle unverified verification status
51
+ else if (isUnverified) {
52
+ if (isFirstVisit) {
53
+ setkycReminderOpen(false);
54
+ setkycOpen(true);
55
+ sessionStorage.setItem('hasSeenKycModal', 'true');
69
56
  }
70
- // Handle unverified verification status
71
- else if (isUnverified) {
72
- if (isFirstVisit) {
73
- setkycReminderOpen(false);
74
- setkycOpen(true);
75
- sessionStorage.setItem('hasSeenKycModal', 'true');
76
- }
77
- else {
78
- setkycReminderOpen(shouldShowReminder);
79
- setkycOpen(!shouldShowReminder);
80
- }
57
+ else {
58
+ setkycReminderOpen(shouldShowReminder);
59
+ setkycOpen(!shouldShowReminder);
81
60
  }
82
61
  }
83
- }, 1000);
84
- return () => clearTimeout(timeoutId);
62
+ else if (isVerificationLocked) {
63
+ setkycReminderOpen(true);
64
+ setkycOpen(false);
65
+ return;
66
+ }
67
+ }
85
68
  }, [
86
69
  setkycReminderOpen,
87
70
  setkycOpen,
88
71
  verificationLoading,
89
72
  accountLoading,
90
- verificationRefetching,
91
- isMutating,
92
73
  isSignUpOpen,
93
74
  isVerificationLocked,
94
75
  isRejected,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opexa/portal-components",
3
- "version": "0.0.997",
3
+ "version": "0.0.999",
4
4
  "exports": {
5
5
  "./ui/*": {
6
6
  "types": "./dist/ui/*/index.d.ts",