@opexa/portal-components 0.0.312 → 0.0.314
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/useFileQuery.js +5 -5
- package/dist/client/hooks/useGenerateSumsubVerificationTokenMutation.d.ts +2 -0
- package/dist/client/hooks/useGenerateSumsubVerificationTokenMutation.js +19 -0
- package/dist/client/hooks/useGlobalStore.d.ts +25 -1
- package/dist/client/hooks/useGlobalStore.js +3 -2
- package/dist/components/AccountVerification/AccountVerification.js +33 -21
- package/dist/components/Banner/Banner.d.ts +5 -0
- package/dist/components/Banner/Banner.js +3 -0
- package/dist/components/DigitainLauncher/DigitainLauncher.d.ts +2 -0
- package/dist/components/DigitainLauncher/DigitainLauncher.js +1 -1
- package/dist/components/DigitainLauncher/DigitianContainter.d.ts +2 -0
- package/dist/components/DigitainLauncher/DigitianContainter.js +2 -2
- package/dist/components/DigitainLauncher/Fallback.d.ts +4 -1
- package/dist/components/DigitainLauncher/Fallback.js +11 -11
- package/dist/components/KYC/KYC.d.ts +4 -3
- package/dist/components/KYC/KYC.js +10 -3
- package/dist/components/KYC/KYCDefault/BasicInformation.d.ts +1 -0
- package/dist/components/KYC/KYCDefault/BasicInformation.js +101 -0
- package/dist/components/KYC/KYCDefault/IdentityVerification.d.ts +1 -0
- package/dist/components/KYC/KYCDefault/IdentityVerification.js +120 -0
- package/dist/components/KYC/KYCDefault/Indicator.d.ts +1 -0
- package/dist/components/KYC/KYCDefault/Indicator.js +8 -0
- package/dist/components/KYC/KYCDefault/KYCDefault.d.ts +7 -0
- package/dist/components/KYC/KYCDefault/KYCDefault.js +45 -0
- package/dist/components/KYC/KYCDefault/KYCDefaultContext.d.ts +6 -0
- package/dist/components/KYC/KYCDefault/KYCDefaultContext.js +2 -0
- package/dist/components/KYC/KYCDefault/PersonalInformation.d.ts +1 -0
- package/dist/components/KYC/KYCDefault/PersonalInformation.js +122 -0
- package/dist/components/KYC/KYCDefault/index.d.ts +1 -0
- package/dist/components/KYC/KYCDefault/index.js +1 -0
- package/dist/components/KYC/KYCDefault/useKYCDefault.d.ts +25 -0
- package/dist/components/KYC/KYCDefault/useKYCDefault.js +38 -0
- package/dist/components/KYC/KYCReminder.d.ts +1 -0
- package/dist/components/KYC/KYCReminder.lazy.js +3 -3
- package/dist/components/KYC/KYCSumsub.d.ts +5 -0
- package/dist/components/KYC/KYCSumsub.js +54 -0
- package/dist/components/KYC/index.d.ts +0 -1
- package/dist/components/KYC/index.js +0 -1
- package/dist/next.config.js +1 -0
- package/dist/services/account.d.ts +4 -0
- package/dist/services/account.js +5 -1
- package/dist/services/queries.d.ts +1 -0
- package/dist/services/queries.js +5 -0
- package/dist/ui/Dialog/Dialog.d.ts +88 -88
- package/dist/ui/Dialog/dialog.recipe.d.ts +8 -8
- package/dist/ui/Dialog/dialog.recipe.js +1 -1
- package/dist/utils/mutationKeys.d.ts +1 -0
- package/dist/utils/mutationKeys.js +1 -0
- package/package.json +3 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useQuery } from '@tanstack/react-query';
|
|
2
|
+
import invariant from 'tiny-invariant';
|
|
2
3
|
import { getFile } from '../../services/file.js';
|
|
3
4
|
import { getFileQueryKey } from '../../utils/queryKeys.js';
|
|
4
5
|
import { getSession } from '../services/getSession.js';
|
|
@@ -15,13 +16,12 @@ export const useFileQuery = (id, config) => {
|
|
|
15
16
|
queryKey: getFileQueryKey(id),
|
|
16
17
|
queryFn: async ({ signal }) => {
|
|
17
18
|
const session = await getSession();
|
|
19
|
+
invariant(session.status === 'authenticated');
|
|
18
20
|
const file = await getFile(id, {
|
|
19
21
|
signal,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
},
|
|
24
|
-
}),
|
|
22
|
+
headers: {
|
|
23
|
+
Authorization: `Bearer ${session.token}`,
|
|
24
|
+
},
|
|
25
25
|
});
|
|
26
26
|
return file ?? null;
|
|
27
27
|
},
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useMutation } from '@tanstack/react-query';
|
|
2
|
+
import invariant from 'tiny-invariant';
|
|
3
|
+
import { generateSumsubVerificationToken } from '../../services/account.js';
|
|
4
|
+
import { getGenerateSumsubVerificationTokenMutationKey } from '../../utils/mutationKeys.js';
|
|
5
|
+
import { getSession } from '../services/getSession.js';
|
|
6
|
+
export const useGenerateSumsubVerificationTokenMutation = () => {
|
|
7
|
+
return useMutation({
|
|
8
|
+
mutationKey: getGenerateSumsubVerificationTokenMutationKey(),
|
|
9
|
+
mutationFn: async () => {
|
|
10
|
+
const session = await getSession();
|
|
11
|
+
invariant(session.status === 'authenticated');
|
|
12
|
+
return generateSumsubVerificationToken({
|
|
13
|
+
headers: {
|
|
14
|
+
Authorization: `Bearer ${session.token}`,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
};
|
|
@@ -82,5 +82,29 @@ export interface GlobalStore {
|
|
|
82
82
|
responsibleGaming: ResponsibleGamingStore;
|
|
83
83
|
pendingBonus: HasPendingBonusStore;
|
|
84
84
|
}
|
|
85
|
-
export declare const useGlobalStore: import("zustand").UseBoundStore<import("zustand").StoreApi<GlobalStore
|
|
85
|
+
export declare const useGlobalStore: import("zustand").UseBoundStore<Omit<Omit<import("zustand").StoreApi<GlobalStore>, "setState" | "devtools"> & {
|
|
86
|
+
setState(partial: GlobalStore | Partial<GlobalStore> | ((state: GlobalStore) => GlobalStore | Partial<GlobalStore>), replace?: false | undefined, action?: (string | {
|
|
87
|
+
[x: string]: unknown;
|
|
88
|
+
[x: number]: unknown;
|
|
89
|
+
[x: symbol]: unknown;
|
|
90
|
+
type: string;
|
|
91
|
+
}) | undefined): void;
|
|
92
|
+
setState(state: GlobalStore | ((state: GlobalStore) => GlobalStore), replace: true, action?: (string | {
|
|
93
|
+
[x: string]: unknown;
|
|
94
|
+
[x: number]: unknown;
|
|
95
|
+
[x: symbol]: unknown;
|
|
96
|
+
type: string;
|
|
97
|
+
}) | undefined): void;
|
|
98
|
+
devtools: {
|
|
99
|
+
cleanup: () => void;
|
|
100
|
+
};
|
|
101
|
+
}, "subscribe"> & {
|
|
102
|
+
subscribe: {
|
|
103
|
+
(listener: (selectedState: GlobalStore, previousSelectedState: GlobalStore) => void): () => void;
|
|
104
|
+
<U>(selector: (state: GlobalStore) => U, listener: (selectedState: U, previousSelectedState: U) => void, options?: {
|
|
105
|
+
equalityFn?: ((a: U, b: U) => boolean) | undefined;
|
|
106
|
+
fireImmediately?: boolean;
|
|
107
|
+
} | undefined): () => void;
|
|
108
|
+
};
|
|
109
|
+
}>;
|
|
86
110
|
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { create } from 'zustand';
|
|
2
|
-
|
|
2
|
+
import { devtools, subscribeWithSelector } from 'zustand/middleware';
|
|
3
|
+
export const useGlobalStore = create()(devtools(subscribeWithSelector((set) => ({
|
|
3
4
|
signIn: {
|
|
4
5
|
open: false,
|
|
5
6
|
setOpen(open) {
|
|
@@ -392,4 +393,4 @@ export const useGlobalStore = create((set) => ({
|
|
|
392
393
|
})),
|
|
393
394
|
'~touched': false,
|
|
394
395
|
},
|
|
395
|
-
}));
|
|
396
|
+
}))));
|
|
@@ -13,39 +13,51 @@ import { FaceIdIcon } from '../../icons/FaceIdIcon.js';
|
|
|
13
13
|
import { FileCheck02Icon } from '../../icons/FileCheck02Icon.js';
|
|
14
14
|
import { FileSearch02Icon } from '../../icons/FileSearch02Icon.js';
|
|
15
15
|
import { FileX02Icon } from '../../icons/FileX02Icon.js';
|
|
16
|
-
import { Spinner02Icon } from '../../icons/Spinner02Icon.js';
|
|
17
16
|
import { Button } from '../../ui/Button/index.js';
|
|
18
17
|
export function AccountVerification(props) {
|
|
19
18
|
const globalStore = useGlobalStore(useShallow((ctx) => ({
|
|
20
19
|
kyc: ctx.kyc,
|
|
21
20
|
})));
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
21
|
+
const memberVerificationQuery = useMemberVerificationQuery();
|
|
22
|
+
const completed = memberVerificationQuery.data?.status === 'VERIFIED' ||
|
|
23
|
+
memberVerificationQuery.data?.status === 'PENDING' ||
|
|
24
|
+
memberVerificationQuery.data?.status === 'APPROVED';
|
|
25
|
+
return (_jsxs("div", { className: props.className, children: [_jsx(Header, {}), _jsxs("div", { className: "mt-5 rounded-xl border border-border-secondary bg-bg-primary-alt shadow-xs", children: [_jsx(Requirements, {}), !completed && (_jsx("div", { className: "flex justify-end border-border-secondary border-t px-4 py-3 lg:py-xl", children: _jsx(Button, { size: "sm", className: "w-full lg:w-fit", onClick: () => globalStore.kyc.setOpen(true), children: "Verify Now" }) }))] }), _jsx(Status, {})] }));
|
|
26
|
+
}
|
|
27
|
+
function Header() {
|
|
28
|
+
const query = useProfileCompletionQuery();
|
|
29
|
+
return (_jsxs("div", { className: "flex items-start gap-8", children: [_jsxs("div", { className: "grow", children: [_jsx("h2", { className: "font-semibold text-sm text-text-secondary-700", children: "Verify your identity" }), _jsx("p", { className: "text-sm text-text-tertiary-600", children: "Complete personal verification to unlock all features and enhance account security." })] }), _jsx(ark.svg, { asChild: true, className: twMerge('size-6', query.data?.accountVerification
|
|
30
|
+
? 'text-text-success-primary'
|
|
31
|
+
: 'text-text-warning-primary'), children: query.data?.accountVerification ? (_jsx(CheckVerified02Icon, {})) : (_jsx(AlertCircleIcon, {})) })] }));
|
|
32
|
+
}
|
|
33
|
+
function Requirements() {
|
|
34
|
+
return (_jsx("div", { className: "px-4 py-5", children: _jsxs("ul", { className: "space-y-lg", children: [_jsxs("li", { className: "flex icon:size-6 items-center gap-lg icon:text-text-nav-item-button-icon text-text-secondary-700", children: [_jsx(FileCheck02Icon, {}), "Basic Information"] }), _jsxs("li", { className: "flex icon:size-6 items-center gap-lg icon:text-text-nav-item-button-icon text-text-secondary-700", children: [_jsx(CreditCard02Icon, {}), "Government ID"] }), _jsxs("li", { className: "flex icon:size-6 items-center gap-lg icon:text-text-nav-item-button-icon text-text-secondary-700", children: [_jsx(FaceIdIcon, {}), "Facial Verification"] })] }) }));
|
|
35
|
+
}
|
|
36
|
+
function Status() {
|
|
37
|
+
const query = useMemberVerificationQuery();
|
|
38
|
+
if (query.isLoading)
|
|
39
|
+
return null;
|
|
40
|
+
switch (query.data?.status) {
|
|
41
|
+
case 'PENDING':
|
|
42
|
+
return _jsx(Status__Pending, {});
|
|
43
|
+
case 'REJECTED':
|
|
44
|
+
return _jsx(Status__Failed, {});
|
|
45
|
+
case 'VERIFIED':
|
|
46
|
+
case 'APPROVED':
|
|
47
|
+
return _jsx(Status__Success, {});
|
|
48
|
+
default:
|
|
49
|
+
return _jsx(Status__Missing, {});
|
|
35
50
|
}
|
|
36
|
-
return (_jsxs("div", { className: props.className, children: [_jsxs("div", { className: "flex items-start gap-8", children: [_jsxs("div", { className: "grow", children: [_jsx("h2", { className: "font-semibold text-sm text-text-secondary-700", children: "Verify your identity" }), _jsx("p", { className: "text-sm text-text-tertiary-600", children: "Complete personal verification to unlock all features and enhance account security." })] }), _jsx(ark.svg, { asChild: true, className: twMerge('size-6', profileCompletion?.accountVerification
|
|
37
|
-
? 'text-text-success-primary'
|
|
38
|
-
: 'text-text-warning-primary'), children: profileCompletion?.accountVerification ? (_jsx(CheckVerified02Icon, {})) : (_jsx(AlertCircleIcon, {})) })] }), _jsxs("div", { className: "mt-5 rounded-xl border border-border-secondary bg-bg-primary-alt shadow-xs", children: [_jsx("div", { className: "px-4 py-5", children: _jsxs("ul", { className: "space-y-lg", children: [_jsxs("li", { className: "flex icon:size-6 items-center gap-lg icon:text-text-nav-item-button-icon text-text-secondary-700", children: [_jsx(FileCheck02Icon, {}), "Basic Information"] }), _jsxs("li", { className: "flex icon:size-6 items-center gap-lg icon:text-text-nav-item-button-icon text-text-secondary-700", children: [_jsx(CreditCard02Icon, {}), "Government ID"] }), _jsxs("li", { className: "flex icon:size-6 items-center gap-lg icon:text-text-nav-item-button-icon text-text-secondary-700", children: [_jsx(FaceIdIcon, {}), "Facial Verification"] })] }) }), !isKycCompleted && (_jsx("div", { className: "flex justify-end border-border-secondary border-t px-4 py-3 lg:py-xl", children: _jsx(Button, { size: "sm", className: "w-full lg:w-fit", onClick: () => globalStore.kyc.setOpen(true), children: "Verify Now" }) }))] }), success && _jsx(VerificationSuccess, {}), pending && _jsx(VerificationInProgress, {}), failed && _jsx(VerificationFailed, {}), empty && _jsx(VerificationNotSubmitted, {})] }));
|
|
39
51
|
}
|
|
40
|
-
function
|
|
52
|
+
function Status__Missing() {
|
|
41
53
|
return (_jsxs("div", { className: "mt-6 flex flex-col gap-2 rounded-xl border border-border-primary bg-bg-primary-alt p-xl shadow-xs lg:flex-row", children: [_jsx("div", { className: "flex size-[2.1875rem] items-center justify-center rounded-full border-2 border-text-warning-primary/10", children: _jsx("div", { className: "flex size-[1.666625rem] items-center justify-center rounded-full border-2 border-text-warning-primary/30", children: _jsx(AlertCircleIcon, { className: "size-5 text-text-warning-primary" }) }) }), _jsx("p", { className: "max-w-[800px] text-sm text-text-tertiary-600", children: "To serve you better and unlock all features, please provide valid identification documents. This helps protect your account and makes recovery easier if ever needed." })] }));
|
|
42
54
|
}
|
|
43
|
-
function
|
|
55
|
+
function Status__Pending() {
|
|
44
56
|
return (_jsxs("div", { className: "mt-6 flex flex-col gap-2 rounded-xl border border-border-primary bg-bg-primary-alt p-xl shadow-xs lg:flex-row", children: [_jsx("div", { className: "flex size-[2.1875rem] items-center justify-center rounded-full border-2 border-text-warning-primary/10", children: _jsx("div", { className: "flex size-[1.666625rem] items-center justify-center rounded-full border-2 border-text-warning-primary/30", children: _jsx(FileSearch02Icon, { className: "size-5 text-text-warning-primary" }) }) }), _jsxs("div", { children: [_jsx("h2", { className: "font-semibold text-sm text-text-secondary-700", children: "Under review" }), _jsx("p", { className: "mt-xs text-sm text-text-tertiary-600", children: "To serve you better and unlock all features, please provide valid identification documents. This helps protect your account and makes recovery easier if ever needed." })] })] }));
|
|
45
57
|
}
|
|
46
|
-
function
|
|
58
|
+
function Status__Success() {
|
|
47
59
|
return (_jsxs("div", { className: "mt-6 flex flex-col gap-2 rounded-xl border border-border-primary bg-bg-primary-alt p-xl shadow-xs lg:flex-row", children: [_jsx("div", { className: "flex size-[2.1875rem] items-center justify-center rounded-full border-2 border-text-success-primary/10", children: _jsx("div", { className: "flex size-[1.666625rem] items-center justify-center rounded-full border-2 border-text-success-primary/30", children: _jsx(FileCheck02Icon, { className: "size-5 text-text-success-primary" }) }) }), _jsxs("div", { children: [_jsx("h2", { className: "font-semibold text-sm text-text-secondary-700", children: "Verification successful" }), _jsx("p", { className: "mt-xs text-sm text-text-tertiary-600", children: "Your account has been successfully verified. You now have full access to all features and improved account security." })] })] }));
|
|
48
60
|
}
|
|
49
|
-
function
|
|
61
|
+
function Status__Failed() {
|
|
50
62
|
return (_jsxs("div", { className: "mt-6 flex flex-col gap-2 rounded-xl border border-border-primary bg-bg-primary-alt p-xl shadow-xs lg:flex-row", children: [_jsx("div", { className: "flex size-[2.1875rem] items-center justify-center rounded-full border-2 border-text-error-primary/10", children: _jsx("div", { className: "flex size-[1.666625rem] items-center justify-center rounded-full border-2 border-text-error-primary/30", children: _jsx(FileX02Icon, { className: "size-5 text-text-error-primary" }) }) }), _jsxs("div", { children: [_jsx("h2", { className: "font-semibold text-sm text-text-secondary-700", children: "Verification failed" }), _jsx("p", { className: "mt-xs text-sm text-text-tertiary-600", children: "There was an issue with the verification process. Please try again or contact support for assistance." })] })] }));
|
|
51
63
|
}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import type { ImageProps } from 'next/image';
|
|
2
|
+
/** @deprecated */
|
|
2
3
|
export interface BannerEntry {
|
|
3
4
|
src: ImageProps['src'];
|
|
4
5
|
redirectUrl?: string;
|
|
5
6
|
}
|
|
7
|
+
/** @deprecated */
|
|
6
8
|
export interface BannerProps {
|
|
7
9
|
banners: BannerEntry[];
|
|
8
10
|
imageWidth?: number | [mobile: number, desktop: number];
|
|
9
11
|
imageHeight?: number | [mobile: number, desktop: number];
|
|
10
12
|
className?: string;
|
|
11
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated Please use Carousel and getImageProps for better performance
|
|
16
|
+
*/
|
|
12
17
|
export declare function Banner(props: BannerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -8,6 +8,9 @@ import Link from 'next/link';
|
|
|
8
8
|
import { Fragment, useEffect, useState } from 'react';
|
|
9
9
|
import { twMerge } from 'tailwind-merge';
|
|
10
10
|
import { dataAttr } from '../../utils/dataAttr.js';
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Please use Carousel and getImageProps for better performance
|
|
13
|
+
*/
|
|
11
14
|
export function Banner(props) {
|
|
12
15
|
const [emblaRef, emblaApi] = useEmblaCarousel({
|
|
13
16
|
loop: true,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { ImageProps } from 'next/image';
|
|
1
2
|
export interface DigitainLauncherParams {
|
|
2
3
|
hostname: string;
|
|
3
4
|
signInUrl?: string | null;
|
|
5
|
+
fallbackBackgroundImage?: ImageProps['src'];
|
|
4
6
|
}
|
|
5
7
|
export declare function DigitainLauncher(props: DigitainLauncherParams): Promise<import("react/jsx-runtime").JSX.Element>;
|
|
@@ -11,5 +11,5 @@ export async function DigitainLauncher(props) {
|
|
|
11
11
|
if (session.status === 'authenticated') {
|
|
12
12
|
params.token = await getDigitainLaunchToken();
|
|
13
13
|
}
|
|
14
|
-
return (_jsxs(_Fragment, { children: [_jsx(Script, { src: `//${props.hostname}/js/partner/bootstrapper.min.js` }), _jsx(Protected, { fallback: _jsx(Fallback, { signInUrl: props.signInUrl }), children: _jsx(DigitainContainer, { params: params }) })] }));
|
|
14
|
+
return (_jsxs(_Fragment, { children: [_jsx(Script, { src: `//${props.hostname}/js/partner/bootstrapper.min.js` }), _jsx(Protected, { fallback: _jsx(Fallback, { type: "fallback", signInUrl: props.signInUrl, fallbackBackgroundImage: props.fallbackBackgroundImage }), children: _jsx(DigitainContainer, { params: params, fallbackBackgroundImage: props.fallbackBackgroundImage }) })] }));
|
|
15
15
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { ImageProps } from 'next/image';
|
|
1
2
|
import type { DigitainBootstrapperParams } from './types';
|
|
2
3
|
export interface DigitainContainerProps {
|
|
3
4
|
params: DigitainBootstrapperParams;
|
|
5
|
+
fallbackBackgroundImage?: ImageProps['src'] | null;
|
|
4
6
|
}
|
|
5
7
|
export declare function DigitainContainer(props: DigitainContainerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -6,7 +6,7 @@ import { useEffect, 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
|
-
import {
|
|
9
|
+
import { Fallback } from './Fallback.js';
|
|
10
10
|
export function DigitainContainer(props) {
|
|
11
11
|
const session = useSessionQuery();
|
|
12
12
|
const [isLoading, setLoading] = useState(false);
|
|
@@ -43,5 +43,5 @@ export function DigitainContainer(props) {
|
|
|
43
43
|
const intervalId = setInterval(checkAndBoot, 500);
|
|
44
44
|
return () => clearInterval(intervalId);
|
|
45
45
|
}, [props.params]);
|
|
46
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { className: twJoin(!isLoading && 'hidden'), children: _jsx(
|
|
46
|
+
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') })] }));
|
|
47
47
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ImageProps } from 'next/image';
|
|
2
|
+
export declare function Fallback({ type, signInUrl, fallbackBackgroundImage, }: {
|
|
3
|
+
type: 'fallback' | 'loading';
|
|
2
4
|
signInUrl?: string | null;
|
|
5
|
+
fallbackBackgroundImage?: ImageProps['src'] | null;
|
|
3
6
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import Image from 'next/image';
|
|
3
4
|
import { useShallow } from 'zustand/shallow';
|
|
4
5
|
import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
|
|
5
|
-
import { User01Icon } from '../../icons/User01Icon.js';
|
|
6
6
|
import { Button } from '../../ui/Button/index.js';
|
|
7
|
-
export function Fallback({ signInUrl }) {
|
|
7
|
+
export function Fallback({ type, signInUrl, fallbackBackgroundImage, }) {
|
|
8
8
|
const globalStore = useGlobalStore(useShallow((ctx) => ({
|
|
9
9
|
signIn: ctx.signIn,
|
|
10
10
|
})));
|
|
11
|
-
return (
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
return (_jsxs("div", { className: "relative h-[829px] w-full", children: [fallbackBackgroundImage && (_jsx(Image, { src: fallbackBackgroundImage, alt: "Background", fill: true, className: "rounded-xl object-cover" })), _jsx("div", { className: "absolute right-0 bottom-0 left-0 h-1/2 rounded-xl bg-gradient-to-b from-[#00000000] to-bg-primary-alt" }), _jsx("div", { className: "absolute right-0 bottom-[60px] left-0 z-10 m-auto flex max-w-[42.5rem] flex-col items-center justify-center px-4", 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-[40px] text-gray-900 uppercase", children: "Sports Book Login Required" }), _jsx("p", { className: "text-gray-600 text-lg leading-relaxed", 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-lg leading-relaxed", 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
|
+
if (signInUrl) {
|
|
13
|
+
window.location.href = signInUrl;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
globalStore.signIn.setOpen(true);
|
|
17
|
+
}
|
|
18
|
+
}, children: "Login" })] }) })) })] }));
|
|
19
19
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
export type
|
|
1
|
+
import type { KYCDefaultProps } from './KYCDefault';
|
|
2
|
+
import type { KYCSumsubProps } from './KYCSumsub';
|
|
3
|
+
export type KYCProps = KYCDefaultProps | KYCSumsubProps;
|
|
4
|
+
export declare function KYC(props: KYCProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -3,12 +3,19 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import dynamic from 'next/dynamic';
|
|
4
4
|
import { useShallow } from 'zustand/shallow';
|
|
5
5
|
import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
|
|
6
|
-
const
|
|
6
|
+
const KYCDefault = dynamic(() => import('./KYCDefault/index.js').then((m) => m.KYCDefault), {
|
|
7
|
+
ssr: false,
|
|
8
|
+
loading: () => null,
|
|
9
|
+
});
|
|
10
|
+
const KYCSumsub = dynamic(() => import('./KYCSumsub.js').then((m) => m.KYCSumsub), {
|
|
7
11
|
ssr: false,
|
|
8
12
|
loading: () => null,
|
|
9
13
|
});
|
|
10
14
|
export function KYC(props) {
|
|
11
15
|
const touched = useGlobalStore(useShallow((ctx) => ctx.kyc['~touched']));
|
|
12
|
-
if (touched)
|
|
13
|
-
return
|
|
16
|
+
if (!touched)
|
|
17
|
+
return null;
|
|
18
|
+
if (props.provider === 'sumsub')
|
|
19
|
+
return _jsx(KYCSumsub, { ...props });
|
|
20
|
+
return _jsx(KYCDefault, { ...props });
|
|
14
21
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function BasicInformation(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
3
|
+
import { differenceInYears, format, isSameDay, isValid, parse } from 'date-fns';
|
|
4
|
+
import { isNil, omitBy, size } from 'lodash-es';
|
|
5
|
+
import { useEffect } from 'react';
|
|
6
|
+
import { useForm } from 'react-hook-form';
|
|
7
|
+
import invariant from 'tiny-invariant';
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { useAccountQuery } from '../../../client/hooks/useAccountQuery.js';
|
|
10
|
+
import { useUpdateAccountMutation } from '../../../client/hooks/useUpdateAccountMutation.js';
|
|
11
|
+
import { toaster } from '../../../client/utils/toaster.js';
|
|
12
|
+
import { Button } from '../../../ui/Button/index.js';
|
|
13
|
+
import { Dialog } from '../../../ui/Dialog/index.js';
|
|
14
|
+
import { Field } from '../../../ui/Field/index.js';
|
|
15
|
+
import { useKYCDefaultContext } from './KYCDefaultContext.js';
|
|
16
|
+
const definition = z.object({
|
|
17
|
+
realName: z
|
|
18
|
+
.string()
|
|
19
|
+
.min(3, 'Name must be 3 or more characters')
|
|
20
|
+
.max(50, 'Name must not be more than 50 characters')
|
|
21
|
+
.regex(/^[a-z0-9 ]+$/gi, 'Name must not contain special characters')
|
|
22
|
+
.trim(),
|
|
23
|
+
birthDay: z
|
|
24
|
+
.string()
|
|
25
|
+
.min(1, 'Date of birth is required')
|
|
26
|
+
.superRefine((value, ctx) => {
|
|
27
|
+
const dob = parse(value, 'yyyy-MM-dd', new Date());
|
|
28
|
+
if (!isValid(dob)) {
|
|
29
|
+
return ctx.addIssue({
|
|
30
|
+
code: z.ZodIssueCode.invalid_date,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
const now = new Date();
|
|
34
|
+
const age = differenceInYears(now, dob);
|
|
35
|
+
if (age < 21) {
|
|
36
|
+
return ctx.addIssue({
|
|
37
|
+
code: z.ZodIssueCode.custom,
|
|
38
|
+
message: 'You must be at least 21 years old',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}),
|
|
42
|
+
branchCode: z.string().min(4).max(10).optional().or(z.literal('')),
|
|
43
|
+
});
|
|
44
|
+
export function BasicInformation() {
|
|
45
|
+
const kyc = useKYCDefaultContext();
|
|
46
|
+
const form = useForm({
|
|
47
|
+
resolver: zodResolver(definition),
|
|
48
|
+
mode: 'all',
|
|
49
|
+
defaultValues: {
|
|
50
|
+
birthDay: '',
|
|
51
|
+
branchCode: '',
|
|
52
|
+
realName: '',
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
const accountQuery = useAccountQuery();
|
|
56
|
+
const account = accountQuery.data;
|
|
57
|
+
const stepCompleted = account != null && account.realName != null && account.birthDay != null;
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (stepCompleted)
|
|
60
|
+
kyc.setStep(2);
|
|
61
|
+
}, [stepCompleted, kyc]);
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (account) {
|
|
64
|
+
form.reset({
|
|
65
|
+
realName: account.realName ?? '',
|
|
66
|
+
birthDay: account.birthDay
|
|
67
|
+
? format(account.birthDay, 'yyyy-MM-dd')
|
|
68
|
+
: '',
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}, [account, form]);
|
|
72
|
+
const updateAccountMutation = useUpdateAccountMutation({
|
|
73
|
+
onError(error) {
|
|
74
|
+
toaster.error({
|
|
75
|
+
title: 'Error',
|
|
76
|
+
description: error.message,
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
onSuccess() {
|
|
80
|
+
kyc.setStep(2);
|
|
81
|
+
toaster.success({
|
|
82
|
+
title: 'Success',
|
|
83
|
+
description: 'Basic information has been set successfully.',
|
|
84
|
+
});
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
return (_jsxs("div", { children: [_jsx(Dialog.Title, { className: "text-center font-semibold text-lg", children: "Basic Information" }), _jsx(Dialog.Description, { className: "mt-xs text-center text-sm text-text-secondary-700", children: "Enter your basic details for identification and communication." }), _jsxs("form", { className: "mt-3", onSubmit: form.handleSubmit((data) => {
|
|
88
|
+
invariant(account);
|
|
89
|
+
const input = omitBy({
|
|
90
|
+
realName: account.realName === data.realName ? undefined : data.realName,
|
|
91
|
+
birthDay: account.birthDay && isSameDay(data.birthDay, account.birthDay)
|
|
92
|
+
? undefined
|
|
93
|
+
: format(data.birthDay, 'yyyy-MM-dd'),
|
|
94
|
+
}, isNil);
|
|
95
|
+
if (size(input) === 0)
|
|
96
|
+
return kyc.setStep(2);
|
|
97
|
+
updateAccountMutation.mutate(input);
|
|
98
|
+
}), children: [_jsxs(Field.Root, { invalid: !!form.formState.errors.realName, readOnly: !!accountQuery.data?.realName, children: [_jsx(Field.Label, { children: "Real Name" }), _jsx(Field.Input, { placeholder: "Enter your real name", ...form.register('realName') }), _jsx(Field.ErrorText, { children: form.formState.errors.realName?.message })] }), _jsxs(Field.Root, { className: "mt-3", invalid: !!form.formState.errors.branchCode, readOnly: !!accountQuery.data?.birthDay, children: [_jsx(Field.Label, { children: "Date of Birth" }), _jsx(Field.Input, { type: "date", ...form.register('birthDay') }), _jsx(Field.ErrorText, { children: form.formState.errors.birthDay?.message })] }), _jsx(Button, { type: "submit", className: "mt-8", disabled: accountQuery.isLoading ||
|
|
99
|
+
updateAccountMutation.isPending ||
|
|
100
|
+
stepCompleted, children: "Continue" })] })] }));
|
|
101
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function IdentityVerification(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
4
|
+
import { useEffect } from 'react';
|
|
5
|
+
import { Controller, useForm } from 'react-hook-form';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { useShallow } from 'zustand/shallow';
|
|
8
|
+
import { useCreateMemberVerificationMutation } from '../../../client/hooks/useCreateMemberVerificationMutation.js';
|
|
9
|
+
import { useGlobalStore } from '../../../client/hooks/useGlobalStore.js';
|
|
10
|
+
import { useMemberVerificationQuery } from '../../../client/hooks/useMemberVerificationQuery.js';
|
|
11
|
+
import { useUpdateMemberVerificationMutation } from '../../../client/hooks/useUpdateMemberVerificationMutation.js';
|
|
12
|
+
import { toaster } from '../../../client/utils/toaster.js';
|
|
13
|
+
import { Button } from '../../../ui/Button/index.js';
|
|
14
|
+
import { Dialog } from '../../../ui/Dialog/index.js';
|
|
15
|
+
import { Field } from '../../../ui/Field/index.js';
|
|
16
|
+
import { getQueryClient } from '../../../utils/getQueryClient.js';
|
|
17
|
+
import { getMemberVerificationQueryKey } from '../../../utils/queryKeys.js';
|
|
18
|
+
import { IdFrontImageField } from '../../shared/IdFrontImageField/index.js';
|
|
19
|
+
import { SelfieImageField } from '../../shared/SelfieImageField/index.js';
|
|
20
|
+
import { useKYCDefaultContext } from './KYCDefaultContext.js';
|
|
21
|
+
const formSchema = z.object({
|
|
22
|
+
selfieImage: z.string().min(1, 'Selfie image is required.'),
|
|
23
|
+
idFrontImage: z.string().min(1, 'Front image of ID is required.'),
|
|
24
|
+
});
|
|
25
|
+
export function IdentityVerification() {
|
|
26
|
+
const kyc = useKYCDefaultContext();
|
|
27
|
+
const { mutate: createMemberVerification, isPending: createPending } = useCreateMemberVerificationMutation({
|
|
28
|
+
onSuccess: () => {
|
|
29
|
+
toaster.success({
|
|
30
|
+
title: 'ID Front Image & Selfie Image uploaded successfully',
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
onError: (error) => {
|
|
34
|
+
toaster.error({
|
|
35
|
+
title: 'Failed to upload ID Front Image & Selfie Image',
|
|
36
|
+
description: error.message,
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
const { mutate: updateMemberVerification, isPending: updatePending } = useUpdateMemberVerificationMutation({
|
|
41
|
+
onSuccess: () => {
|
|
42
|
+
const queryClient = getQueryClient();
|
|
43
|
+
toaster.success({
|
|
44
|
+
title: 'ID Front Image & Selfie Image updated successfully',
|
|
45
|
+
});
|
|
46
|
+
queryClient.setQueryData(getMemberVerificationQueryKey(), (prev) => {
|
|
47
|
+
if (!prev)
|
|
48
|
+
return prev;
|
|
49
|
+
return {
|
|
50
|
+
...prev,
|
|
51
|
+
status: 'CREATED',
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
onError: (error) => {
|
|
56
|
+
toaster.error({
|
|
57
|
+
title: 'Failed to upload ID Front Image & Selfie Image',
|
|
58
|
+
description: error.message,
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
const memberVerification = useMemberVerificationQuery();
|
|
63
|
+
const memberId = memberVerification.data?.id;
|
|
64
|
+
const globalStore = useGlobalStore(useShallow((ctx) => ({
|
|
65
|
+
kyc: ctx.kyc,
|
|
66
|
+
})));
|
|
67
|
+
const form = useForm({
|
|
68
|
+
resolver: zodResolver(formSchema),
|
|
69
|
+
defaultValues: {
|
|
70
|
+
idFrontImage: '',
|
|
71
|
+
selfieImage: '',
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
function onSubmit(values) {
|
|
75
|
+
if (!memberId) {
|
|
76
|
+
createMemberVerification({
|
|
77
|
+
selfieImage: values.selfieImage,
|
|
78
|
+
idFrontImage: values.idFrontImage,
|
|
79
|
+
address: '',
|
|
80
|
+
nationality: '',
|
|
81
|
+
natureOfWork: '',
|
|
82
|
+
permanentAddress: '',
|
|
83
|
+
placeOfBirth: '',
|
|
84
|
+
sourceOfIncome: '',
|
|
85
|
+
});
|
|
86
|
+
kyc.setStep(3);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
updateMemberVerification({
|
|
90
|
+
id: memberId,
|
|
91
|
+
data: {
|
|
92
|
+
selfieImage: values.selfieImage,
|
|
93
|
+
idFrontImage: values.idFrontImage,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
kyc.setStep(3);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
if (kyc.selfieImageId)
|
|
101
|
+
form.setValue('selfieImage', kyc.selfieImageId);
|
|
102
|
+
if (kyc.idFrontImageId)
|
|
103
|
+
form.setValue('idFrontImage', kyc.idFrontImageId);
|
|
104
|
+
}, [form, kyc.idFrontImageId, kyc.selfieImageId]);
|
|
105
|
+
return (_jsxs("div", { children: [_jsx(Dialog.Title, { className: "text-center font-semibold text-lg", children: "Verify your identity" }), _jsx(Dialog.Description, { className: "mt-xs text-center text-sm text-text-secondary-700", children: "Verify your details to confirm your identity and secure your access." }), _jsxs("div", { className: "mt-7 rounded-xl border border-border-primary bg-bg-primary p-lg text-text-placeholder text-xs leading-tight", children: [_jsx("h3", { className: "font-semibold", children: "Instructions" }), _jsxs("ol", { className: "mt-2 list-inside list-decimal", children: [_jsx("li", { children: "Upload a full photo of your ID." }), _jsx("li", { children: "Please ensure that all details in the uploaded image are legible." }), _jsx("li", { children: "Please ensure that the ID uploaded is within the validity period." })] })] }), _jsxs("form", { className: "mt-xl", onSubmit: form.handleSubmit(onSubmit), children: [_jsx(Controller, { control: form.control, name: "idFrontImage", render: (o) => (_jsxs(Field.Root, { invalid: o.fieldState.invalid, children: [_jsx(Field.Label, { children: "Front of your ID" }), _jsx(IdFrontImageField, { value: o.field.value, onChange: o.field.onChange, onError: (error) => {
|
|
106
|
+
form.setValue('idFrontImage', '');
|
|
107
|
+
form.setError('idFrontImage', {
|
|
108
|
+
type: 'validate',
|
|
109
|
+
message: error.message,
|
|
110
|
+
});
|
|
111
|
+
} }), _jsx(Field.ErrorText, { children: o.fieldState.error?.message })] })) }), _jsx(Controller, { control: form.control, name: "selfieImage", render: (o) => (_jsxs(Field.Root, { invalid: o.fieldState.invalid, className: "mt-3", children: [_jsx(Field.Label, { children: "Selfie holding your ID" }), _jsx(SelfieImageField, { value: o.field.value, onChange: o.field.onChange, onError: (error) => {
|
|
112
|
+
form.setValue('selfieImage', '');
|
|
113
|
+
form.setError('selfieImage', {
|
|
114
|
+
type: 'validate',
|
|
115
|
+
message: error.message,
|
|
116
|
+
});
|
|
117
|
+
} }), _jsx(Field.ErrorText, { children: o.fieldState.error?.message })] })) }), _jsx(Button, { type: "submit", className: "mt-6", disabled: createPending || updatePending, children: "Continue" }), _jsx(Button, { variant: "outline", colorScheme: "gray", className: "mt-lg", type: "button", onClick: () => {
|
|
118
|
+
globalStore.kyc.setOpen(false);
|
|
119
|
+
}, children: "Skip for now" })] })] }));
|
|
120
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function Indicator(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { noop } from 'lodash-es';
|
|
3
|
+
import { Progress } from '../../../ui/Progress/index.js';
|
|
4
|
+
import { useKYCDefaultContext } from './KYCDefaultContext.js';
|
|
5
|
+
export function Indicator() {
|
|
6
|
+
const kyc = useKYCDefaultContext();
|
|
7
|
+
return (_jsxs("div", { className: "flex items-center justify-center gap-1.5 py-3", children: [_jsx(Progress.Root, { className: "w-10 shrink-0", value: kyc.step > 1 ? 100 : 0, onValueChange: noop, children: _jsx(Progress.Track, { className: "bg-bg-primary-hover", children: _jsx(Progress.Range, {}) }) }), _jsx(Progress.Root, { className: "w-10 shrink-0", value: kyc.step > 2 ? 100 : 0, onValueChange: noop, children: _jsx(Progress.Track, { className: "bg-bg-primary-hover", children: _jsx(Progress.Range, {}) }) }), _jsx(Progress.Root, { className: "w-10 shrink-0", value: kyc.step === 3 ? 100 : 0, onValueChange: noop, children: _jsx(Progress.Track, { className: "bg-bg-primary-hover", children: _jsx(Progress.Range, {}) }) })] }));
|
|
8
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ImageProps } from 'next/image';
|
|
2
|
+
import { type KYCReminderProps } from '../KYCReminder';
|
|
3
|
+
export interface KYCDefaultProps extends KYCReminderProps {
|
|
4
|
+
provider?: 'opexa';
|
|
5
|
+
logo: ImageProps['src'];
|
|
6
|
+
}
|
|
7
|
+
export declare function KYCDefault(props: KYCDefaultProps): import("react/jsx-runtime").JSX.Element;
|