@opexa/portal-components 0.0.154 → 0.0.158
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/useBonusesQuery.d.ts +2 -1
- package/dist/client/hooks/useBonusesQuery.js +3 -3
- package/dist/client/hooks/useMarkMessageAsReadMutation.js +5 -1
- package/dist/client/hooks/useMessagesQuery.js +1 -0
- package/dist/client/hooks/useUnreadMessagesCountQuery.js +1 -0
- package/dist/components/AccountVerification/AccountVerification.js +1 -5
- package/dist/components/Bonuses/Bonuses.client.js +29 -17
- package/dist/components/Bonuses/Bonuses.js +2 -1
- package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/OnlineBankDepositContext.d.ts +2 -2
- package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/useOnlineBankDeposit.d.ts +1 -1
- 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/KYC/AutoOpen.d.ts +1 -0
- package/dist/components/KYC/AutoOpen.js +25 -0
- package/dist/components/KYC/BasicInformation.js +6 -4
- package/dist/components/KYC/CaptureSelfie.js +1 -2
- package/dist/components/KYC/FileUpload.js +29 -3
- package/dist/components/KYC/KYC.js +2 -1
- package/dist/components/KYC/KYC.lazy.js +3 -26
- package/dist/components/KYC/useKYC.d.ts +1 -0
- package/dist/components/KYC/useKYC.js +8 -0
- package/dist/components/KYC/utils.d.ts +1 -0
- package/dist/components/KYC/utils.js +9 -0
- package/dist/components/Messages/Messages.lazy.js +2 -2
- package/dist/components/Messages/MessagesPopup.js +19 -14
- package/dist/components/News/News.js +1 -1
- package/dist/components/PortalProvider/PortalProvider.js +2 -1
- package/dist/components/PortalProvider/WebVitals.d.ts +1 -0
- package/dist/components/PortalProvider/WebVitals.js +8 -0
- package/dist/components/Search/Search.lazy.js +2 -2
- package/dist/components/SignUp/SignUpForm.js +0 -4
- package/dist/constants/EnvVar.d.ts +1 -0
- package/dist/constants/EnvVar.js +5 -0
- package/dist/handlers.js +1 -4
- package/dist/server/utils/prefetchBonusesQuery.d.ts +2 -1
- package/dist/server/utils/prefetchBonusesQuery.js +3 -3
- package/dist/services/graphqlRequest.js +3 -1
- package/dist/services/httpRequest.js +3 -1
- package/dist/services/queries.d.ts +1 -1
- package/dist/services/queries.js +2 -2
- package/dist/services/wallet.d.ts +11 -2
- package/dist/services/wallet.js +2 -2
- package/dist/ui/Carousel/Carousel.d.ts +72 -72
- package/dist/ui/Carousel/carousel.recipe.d.ts +8 -8
- package/dist/ui/Tooltip/Tooltip.d.ts +48 -48
- package/dist/ui/Tooltip/tooltip.recipe.d.ts +8 -8
- package/dist/utils/queryKeys.d.ts +2 -2
- package/dist/utils/queryKeys.js +1 -1
- package/package.json +1 -1
- package/dist/components/KYC/backup/Header.d.ts +0 -1
- package/dist/components/KYC/backup/Header.js +0 -8
- package/dist/components/KYC/backup/Indicator.d.ts +0 -1
- package/dist/components/KYC/backup/Indicator.js +0 -9
- package/dist/components/KYC/backup/KYC.d.ts +0 -1
- package/dist/components/KYC/backup/KYC.js +0 -14
- package/dist/components/KYC/backup/KYC.lazy.d.ts +0 -1
- package/dist/components/KYC/backup/KYC.lazy.js +0 -26
- package/dist/components/KYC/backup/KYCContext.d.ts +0 -6
- package/dist/components/KYC/backup/KYCContext.js +0 -2
- package/dist/components/KYC/backup/Step1.d.ts +0 -1
- package/dist/components/KYC/backup/Step1.js +0 -13
- package/dist/components/KYC/backup/Step2.d.ts +0 -1
- package/dist/components/KYC/backup/Step2.js +0 -13
- package/dist/components/KYC/backup/Step3.d.ts +0 -1
- package/dist/components/KYC/backup/Step3.js +0 -13
- package/dist/components/KYC/backup/Step4.d.ts +0 -1
- package/dist/components/KYC/backup/Step4.js +0 -7
- package/dist/components/KYC/backup/useKYC.d.ts +0 -10
- package/dist/components/KYC/backup/useKYC.js +0 -8
- package/dist/components/KYC/loadModels.d.ts +0 -1
- package/dist/components/KYC/loadModels.js +0 -9
- package/dist/components/Messages/Message.d.ts +0 -1
- package/dist/components/Messages/Message.js +0 -37
- package/dist/components/Messages/MessageContext.d.ts +0 -6
- package/dist/components/Messages/MessageContext.js +0 -2
- package/dist/components/Messages/MessagePopup.d.ts +0 -1
- package/dist/components/Messages/MessagePopup.js +0 -24
- package/dist/components/Messages/MessageTrigger.d.ts +0 -8
- package/dist/components/Messages/MessageTrigger.js +0 -19
- package/dist/constants/BranchCode.d.ts +0 -4
- package/dist/constants/BranchCode.js +0 -42
- package/dist/icons/BellRingIcon.d.ts +0 -2
- package/dist/icons/BellRingIcon.js +0 -4
|
@@ -5,7 +5,7 @@ import { getQueryClient } from '../../utils/getQueryClient.js';
|
|
|
5
5
|
import { getBonusesCountQueryKey, getBonusesQueryKey, } from '../../utils/queryKeys.js';
|
|
6
6
|
import { getSession } from '../services/getSession.js';
|
|
7
7
|
import { useSessionQuery } from './useSessionQuery.js';
|
|
8
|
-
export const useBonusesQuery = (config) => {
|
|
8
|
+
export const useBonusesQuery = (input, config) => {
|
|
9
9
|
const queryClient = getQueryClient();
|
|
10
10
|
const sessionQuery = useSessionQuery();
|
|
11
11
|
const query = useQuery({
|
|
@@ -14,11 +14,11 @@ export const useBonusesQuery = (config) => {
|
|
|
14
14
|
enabled: config?.enabled === false
|
|
15
15
|
? false
|
|
16
16
|
: sessionQuery.data?.status === 'authenticated',
|
|
17
|
-
queryKey: getBonusesQueryKey(),
|
|
17
|
+
queryKey: getBonusesQueryKey(input),
|
|
18
18
|
queryFn: async ({ signal }) => {
|
|
19
19
|
const session = await getSession();
|
|
20
20
|
invariant(session.status === 'authenticated');
|
|
21
|
-
const bonuses = await getBonuses({
|
|
21
|
+
const bonuses = await getBonuses(input, {
|
|
22
22
|
signal,
|
|
23
23
|
headers: {
|
|
24
24
|
Authorization: `Bearer ${session.token}`,
|
|
@@ -44,7 +44,11 @@ export const useMarkMessageAsReadMutation = (config) => {
|
|
|
44
44
|
})),
|
|
45
45
|
};
|
|
46
46
|
});
|
|
47
|
-
queryClient.
|
|
47
|
+
queryClient.setQueriesData({
|
|
48
|
+
queryKey: getUnreadMessagesCountQueryKey(),
|
|
49
|
+
exact: false,
|
|
50
|
+
type: 'all',
|
|
51
|
+
}, (prev) => {
|
|
48
52
|
return prev && prev > 0 ? prev - 1 : 0;
|
|
49
53
|
});
|
|
50
54
|
return id;
|
|
@@ -7,6 +7,7 @@ import { useSessionQuery } from './useSessionQuery.js';
|
|
|
7
7
|
export const useMessagesQuery = (input, config) => {
|
|
8
8
|
const sessionQuery = useSessionQuery();
|
|
9
9
|
const query = useInfiniteQuery({
|
|
10
|
+
staleTime: 1000 * 2,
|
|
10
11
|
...config,
|
|
11
12
|
enabled: config?.enabled === false
|
|
12
13
|
? false
|
|
@@ -7,6 +7,7 @@ import { useSessionQuery } from './useSessionQuery.js';
|
|
|
7
7
|
export const useUnreadMessagesCountQuery = (input, config) => {
|
|
8
8
|
const sessionQuery = useSessionQuery();
|
|
9
9
|
const query = useQuery({
|
|
10
|
+
staleTime: 1000 * 2,
|
|
10
11
|
...config,
|
|
11
12
|
enabled: config?.enabled === false
|
|
12
13
|
? false
|
|
@@ -6,7 +6,6 @@ import { useShallow } from 'zustand/shallow';
|
|
|
6
6
|
import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
|
|
7
7
|
import { useMemberVerificationQuery } from '../../client/hooks/useMemberVerificationQuery.js';
|
|
8
8
|
import { useProfileCompletionQuery } from '../../client/hooks/useProfileCompletionQuery.js';
|
|
9
|
-
import { useSessionQuery } from '../../client/hooks/useSessionQuery.js';
|
|
10
9
|
import { AlertCircleIcon } from '../../icons/AlertCircleIcon.js';
|
|
11
10
|
import { CheckVerified02Icon } from '../../icons/CheckVerified02Icon.js';
|
|
12
11
|
import { CreditCard02Icon } from '../../icons/CreditCard02Icon.js';
|
|
@@ -20,8 +19,6 @@ export function AccountVerification(props) {
|
|
|
20
19
|
const globalStore = useGlobalStore(useShallow((ctx) => ({
|
|
21
20
|
kyc: ctx.kyc,
|
|
22
21
|
})));
|
|
23
|
-
const sessionQuery = useSessionQuery();
|
|
24
|
-
const session = sessionQuery.data;
|
|
25
22
|
const profileCompletionQuery = useProfileCompletionQuery();
|
|
26
23
|
const profileCompletion = profileCompletionQuery.data;
|
|
27
24
|
const verificationQuery = useMemberVerificationQuery();
|
|
@@ -33,8 +30,7 @@ export function AccountVerification(props) {
|
|
|
33
30
|
verification?.status === 'UNVERIFIED';
|
|
34
31
|
return (_jsxs("div", { className: props.className, children: [_jsxs("div", { className: "flex items-start gap-8", children: [_jsxs("div", { className: "grow", children: [_jsx("h2", { className: "text-text-secondary-700 text-sm font-semibold", children: "Verify your identity" }), _jsx("p", { className: "text-text-tertiary-600 text-sm", children: "Complete personal verification to unlock all features and enhance account security." })] }), _jsx(ark.svg, { asChild: true, className: twMerge('size-6', profileCompletion?.accountVerification
|
|
35
32
|
? 'text-text-success-primary'
|
|
36
|
-
: 'text-text-warning-primary'), children: profileCompletion?.accountVerification ? (_jsx(CheckVerified02Icon, {})) : (_jsx(AlertCircleIcon, {})) })] }), _jsxs("div", { className: "shadow-xs border-border-secondary bg-bg-primary-alt mt-5 rounded-xl border", children: [_jsx("div", { className: "px-4 py-5", children: _jsxs("ul", { className: "space-y-lg", children: [_jsxs("li", { className: "text-text-secondary-700 icon:size-6 icon:text-text-nav-item-button-icon flex items-center gap-lg", children: [_jsx(FileCheck02Icon, {}), "Basic Information"] }), _jsxs("li", { className: "text-text-secondary-700 icon:size-6 icon:text-text-nav-item-button-icon flex items-center gap-lg", children: [_jsx(Globe05Icon, {}), "Proof of address"] }), _jsxs("li", { className: "text-text-secondary-700 icon:size-6 icon:text-text-nav-item-button-icon flex items-center gap-lg", children: [_jsx(CreditCard02Icon, {}), "Government ID"] }), _jsxs("li", { className: "text-text-secondary-700 icon:size-6 icon:text-text-nav-item-button-icon flex items-center gap-lg", children: [_jsx(FaceIdIcon, {}), "Facial Verification"] })] }) }), _jsx("div", { className: "border-border-secondary flex justify-end border-t px-4 py-3 lg:py-xl", children: (
|
|
37
|
-
session?.status === 'authenticated') && (_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, {})] }));
|
|
33
|
+
: 'text-text-warning-primary'), children: profileCompletion?.accountVerification ? (_jsx(CheckVerified02Icon, {})) : (_jsx(AlertCircleIcon, {})) })] }), _jsxs("div", { className: "shadow-xs border-border-secondary bg-bg-primary-alt mt-5 rounded-xl border", children: [_jsx("div", { className: "px-4 py-5", children: _jsxs("ul", { className: "space-y-lg", children: [_jsxs("li", { className: "text-text-secondary-700 icon:size-6 icon:text-text-nav-item-button-icon flex items-center gap-lg", children: [_jsx(FileCheck02Icon, {}), "Basic Information"] }), _jsxs("li", { className: "text-text-secondary-700 icon:size-6 icon:text-text-nav-item-button-icon flex items-center gap-lg", children: [_jsx(Globe05Icon, {}), "Proof of address"] }), _jsxs("li", { className: "text-text-secondary-700 icon:size-6 icon:text-text-nav-item-button-icon flex items-center gap-lg", children: [_jsx(CreditCard02Icon, {}), "Government ID"] }), _jsxs("li", { className: "text-text-secondary-700 icon:size-6 icon:text-text-nav-item-button-icon flex items-center gap-lg", children: [_jsx(FaceIdIcon, {}), "Facial Verification"] })] }) }), _jsx("div", { className: "border-border-secondary flex justify-end border-t px-4 py-3 lg:py-xl", children: (!verification || verification?.status === 'REJECTED') && (_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, {})] }));
|
|
38
34
|
}
|
|
39
35
|
function VerificationNotSubmitted() {
|
|
40
36
|
return (_jsxs("div", { className: "shadow-xs border-border-primary bg-bg-primary-alt mt-6 flex flex-col gap-2 rounded-xl border p-xl lg:flex-row", children: [_jsx("div", { className: "border-text-warning-primary/10 flex size-[2.1875rem] items-center justify-center rounded-full border-2", children: _jsx("div", { className: "border-text-warning-primary/30 flex size-[1.666625rem] items-center justify-center rounded-full border-2", children: _jsx(AlertCircleIcon, { className: "text-text-warning-primary size-5" }) }) }), _jsx("p", { className: "text-text-tertiary-600 max-w-[800px] text-sm", 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." })] }));
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { isAfter } from 'date-fns';
|
|
4
3
|
import { clamp } from 'lodash-es';
|
|
5
4
|
import Image from 'next/image';
|
|
6
5
|
import Link from 'next/link';
|
|
7
|
-
import {
|
|
6
|
+
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
|
8
7
|
import { z } from 'zod';
|
|
9
8
|
import { useShallow } from 'zustand/shallow';
|
|
10
9
|
import { useBonusesQuery } from '../../client/hooks/useBonusesQuery.js';
|
|
@@ -23,32 +22,45 @@ import { Button } from '../../ui/Button/index.js';
|
|
|
23
22
|
import { Popover } from '../../ui/Popover/index.js';
|
|
24
23
|
import { Progress } from '../../ui/Progress/index.js';
|
|
25
24
|
import { SegmentGroup } from '../../ui/SegmentGroup/index.js';
|
|
26
|
-
import { capitalize } from '../../utils/capitalize.js';
|
|
27
25
|
import { formatNumber } from '../../utils/formatNumber.js';
|
|
28
26
|
import { parseDecimal } from '../../utils/parseDecimal.js';
|
|
29
27
|
import { ClaimSpotBonus } from './ClaimSpotBonus.js';
|
|
30
|
-
const
|
|
28
|
+
const TabSchema = z
|
|
29
|
+
.enum(['all', 'active', 'cashbacks'])
|
|
30
|
+
.optional()
|
|
31
|
+
.nullable()
|
|
32
|
+
.catch('all')
|
|
33
|
+
.transform((v) => v ?? 'all');
|
|
31
34
|
export function Bonuses__client(props) {
|
|
32
|
-
const
|
|
35
|
+
const router = useRouter();
|
|
36
|
+
const pathname = usePathname();
|
|
37
|
+
const searchParams = useSearchParams();
|
|
38
|
+
const tab = TabSchema.parse(searchParams.get('tab'));
|
|
39
|
+
const setTab = (tab) => {
|
|
40
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
41
|
+
params.set('tab', tab);
|
|
42
|
+
router.push(`${pathname}?${params.toString()}`);
|
|
43
|
+
};
|
|
33
44
|
const bonusesQuery = useBonusesQuery({
|
|
45
|
+
...(tab === 'active' && {
|
|
46
|
+
filter: {
|
|
47
|
+
expiration: {
|
|
48
|
+
greaterThanOrEqual: new Date(),
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
}),
|
|
52
|
+
}, {
|
|
34
53
|
refetchInterval: 5000,
|
|
54
|
+
enabled: tab !== 'cashbacks',
|
|
35
55
|
});
|
|
36
56
|
const cashbackBonusesQuery = useCashbackBonusesQuery({
|
|
37
57
|
refetchInterval: 5000,
|
|
38
58
|
});
|
|
39
|
-
const bonuses =
|
|
40
|
-
|
|
41
|
-
: (bonusesQuery.data ?? []).filter((bonus) => {
|
|
42
|
-
return tab === 'ACTIVE' ? (new Date(), bonus.expiration) : true;
|
|
43
|
-
});
|
|
44
|
-
const cashbackBonuses = (cashbackBonusesQuery.data ?? []).filter((bonus) => {
|
|
45
|
-
return tab === 'ACTIVE'
|
|
46
|
-
? isAfter(new Date(), bonus.cashback.activationEndDateTime)
|
|
47
|
-
: true;
|
|
48
|
-
});
|
|
59
|
+
const bonuses = bonusesQuery.data ?? [];
|
|
60
|
+
const cashbackBonuses = cashbackBonusesQuery.data ?? [];
|
|
49
61
|
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: props.className, children: [_jsx("h2", { className: "text-lg font-semibold", children: props.heading ?? 'Rewards' }), _jsxs(SegmentGroup.Root, { value: tab, onValueChange: (details) => {
|
|
50
|
-
setTab(
|
|
51
|
-
}, className: "mt-3", children: [
|
|
62
|
+
setTab(TabSchema.parse(details.value));
|
|
63
|
+
}, className: "mt-3", children: [_jsxs(SegmentGroup.Item, { value: "all", children: [_jsx(SegmentGroup.ItemText, { children: "All" }), _jsx(SegmentGroup.ItemControl, {}), _jsx(SegmentGroup.ItemHiddenInput, {})] }), _jsxs(SegmentGroup.Item, { value: "active", children: [_jsx(SegmentGroup.ItemText, { children: "Active" }), _jsx(SegmentGroup.ItemControl, {}), _jsx(SegmentGroup.ItemHiddenInput, {})] }), _jsxs(SegmentGroup.Item, { value: "cashbacks", children: [_jsx(SegmentGroup.ItemText, { children: "Cashbacks" }), _jsx(SegmentGroup.ItemControl, {}), _jsx(SegmentGroup.ItemHiddenInput, {})] }), _jsx(SegmentGroup.Indicator, {})] }), _jsxs("div", { className: "mt-3xl grid gap-3xl lg:mt-lg lg:grid-cols-3", children: [tab === 'all' && _jsx(SpotBonus, {}), bonuses.map((bonus) => (_jsx(Bonus, { data: bonus, viewDetailsUrl: props.viewBonusDetailsUrl ?? '/rewards' }, bonus.id))), cashbackBonuses.map((cashbackBonus) => (_jsx(CashbackBonus, { data: cashbackBonus }, cashbackBonus.id)))] })] }), _jsx(ClaimSpotBonus, {})] }));
|
|
52
64
|
}
|
|
53
65
|
function Bonus(props) {
|
|
54
66
|
const bonus = props.data;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Suspense } from 'react';
|
|
2
3
|
import { prefetchBonusesQuery } from '../../server/utils/prefetchBonusesQuery.js';
|
|
3
4
|
import { prefetchCashbacksQuery } from '../../server/utils/prefetchCashbacksQuery.js';
|
|
4
5
|
import { Bonuses__client } from './Bonuses.client.js';
|
|
5
6
|
export async function Bonuses(props) {
|
|
6
7
|
await Promise.allSettled([prefetchBonusesQuery(), prefetchCashbacksQuery()]);
|
|
7
|
-
return _jsx(Bonuses__client, { ...props });
|
|
8
|
+
return (_jsx(Suspense, { fallback: null, children: _jsx(Bonuses__client, { ...props }) }));
|
|
8
9
|
}
|
package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/OnlineBankDepositContext.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const OnlineBankDepositContext: (props: {
|
|
2
2
|
value: {
|
|
3
|
-
view: "
|
|
3
|
+
view: "vca" | "form";
|
|
4
4
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
5
5
|
verify: () => void;
|
|
6
6
|
reset: () => void;
|
|
@@ -13,7 +13,7 @@ export declare const OnlineBankDepositContext: (props: {
|
|
|
13
13
|
} & {
|
|
14
14
|
children?: import("react").ReactNode | undefined;
|
|
15
15
|
}) => React.ReactNode, useOnlineBankDepositContext: () => {
|
|
16
|
-
view: "
|
|
16
|
+
view: "vca" | "form";
|
|
17
17
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
18
18
|
verify: () => void;
|
|
19
19
|
reset: () => void;
|
package/dist/components/DepositWithdrawal/Deposit/OnlineBankDeposit/useOnlineBankDeposit.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Deposit } from '../../../../types';
|
|
2
2
|
export type UseOnlineBankDepositReturn = ReturnType<typeof useOnlineBankDeposit>;
|
|
3
3
|
export declare function useOnlineBankDeposit(): {
|
|
4
|
-
view: "
|
|
4
|
+
view: "vca" | "form";
|
|
5
5
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
6
6
|
verify: () => void;
|
|
7
7
|
reset: () => void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const QRPHDepositContext: (props: {
|
|
2
2
|
value: {
|
|
3
|
-
view: "
|
|
3
|
+
view: "qrCode" | "form";
|
|
4
4
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
5
5
|
verify: () => void;
|
|
6
6
|
reset: () => void;
|
|
@@ -13,7 +13,7 @@ export declare const QRPHDepositContext: (props: {
|
|
|
13
13
|
} & {
|
|
14
14
|
children?: import("react").ReactNode | undefined;
|
|
15
15
|
}) => React.ReactNode, useQRPHDepositContext: () => {
|
|
16
|
-
view: "
|
|
16
|
+
view: "qrCode" | "form";
|
|
17
17
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
18
18
|
verify: () => void;
|
|
19
19
|
reset: () => void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Deposit } from '../../../../types';
|
|
2
2
|
export type UseQRPHDepositReturn = ReturnType<typeof useQRPHDeposit>;
|
|
3
3
|
export declare function useQRPHDeposit(): {
|
|
4
|
-
view: "
|
|
4
|
+
view: "qrCode" | "form";
|
|
5
5
|
status: "waiting" | "processing" | "failed" | "verification-waiting" | "verification-processing" | "verification-failed" | "verification-success";
|
|
6
6
|
verify: () => void;
|
|
7
7
|
reset: () => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function AutoOpen(): null;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useShallow } from 'zustand/shallow';
|
|
3
|
+
import { useAccountQuery } from '../../client/hooks/useAccountQuery.js';
|
|
4
|
+
import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
|
|
5
|
+
import { useMemberVerificationQuery } from '../../client/hooks/useMemberVerificationQuery.js';
|
|
6
|
+
import { useSessionQuery } from '../../client/hooks/useSessionQuery.js';
|
|
7
|
+
export function AutoOpen() {
|
|
8
|
+
const kycStore = useGlobalStore(useShallow((ctx) => ctx.kyc));
|
|
9
|
+
const { data: session } = useSessionQuery();
|
|
10
|
+
const { data: account } = useAccountQuery();
|
|
11
|
+
const { data: verification } = useMemberVerificationQuery();
|
|
12
|
+
const shouldOpen = !account?.realName ||
|
|
13
|
+
!account?.birthDay ||
|
|
14
|
+
!verification ||
|
|
15
|
+
verification.status === 'REJECTED';
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (session?.status == 'authenticated' &&
|
|
18
|
+
!kycStore['~touched'] &&
|
|
19
|
+
shouldOpen) {
|
|
20
|
+
kycStore.setOpen(true);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
}, [kycStore, session?.status, shouldOpen]);
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
@@ -5,11 +5,11 @@ import { isNil, omitBy, size } from 'lodash-es';
|
|
|
5
5
|
import { useEffect } from 'react';
|
|
6
6
|
import { useForm } from 'react-hook-form';
|
|
7
7
|
import invariant from 'tiny-invariant';
|
|
8
|
+
import { useInterval } from 'usehooks-ts';
|
|
8
9
|
import { z } from 'zod';
|
|
9
10
|
import { useAccountQuery } from '../../client/hooks/useAccountQuery.js';
|
|
10
11
|
import { useUpdateAccountMutation } from '../../client/hooks/useUpdateAccountMutation.js';
|
|
11
12
|
import { toaster } from '../../client/utils/toaster.js';
|
|
12
|
-
import { SpinnerIcon } from '../../icons/SpinnerIcon.js';
|
|
13
13
|
import { Button } from '../../ui/Button/index.js';
|
|
14
14
|
import { Dialog } from '../../ui/Dialog/index.js';
|
|
15
15
|
import { Field } from '../../ui/Field/index.js';
|
|
@@ -55,6 +55,8 @@ export function BasicInformation() {
|
|
|
55
55
|
});
|
|
56
56
|
const accountQuery = useAccountQuery();
|
|
57
57
|
const account = accountQuery.data;
|
|
58
|
+
const completed = account != null && account.realName != null && account.birthDay != null;
|
|
59
|
+
useInterval(() => kyc.setStep(2), completed ? 1000 : null);
|
|
58
60
|
const updateAccountMutation = useUpdateAccountMutation({
|
|
59
61
|
onError(error) {
|
|
60
62
|
toaster.error({
|
|
@@ -80,8 +82,6 @@ export function BasicInformation() {
|
|
|
80
82
|
});
|
|
81
83
|
}
|
|
82
84
|
}, [account, form, kyc]);
|
|
83
|
-
if (accountQuery.isLoading)
|
|
84
|
-
return _jsx(SpinnerIcon, {});
|
|
85
85
|
return (_jsxs("div", { children: [_jsx(Dialog.Title, { className: "text-center text-lg font-semibold", children: "Basic Information" }), _jsx(Dialog.Description, { className: "text-text-secondary-700 mt-xs text-center text-sm", children: "Enter your basic details for identification and communication." }), _jsxs("form", { className: "mt-3", onSubmit: form.handleSubmit((data) => {
|
|
86
86
|
invariant(account);
|
|
87
87
|
const input = omitBy({
|
|
@@ -93,5 +93,7 @@ export function BasicInformation() {
|
|
|
93
93
|
if (size(input) === 0)
|
|
94
94
|
return kyc.setStep(2);
|
|
95
95
|
updateAccountMutation.mutate(input);
|
|
96
|
-
}), 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:
|
|
96
|
+
}), 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 ||
|
|
97
|
+
updateAccountMutation.isPending ||
|
|
98
|
+
completed, children: completed ? (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", className: "size-5", children: [_jsx("path", { fill: "currentColor", d: "M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z", opacity: ".25" }), _jsx("path", { fill: "currentColor", d: "M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z", children: _jsx("animateTransform", { attributeName: "transform", dur: "0.75s", repeatCount: "indefinite", type: "rotate", values: "0 12 12;360 12 12" }) })] })) : ('Continue') })] })] }));
|
|
97
99
|
}
|
|
@@ -10,9 +10,8 @@ import { Button } from '../../ui/Button/index.js';
|
|
|
10
10
|
import { Dialog } from '../../ui/Dialog/index.js';
|
|
11
11
|
import { onMobileDevice } from '../../utils/onMobileDevice.js';
|
|
12
12
|
import { useKYCContext } from './KYCContext.js';
|
|
13
|
-
import { loadFaceApiModels } from './loadModels.js';
|
|
14
13
|
import PersonOverlayDesktop from './PersonOverlayDesktop.js';
|
|
15
|
-
import { dataURLtoBlob, resizeFile } from './utils.js';
|
|
14
|
+
import { dataURLtoBlob, loadFaceApiModels, resizeFile } from './utils.js';
|
|
16
15
|
export function CaptureSelfie() {
|
|
17
16
|
const kyc = useKYCContext();
|
|
18
17
|
const { mutate, isPending } = useUploadImageFileMutation();
|
|
@@ -1,17 +1,43 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import Image from 'next/image';
|
|
4
|
+
import { useEffect, useState } from 'react';
|
|
4
5
|
import { twMerge } from 'tailwind-merge';
|
|
5
|
-
import
|
|
6
|
+
import invariant from 'tiny-invariant';
|
|
6
7
|
import { useUploadImageFileMutation } from '../../client/hooks/useUploadImageFileMutation.js';
|
|
8
|
+
import { getSession } from '../../client/services/getSession.js';
|
|
7
9
|
import { UploadCloud02Icon } from '../../icons/UploadCloud02Icon.js';
|
|
10
|
+
import { getFile } from '../../services/file.js';
|
|
8
11
|
import { Button } from '../../ui/Button/index.js';
|
|
12
|
+
import { createPoll } from '../../utils/createPoll.js';
|
|
9
13
|
import { useKYCContext } from './KYCContext.js';
|
|
10
14
|
import { validateFile } from './utils.js';
|
|
11
15
|
function FileUpload({ value, name, hasDescription, onChange, captureObject, }) {
|
|
12
16
|
const kyc = useKYCContext();
|
|
13
17
|
const { mutate, isPending } = useUploadImageFileMutation();
|
|
14
|
-
const
|
|
18
|
+
const [uploadedImageUrl, setUploadedImageUrl] = useState(null);
|
|
19
|
+
async function pollImage(id) {
|
|
20
|
+
if (!id)
|
|
21
|
+
return;
|
|
22
|
+
const poll = createPoll(async () => {
|
|
23
|
+
const session = await getSession();
|
|
24
|
+
invariant(session.status === 'authenticated');
|
|
25
|
+
const file = await getFile(id, {
|
|
26
|
+
headers: {
|
|
27
|
+
Authorization: `Bearer ${session.token}`,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
return file ?? null;
|
|
31
|
+
}, { until: (r) => !!r, interval: 1000, maxAttempt: 5 });
|
|
32
|
+
const image = await poll();
|
|
33
|
+
if (!image) {
|
|
34
|
+
console.error('Image not found or failed to load');
|
|
35
|
+
}
|
|
36
|
+
setUploadedImageUrl(image?.url ?? null);
|
|
37
|
+
}
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
pollImage(value);
|
|
40
|
+
}, [value]);
|
|
15
41
|
if (isPending) {
|
|
16
42
|
return (_jsx("div", { className: "border-border-primary bg-bg-primary flex min-h-[11.25rem] flex-col justify-center gap-lg rounded-xl border px-3xl py-xl", children: _jsx("div", { className: "flex items-center justify-center", children: _jsx("span", { className: "text-text-secondary-700", children: "Uploading..." }) }) }));
|
|
17
43
|
}
|
|
@@ -38,6 +64,6 @@ function FileUpload({ value, name, hasDescription, onChange, captureObject, }) {
|
|
|
38
64
|
fileInput.click();
|
|
39
65
|
}
|
|
40
66
|
}
|
|
41
|
-
return (_jsxs("div", { className: "border-border-primary bg-bg-primary flex min-h-[11.25rem] flex-col justify-center gap-lg rounded-xl border px-3xl py-xl", children: [
|
|
67
|
+
return (_jsxs("div", { className: "border-border-primary bg-bg-primary flex min-h-[11.25rem] flex-col justify-center gap-lg rounded-xl border px-3xl py-xl", children: [uploadedImageUrl ? (_jsxs("div", { className: "border-border-primary bg-bg-primary min-h-[9.25rem]", children: [_jsx(Image, { src: uploadedImageUrl, alt: "Uploaded", className: "w-full object-contain", width: 350, height: 350, draggable: false }), _jsx(Button, { size: "xs", variant: "outline", className: twMerge('mx-auto mt-4 w-fit', value && 'hidden'), type: "button", onClick: handleUploadClick, children: "Reupload" })] })) : hasDescription ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "border-border-primary shadow-xs mx-auto flex size-8 items-center justify-center rounded-sm border", children: _jsx(UploadCloud02Icon, { className: "text-text-quinary size-4" }) }), _jsxs("p", { className: "text-text-tertiary-600 text-center text-sm", children: [_jsx("span", { className: "text-button-secondary-fg cursor-pointer font-semibold", onClick: handleUploadClick, children: "Click to upload" }), ' ', "or drag and drop", _jsx("br", {}), "PNG, JPG or JPEG (max. 10mb)", _jsx("br", {}), "or"] })] })) : null, _jsx("input", { type: "file", id: `file-upload-${name}`, name: name, onChange: handleFileChange, accept: "image/png, image/jpg, image/jpeg", className: "hidden" }), _jsx(Button, { size: "xs", variant: "outline", className: "mx-auto w-fit", onClick: () => kyc.setCapturing(captureObject), disabled: isPending, type: "button", children: value ? 'Retake Photo' : 'Take a Photo' })] }));
|
|
42
68
|
}
|
|
43
69
|
export default FileUpload;
|
|
@@ -4,11 +4,12 @@ import dynamic from 'next/dynamic';
|
|
|
4
4
|
import Script from 'next/script';
|
|
5
5
|
import { useShallow } from 'zustand/shallow';
|
|
6
6
|
import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
|
|
7
|
+
import { AutoOpen } from './AutoOpen.js';
|
|
7
8
|
const Component = dynamic(() => import('./KYC.lazy.js').then((m) => m.KYC), {
|
|
8
9
|
ssr: false,
|
|
9
10
|
loading: () => null,
|
|
10
11
|
});
|
|
11
12
|
export function KYC(props) {
|
|
12
13
|
const touched = useGlobalStore(useShallow((ctx) => ctx.kyc['~touched']));
|
|
13
|
-
return (_jsxs(_Fragment, { children: [touched && _jsx(Component, { ...props }), _jsx(Script, { src: "https://docs.opencv.org/4.7.0/opencv.js",
|
|
14
|
+
return (_jsxs(_Fragment, { children: [touched && _jsx(Component, { ...props }), _jsx(AutoOpen, {}), _jsx(Script, { src: "https://docs.opencv.org/4.7.0/opencv.js", defer: true }), _jsx(Script, { src: "https://cdn.jsdelivr.net/gh/ColonelParrot/jscanify@master/src/jscanify.min.js", defer: true })] }));
|
|
14
15
|
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
'use client';
|
|
2
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
2
|
import Image from 'next/image';
|
|
4
|
-
import { useEffect } from 'react';
|
|
5
3
|
import { useShallow } from 'zustand/shallow';
|
|
6
|
-
import { useAccountQuery } from '../../client/hooks/useAccountQuery.js';
|
|
7
4
|
import { useGlobalStore } from '../../client/hooks/useGlobalStore.js';
|
|
8
|
-
import { useMemberVerificationQuery } from '../../client/hooks/useMemberVerificationQuery.js';
|
|
9
5
|
import { XIcon } from '../../icons/XIcon.js';
|
|
10
6
|
import { Dialog } from '../../ui/Dialog/index.js';
|
|
11
7
|
import { Portal } from '../../ui/Portal/index.js';
|
|
8
|
+
import { BasicInformation } from './BasicInformation.js';
|
|
12
9
|
import { CaptureIdDocument } from './CaptureIdDocument.js';
|
|
13
10
|
import { CaptureSelfie } from './CaptureSelfie.js';
|
|
14
11
|
import { IdentityVerification } from './IdentityVerification.js';
|
|
@@ -17,31 +14,11 @@ import { KYCContext } from './KYCContext.js';
|
|
|
17
14
|
import { PersonalInformation } from './PersonalInformation.js';
|
|
18
15
|
import { useKYC } from './useKYC.js';
|
|
19
16
|
export function KYC(props) {
|
|
20
|
-
const kyc = useKYC();
|
|
21
|
-
const accountQuery = useAccountQuery();
|
|
22
|
-
const memberVerification = useMemberVerificationQuery();
|
|
23
|
-
const isBasicInfoVerified = Boolean(accountQuery.data?.realName) &&
|
|
24
|
-
Boolean(accountQuery.data?.birthDay);
|
|
25
|
-
const isMemberUploaded = Boolean(memberVerification.data?.idFrontImage) &&
|
|
26
|
-
Boolean(memberVerification.data?.selfieImage);
|
|
27
|
-
const memberStatus = memberVerification.data?.status;
|
|
28
|
-
//check steps
|
|
29
|
-
useEffect(() => {
|
|
30
|
-
if (memberStatus === 'REJECTED') {
|
|
31
|
-
kyc.setStep(2);
|
|
32
|
-
}
|
|
33
|
-
else if (isBasicInfoVerified && isMemberUploaded) {
|
|
34
|
-
kyc.setStep(3);
|
|
35
|
-
}
|
|
36
|
-
}, [isBasicInfoVerified, isMemberUploaded, memberStatus, kyc]);
|
|
37
17
|
const globalStore = useGlobalStore(useShallow((ctx) => ({
|
|
38
18
|
kyc: ctx.kyc,
|
|
39
19
|
})));
|
|
20
|
+
const kyc = useKYC();
|
|
40
21
|
return (_jsx(KYCContext, { value: kyc, children: _jsx(Dialog.Root, { open: globalStore.kyc.open, onOpenChange: (details) => {
|
|
41
22
|
globalStore.kyc.setOpen(details.open);
|
|
42
|
-
}, lazyMount: true, unmountOnExit: true, onExitComplete: ()
|
|
43
|
-
kyc.setStep(2);
|
|
44
|
-
kyc.setDone(false);
|
|
45
|
-
kyc.setCapturing(null);
|
|
46
|
-
}, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, {}), _jsx(Dialog.Positioner, { children: _jsxs(Dialog.Content, { className: "bg-bg-primary-alt lg:min-h-auto mx-auto min-h-full w-full lg:w-fit", children: [kyc.capturing === 'SELFIE' && _jsx(CaptureSelfie, {}), kyc.capturing === 'ID_DOCUMENT' && _jsx(CaptureIdDocument, {}), !kyc.capturing && (_jsxs("div", { className: "w-full p-3xl lg:w-[400px]", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsx(Image, { src: props.logo, alt: "", width: 200, height: 100, className: "mx-auto mb-5 block h-7.5 w-auto", draggable: false }), _jsx(Indicator, {}), kyc.step === 2 && _jsx(IdentityVerification, {}), kyc.step === 3 && _jsx(PersonalInformation, {})] }))] }) })] }) }) }));
|
|
23
|
+
}, lazyMount: true, unmountOnExit: true, onExitComplete: kyc.reset, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, {}), _jsx(Dialog.Positioner, { children: _jsxs(Dialog.Content, { className: "bg-bg-primary-alt lg:min-h-auto mx-auto min-h-full w-full lg:w-fit", children: [kyc.capturing === 'SELFIE' && _jsx(CaptureSelfie, {}), kyc.capturing === 'ID_DOCUMENT' && _jsx(CaptureIdDocument, {}), !kyc.capturing && (_jsxs("div", { className: "w-full p-3xl lg:w-[400px]", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsx(Image, { src: props.logo, alt: "", width: 200, height: 100, className: "mx-auto mb-5 block h-7.5 w-auto", draggable: false }), _jsx(Indicator, {}), kyc.step === 1 && _jsx(BasicInformation, {}), kyc.step === 2 && _jsx(IdentityVerification, {}), kyc.step === 3 && _jsx(PersonalInformation, {})] }))] }) })] }) }) }));
|
|
47
24
|
}
|
|
@@ -17,6 +17,13 @@ export function useKYC() {
|
|
|
17
17
|
subscriber(detail);
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
|
+
const reset = () => {
|
|
21
|
+
setStep(1);
|
|
22
|
+
setDone(false);
|
|
23
|
+
setCapturing(null);
|
|
24
|
+
setFrontImageId(null);
|
|
25
|
+
setSelfieImageId(null);
|
|
26
|
+
};
|
|
20
27
|
return {
|
|
21
28
|
step,
|
|
22
29
|
setStep,
|
|
@@ -30,5 +37,6 @@ export function useKYC() {
|
|
|
30
37
|
setSelfieImageId,
|
|
31
38
|
subscribe,
|
|
32
39
|
triggerEvent,
|
|
40
|
+
reset,
|
|
33
41
|
};
|
|
34
42
|
}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
import * as faceapi from 'face-api.js';
|
|
1
2
|
import Resizer from 'react-image-file-resizer';
|
|
3
|
+
export async function loadFaceApiModels() {
|
|
4
|
+
const MODEL_URL = '/models';
|
|
5
|
+
await Promise.all([
|
|
6
|
+
faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_URL),
|
|
7
|
+
faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL),
|
|
8
|
+
faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URL),
|
|
9
|
+
]);
|
|
10
|
+
}
|
|
2
11
|
export function dataURLtoBlob(dataURL) {
|
|
3
12
|
const parts = dataURL.split(';base64,');
|
|
4
13
|
const contentType = parts[0].split(':')[1];
|
|
@@ -27,7 +27,7 @@ const TABS = ['ALL', 'UNREAD'];
|
|
|
27
27
|
export function Messages(props) {
|
|
28
28
|
const globalStore = useGlobalStore(useShallow((ctx) => ({ messages: ctx.messages })));
|
|
29
29
|
const unreadMessagesCountQuery = useUnreadMessagesCountQuery({}, {
|
|
30
|
-
refetchInterval: globalStore.messages.open ?
|
|
30
|
+
refetchInterval: globalStore.messages.open ? 5000 : 10000,
|
|
31
31
|
});
|
|
32
32
|
const unreadMessagesCount = unreadMessagesCountQuery.data ?? 0;
|
|
33
33
|
const messagesQuery = useMessagesQuery({
|
|
@@ -41,7 +41,7 @@ export function Messages(props) {
|
|
|
41
41
|
}),
|
|
42
42
|
}, {
|
|
43
43
|
enabled: globalStore.messages.open,
|
|
44
|
-
refetchInterval:
|
|
44
|
+
refetchInterval: 10000,
|
|
45
45
|
});
|
|
46
46
|
const messages = messagesQuery.data?.pages.flatMap((page) => page.edges.map((e) => e.node)) ?? [];
|
|
47
47
|
const [mobileOffsetTop, desktopOffsetTop] = Array.isArray(props.offsetTop)
|
|
@@ -29,22 +29,24 @@ export function MessagesPopup() {
|
|
|
29
29
|
depositWithdrawal: ctx.depositWithdrawal,
|
|
30
30
|
})));
|
|
31
31
|
const markMessageAsReadMutation = useMarkMessageAsReadMutation();
|
|
32
|
-
const [paused, setPaused] = useState(false);
|
|
33
|
-
useInterval(() => setPaused(false), paused ? 1000 * 30 : null);
|
|
34
32
|
const disclosure = useDisclosure({
|
|
35
33
|
onOpenChange(open) {
|
|
36
34
|
if (open) {
|
|
37
35
|
const message = messages.at(0);
|
|
38
|
-
if (!message
|
|
36
|
+
if (!message)
|
|
37
|
+
return;
|
|
38
|
+
if (message.markedAsRead)
|
|
39
39
|
return;
|
|
40
40
|
markMessageAsReadMutation.mutate(message.id);
|
|
41
41
|
}
|
|
42
42
|
else {
|
|
43
43
|
setPaused(true);
|
|
44
|
-
|
|
44
|
+
setIndex_(0);
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
});
|
|
48
|
+
const [paused, setPaused] = useState(false);
|
|
49
|
+
useInterval(() => setPaused(false), paused ? 1000 * 30 : null);
|
|
48
50
|
const messagesQuery = useMessagesQuery({
|
|
49
51
|
first: 10,
|
|
50
52
|
filter: {
|
|
@@ -62,10 +64,19 @@ export function MessagesPopup() {
|
|
|
62
64
|
!globalStore.message.open &&
|
|
63
65
|
!globalStore.kyc.open &&
|
|
64
66
|
!paused,
|
|
65
|
-
refetchInterval: disclosure.open ? undefined :
|
|
67
|
+
refetchInterval: disclosure.open ? undefined : 10000,
|
|
66
68
|
});
|
|
67
69
|
const messages = messagesQuery.data?.pages.flatMap((page) => page.edges.map((edge) => edge.node)) ?? [];
|
|
68
|
-
const [
|
|
70
|
+
const [index, setIndex_] = useState(0);
|
|
71
|
+
const setIndex = (newIndex) => {
|
|
72
|
+
setIndex_(newIndex);
|
|
73
|
+
const message = messages.at(newIndex);
|
|
74
|
+
if (!message)
|
|
75
|
+
return;
|
|
76
|
+
if (message.markedAsRead)
|
|
77
|
+
return;
|
|
78
|
+
markMessageAsReadMutation.mutate(message.id);
|
|
79
|
+
};
|
|
69
80
|
useEffect(() => {
|
|
70
81
|
if (messages.length > 0) {
|
|
71
82
|
disclosure.setOpen(true);
|
|
@@ -73,14 +84,8 @@ export function MessagesPopup() {
|
|
|
73
84
|
}, [disclosure, messages.length, paused]);
|
|
74
85
|
return (_jsx(Dialog.Root, { open: disclosure.open, onOpenChange: (details) => {
|
|
75
86
|
disclosure.setOpen(details.open);
|
|
76
|
-
}, lazyMount: true, unmountOnExit: true, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, { className: "!z-[calc(var(--z-dialog)+3)]" }), _jsx(Dialog.Positioner, { className: "!z-[calc(var(--z-dialog)+4)] flex items-center justify-center", children: _jsxs(Dialog.Content, { className: "min-h-auto mx-auto min-w-[21.438rem] max-w-[21.438rem] rounded-xl p-3xl lg:min-w-[25rem] lg:max-w-[25rem]", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsxs(Carousel.Root, { page:
|
|
77
|
-
|
|
78
|
-
const message = messages.at(details.page - 1);
|
|
79
|
-
if (!message)
|
|
80
|
-
return;
|
|
81
|
-
if (message.markedAsRead)
|
|
82
|
-
return;
|
|
83
|
-
markMessageAsReadMutation.mutate(message.id);
|
|
87
|
+
}, lazyMount: true, unmountOnExit: true, children: _jsxs(Portal, { children: [_jsx(Dialog.Backdrop, { className: "!z-[calc(var(--z-dialog)+3)]" }), _jsx(Dialog.Positioner, { className: "!z-[calc(var(--z-dialog)+4)] flex items-center justify-center", children: _jsxs(Dialog.Content, { className: "min-h-auto mx-auto min-w-[21.438rem] max-w-[21.438rem] rounded-xl p-3xl lg:min-w-[25rem] lg:max-w-[25rem]", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsxs(Carousel.Root, { page: index, onPageChange: (details) => {
|
|
88
|
+
setIndex(details.page);
|
|
84
89
|
}, slideCount: messages.length, allowMouseDrag: true, children: [_jsx(Carousel.ItemGroup, { children: messages.map((message, index) => (_jsxs(Carousel.Item, { index: index, className: "select-none", children: [_jsx("div", { className: "bg-bg-brand-secondary text-text-brand mx-auto flex size-12 items-center justify-center rounded-full", children: _jsx(MessageIcon, { type: message.icon, className: "size-6" }) }), _jsx("h2", { className: "mt-lg text-center text-lg font-semibold xl:mt-xl", children: message.title }), message.content && (_jsx("div", { dangerouslySetInnerHTML: { __html: message.content }, className: "text-text-secondary-700 mt-xs pb-5 text-center text-sm" })), message.image && (_jsx("div", { className: "mt-5 pb-5", children: _jsx(Image, { src: message.image, alt: "", width: 400, height: 250, loading: "lazy", unoptimized: true, className: "h-auto w-full rounded-sm" }) })), message.actions.length ? (_jsx("div", { className: "mt-3xl flex flex-col gap-2 text-center lg:mt-4xl", children: message.actions.map((action, index) => (_jsx(Button, { asChild: true, children: _jsx(Link, { href: normalizeActionUrl(transactionsPageUrl, action.url), onClick: () => {
|
|
85
90
|
disclosure.setOpen(false);
|
|
86
91
|
}, children: action.name }) }, index))) })) : null] }, message.id))) }), _jsxs(Carousel.Control, { className: "mt-5 flex items-center lg:mt-3xl", children: [_jsxs(Carousel.PrevTrigger, { className: "text-text-quarterary-500 hidden items-center gap-md font-semibold disabled:invisible lg:flex", children: [_jsx(ChevronLeftIcon, { className: "size-5" }), "Back"] }), _jsx(Carousel.IndicatorGroup, { className: "flex grow justify-center gap-xs", children: messages.map((message, index) => (_jsx(Carousel.Indicator, { index: index, className: "bg-bg-quaternary ui-current:bg-brand-400 size-2.5 rounded-full transition-all duration-150 ui-current:w-5" }, message.id))) }), _jsxs(Carousel.NextTrigger, { className: "text-text-quarterary-500 hidden items-center gap-md font-semibold disabled:invisible lg:flex", children: ["Next", _jsx(ChevronRightIcon, { className: "size-5" })] })] })] })] }) })] }) }));
|
|
@@ -4,7 +4,7 @@ import Link from 'next/link';
|
|
|
4
4
|
import { ChevronLeftIcon } from '../../icons/ChevronLeftIcon.js';
|
|
5
5
|
import { Prose } from '../../ui/Prose/index.js';
|
|
6
6
|
export function News(props) {
|
|
7
|
-
return (_jsxs("div", { style: props.style, className: props.className, children: [_jsxs(Link, { href: props.viewAllUrl ?? '/news', className: "text-button-secondary-fg flex items-center gap-lg text-lg font-semibold", children: [_jsx(ChevronLeftIcon, { className: "size-6" }), "Back to all News"] }), _jsx(Image, { src: props.news.image, alt: "", width: 1024, height: 600, priority: true, className: "mt-3xl block h-auto w-full rounded-xl lg:mt-6" }), _jsx("p", { className: "text-brand-400 mt-xl text-sm font-semibold lg:mt-6", children: props.news.category }), _jsx("h2", { className: "mt-xl text-2xl font-semibold lg:mt-6", children: props.news.title }), _jsx(Prose, { className: "mt-xl lg:mt-6", dangerouslySetInnerHTML: {
|
|
7
|
+
return (_jsxs("div", { style: props.style, className: props.className, children: [_jsxs(Link, { href: props.viewAllUrl ?? '/news', className: "text-button-secondary-fg flex items-center gap-lg text-lg font-semibold", children: [_jsx(ChevronLeftIcon, { className: "size-6" }), "Back to all News"] }), _jsx(Image, { src: props.news.image, alt: "", width: 1024, height: 600, priority: true, unoptimized: true, className: "mt-3xl block h-auto w-full rounded-xl lg:mt-6" }), _jsx("p", { className: "text-brand-400 mt-xl text-sm font-semibold lg:mt-6", children: props.news.category }), _jsx("h2", { className: "mt-xl text-2xl font-semibold lg:mt-6", children: props.news.title }), _jsx(Prose, { className: "mt-xl lg:mt-6", dangerouslySetInnerHTML: {
|
|
8
8
|
__html: props.news.content,
|
|
9
9
|
} })] }));
|
|
10
10
|
}
|