@opexa/portal-components 0.0.143 → 0.0.145

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.
@@ -30,7 +30,6 @@ export const useUpdateMemberVerificationMutation = (config) => {
30
30
  selfieImage: data.selfieImage
31
31
  ? { id: data.selfieImage, status: 'UPLOADING' }
32
32
  : prev.selfieImage,
33
- status: 'UNVERIFIED',
34
33
  };
35
34
  });
36
35
  },
@@ -6,6 +6,7 @@ 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';
9
10
  import { AlertCircleIcon } from '../../icons/AlertCircleIcon.js';
10
11
  import { CheckVerified02Icon } from '../../icons/CheckVerified02Icon.js';
11
12
  import { CreditCard02Icon } from '../../icons/CreditCard02Icon.js';
@@ -20,6 +21,7 @@ export function AccountVerification(props) {
20
21
  kyc: ctx.kyc,
21
22
  })));
22
23
  const profileCompletionQuery = useProfileCompletionQuery();
24
+ const session = useSessionQuery();
23
25
  const profileCompletion = profileCompletionQuery.data;
24
26
  const verificationQuery = useMemberVerificationQuery();
25
27
  const verification = verificationQuery.data;
@@ -30,7 +32,8 @@ export function AccountVerification(props) {
30
32
  verification?.status === 'UNVERIFIED';
31
33
  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
32
34
  ? 'text-text-success-primary'
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: _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, {})] }));
35
+ : '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?.status !== 'PENDING' ||
36
+ (session.data?.status !== 'unauthenticated' && (_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, {})] }));
34
37
  }
35
38
  function VerificationNotSubmitted() {
36
39
  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." })] }));
@@ -14,6 +14,7 @@ export interface GamesListProps {
14
14
  search?: string;
15
15
  /** @default "Games"*/
16
16
  heading?: string;
17
+ viewProvidersUrl?: string;
17
18
  className?: string | ClassNameEntries;
18
19
  }
19
20
  export declare function GamesList__client(props: GamesListProps): import("react/jsx-runtime").JSX.Element;
@@ -1,8 +1,10 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { isString, noop } from 'lodash-es';
4
+ import Link from 'next/link';
4
5
  import { useGamesQuery } from '../../client/hooks/useGamesQuery.js';
5
6
  import { useInfiniteQueryHelper } from '../../client/hooks/useInfiniteQueryHelper.js';
7
+ import { ChevronLeftIcon } from '../../icons/ChevronLeftIcon.js';
6
8
  import { GamingPad01Icon } from '../../icons/GamingPad01Icon.js';
7
9
  import { SpinnerIcon } from '../../icons/SpinnerIcon.js';
8
10
  import { Button } from '../../ui/Button/index.js';
@@ -20,7 +22,7 @@ export function GamesList__client(props) {
20
22
  const classNames = isString(props.className)
21
23
  ? { root: props.className }
22
24
  : (props.className ?? {});
23
- return (_jsxs("div", { className: classNames.root, children: [_jsx("h2", { className: "text-lg font-semibold", children: props.heading ?? 'Games' }), totalRows <= 0 && (_jsx(Empty, { icon: loading ? SpinnerIcon : GamingPad01Icon, title: loading ? 'Just a moment' : 'No games', message: loading
25
+ return (_jsxs("div", { className: classNames.root, children: [_jsxs("div", { className: "flex flex-col lg:flex-row lg:items-center lg:justify-between", children: [_jsx("h2", { className: "order-2 mt-4xl text-lg font-semibold lg:order-none lg:mt-0", children: props.heading ?? 'Games' }), props.viewProvidersUrl && (_jsxs(Link, { href: props.viewProvidersUrl, className: "text-button-tertiary-fg order-1 flex items-center gap-sm text-sm font-semibold lg:order-none", children: [_jsx(ChevronLeftIcon, { className: "size-5" }), "Back to all providers"] }))] }), totalRows <= 0 && (_jsx(Empty, { icon: loading ? SpinnerIcon : GamingPad01Icon, title: loading ? 'Just a moment' : 'No games', message: loading
24
26
  ? 'Fetching latest games...'
25
27
  : 'No game is currently available. Please check back later', className: "mt-lg" })), totalRows >= 1 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "mt-lg grid grid-cols-3 gap-1.5 lg:grid-cols-6 lg:gap-2.5", children: availableRows.map((game) => (_jsx(GameContext, { value: game, children: _jsx(Game, { badge: props.badge, className: {
26
28
  root: classNames.thumbnailRoot,
@@ -15,6 +15,8 @@ import { Button } from '../../ui/Button/index.js';
15
15
  import { Dialog } from '../../ui/Dialog/index.js';
16
16
  import { Field } from '../../ui/Field/index.js';
17
17
  import { Portal } from '../../ui/Portal/index.js';
18
+ import { getQueryClient } from '../../utils/getQueryClient.js';
19
+ import { getMemberVerificationQueryKey } from '../../utils/queryKeys.js';
18
20
  import FileUpload from './FileUpload.js';
19
21
  import { useKYCContext } from './KYCContext.js';
20
22
  const formSchema = z.object({
@@ -38,9 +40,18 @@ export function IdentityVerification() {
38
40
  });
39
41
  const { mutate: updateMemberVerification, isPending: updatePending } = useUpdateMemberVerificationMutation({
40
42
  onSuccess: () => {
43
+ const queryClient = getQueryClient();
41
44
  toaster.success({
42
45
  title: 'ID Front Image & Selfie Image updated successfully',
43
46
  });
47
+ queryClient.setQueryData(getMemberVerificationQueryKey(), (prev) => {
48
+ if (!prev)
49
+ return prev;
50
+ return {
51
+ ...prev,
52
+ status: 'UNVERIFIED',
53
+ };
54
+ });
44
55
  },
45
56
  onError: (error) => {
46
57
  toaster.error({
@@ -9,7 +9,6 @@ import { useMemberVerificationQuery } from '../../client/hooks/useMemberVerifica
9
9
  import { XIcon } from '../../icons/XIcon.js';
10
10
  import { Dialog } from '../../ui/Dialog/index.js';
11
11
  import { Portal } from '../../ui/Portal/index.js';
12
- import { BasicInformation } from './BasicInformation.js';
13
12
  import { CaptureIdDocument } from './CaptureIdDocument.js';
14
13
  import { CaptureSelfie } from './CaptureSelfie.js';
15
14
  import { IdentityVerification } from './IdentityVerification.js';
@@ -28,10 +27,7 @@ export function KYC(props) {
28
27
  const memberStatus = memberVerification.data?.status;
29
28
  //check steps
30
29
  useEffect(() => {
31
- if (!isBasicInfoVerified) {
32
- kyc.setStep(1);
33
- }
34
- else if (memberStatus === 'REJECTED') {
30
+ if (memberStatus === 'REJECTED') {
35
31
  kyc.setStep(2);
36
32
  }
37
33
  else if (isBasicInfoVerified && isMemberUploaded) {
@@ -44,8 +40,8 @@ export function KYC(props) {
44
40
  return (_jsx(KYCContext, { value: kyc, children: _jsx(Dialog.Root, { open: globalStore.kyc.open, onOpenChange: (details) => {
45
41
  globalStore.kyc.setOpen(details.open);
46
42
  }, lazyMount: true, unmountOnExit: true, onExitComplete: () => {
47
- kyc.setStep(1);
43
+ kyc.setStep(2);
48
44
  kyc.setDone(false);
49
45
  kyc.setCapturing(null);
50
- }, 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, {})] }))] }) })] }) }) }));
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, {})] }))] }) })] }) }) }));
51
47
  }
@@ -14,6 +14,8 @@ import { Button } from '../../ui/Button/index.js';
14
14
  import { Checkbox } from '../../ui/Checkbox/index.js';
15
15
  import { Dialog } from '../../ui/Dialog/index.js';
16
16
  import { Field } from '../../ui/Field/index.js';
17
+ import { getQueryClient } from '../../utils/getQueryClient.js';
18
+ import { getMemberVerificationQueryKey } from '../../utils/queryKeys.js';
17
19
  import { useKYCContext } from './KYCContext.js';
18
20
  const definition = z.object({
19
21
  address: z.string().trim().min(1, 'Current address is required'),
@@ -38,6 +40,15 @@ export function PersonalInformation() {
38
40
  });
39
41
  },
40
42
  onSuccess() {
43
+ const queryClient = getQueryClient();
44
+ queryClient.setQueryData(getMemberVerificationQueryKey(), (prev) => {
45
+ if (!prev)
46
+ return prev;
47
+ return {
48
+ ...prev,
49
+ status: 'PENDING',
50
+ };
51
+ });
41
52
  kyc.setDone(true);
42
53
  globalStore.kyc.setOpen(false);
43
54
  toaster.success({
@@ -1,6 +1,6 @@
1
1
  import { useRef, useState } from 'react';
2
2
  export function useKYC() {
3
- const [step, setStep] = useState(1);
3
+ const [step, setStep] = useState(2);
4
4
  const [done, setDone] = useState(false);
5
5
  const [idFrontImageId, setFrontImageId] = useState(null);
6
6
  const [selfieImageId, setSelfieImageId] = useState(null);
@@ -8,7 +8,10 @@ import { useLocaleInfo } from '../../client/hooks/useLocaleInfo.js';
8
8
  import { useMarkMessageAsReadMutation } from '../../client/hooks/useMarkMessageAsReadMutation.js';
9
9
  import { useMessageContext } from './MessageContext.js';
10
10
  import { MessageIcon } from './MessageIcon.js';
11
+ import { useMessagesPropsContext } from './MessagesContext.js';
11
12
  export function Message() {
13
+ const messagesProps = useMessagesPropsContext();
14
+ const transactionsPageUrl = messagesProps.transactionsPageUrl ?? '/transactions';
12
15
  const message = useMessageContext();
13
16
  const localeInfo = useLocaleInfo();
14
17
  const globalStore = useGlobalStore(useShallow((ctx) => ({
@@ -23,9 +26,23 @@ export function Message() {
23
26
  if (!message.markedAsRead)
24
27
  markMessageAsReadMutation.mutate(message.id);
25
28
  };
29
+ function normalizeRedirectUrl(value) {
30
+ const searchParams = new URLSearchParams(value);
31
+ if (searchParams.has('personalCenter')) {
32
+ if (searchParams.get('personalCenter') === 'deposit' &&
33
+ searchParams.has('id')) {
34
+ return `${transactionsPageUrl}?tab=deposits&id=${searchParams.get('id')}`;
35
+ }
36
+ if (searchParams.get('personalCenter') === 'withdrawal' &&
37
+ searchParams.has('id')) {
38
+ return `${transactionsPageUrl}?tab=withdrawals&id=${searchParams.get('id')}`;
39
+ }
40
+ }
41
+ return value;
42
+ }
26
43
  return (_jsxs("div", { role: "button", tabIndex: 0, className: "border-border-secondary rounded-xs bg-bg-secondary flex h-auto flex-shrink-0 cursor-pointer flex-col border px-3.5 py-2.5", onClick: handleViewMessage, "aria-pressed": "false", children: [_jsxs("div", { className: "flex items-center space-x-2", children: [_jsx("p", { className: "text-text-tertiary-600 text-xs font-normal", children: format(new Date(message.dateTimeCreated), 'M/d/yyyy - h:mma', {
27
44
  in: tz(localeInfo.timezone),
28
- }) }), !message.markedAsRead && (_jsx("div", { className: "bg-utility-success-500 h-2.5 w-2.5 rounded-full" }))] }), _jsxs("div", { className: "mb-2 flex items-center space-x-2", children: [_jsx(MessageIcon, { type: message.icon, className: "text-brand-400 size-5" }), _jsx("p", { className: "text-text-primary-brand text-sm font-semibold", children: message.title })] }), _jsx("p", { className: "line-clamp-3 text-wrap text-sm font-normal", dangerouslySetInnerHTML: { __html: message.content } }), message.actions.length > 0 && (_jsx("div", { className: "mt-2 flex flex-wrap items-center justify-end gap-2", children: message.actions.map((action, index) => (_jsx(Link, { className: "border-button-secondary-border text-button-secondary-fg rounded-md border px-3 py-2 text-sm", href: action.url, onClick: (e) => {
45
+ }) }), !message.markedAsRead && (_jsx("div", { className: "bg-utility-success-500 h-2.5 w-2.5 rounded-full" }))] }), _jsxs("div", { className: "mb-2 flex items-center space-x-2", children: [_jsx(MessageIcon, { type: message.icon, className: "text-brand-400 size-5" }), _jsx("p", { className: "text-text-primary-brand text-sm font-semibold", children: message.title })] }), _jsx("p", { className: "line-clamp-3 text-wrap text-sm font-normal", dangerouslySetInnerHTML: { __html: message.content } }), message.actions.length > 0 && (_jsx("div", { className: "mt-2 flex flex-wrap items-center justify-end gap-2", children: message.actions.map((action, index) => (_jsx(Link, { className: "border-button-secondary-border text-button-secondary-fg rounded-md border px-3 py-2 text-sm", href: normalizeRedirectUrl(action.url), onClick: (e) => {
29
46
  e.stopPropagation();
30
47
  globalStore.messages.setOpen(false);
31
48
  globalStore.messages.setTab('ALL');
@@ -1,5 +1,5 @@
1
1
  import type { Message } from '../../types';
2
- export declare const MessageContext: (props: {
2
+ export declare const MessageProvider: (props: {
3
3
  value: Message;
4
4
  } & {
5
5
  children?: import("react").ReactNode | undefined;
@@ -1,2 +1,2 @@
1
1
  import { createContext } from '../../client/utils/createContext.js';
2
- export const [MessageContext, useMessageContext] = createContext();
2
+ export const [MessageProvider, useMessageContext] = createContext();
@@ -9,5 +9,7 @@ export interface MessagesProps {
9
9
  * ```
10
10
  */
11
11
  offsetTop?: string | [mobile: string, desktop: string];
12
+ /** @default '/transactions' */
13
+ transactionsPageUrl?: string;
12
14
  }
13
15
  export declare function Messages(props: MessagesProps): import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { twMerge } from 'tailwind-merge';
4
4
  import { z } from 'zod';
5
5
  import { useShallow } from 'zustand/shallow';
@@ -13,8 +13,9 @@ import { Portal } from '../../ui/Portal/index.js';
13
13
  import { Tabs } from '../../ui/Tabs/index.js';
14
14
  import { InfiniteScroll } from '../shared/InfiniteScroll.js';
15
15
  import { Message } from './Message.js';
16
- import { MessageContext } from './MessageContext.js';
16
+ import { MessageProvider } from './MessageContext.js';
17
17
  import { MessagePopup } from './MessagePopup.js';
18
+ import { MessagesPropsProvider } from './MessagesContext.js';
18
19
  const TABS = ['ALL', 'UNREAD'];
19
20
  export function Messages(props) {
20
21
  const globalStore = useGlobalStore(useShallow((ctx) => ({ messages: ctx.messages })));
@@ -39,10 +40,10 @@ export function Messages(props) {
39
40
  const [mobileOffsetTop, desktopOffsetTop] = Array.isArray(props.offsetTop)
40
41
  ? props.offsetTop
41
42
  : [props.offsetTop ?? '0px', props.offsetTop ?? '0px'];
42
- return (_jsxs(_Fragment, { children: [_jsx(Drawer.Root, { open: globalStore.messages.open, onOpenChange: ({ open }) => globalStore.messages.setOpen(open), lazyMount: true, unmountOnExit: true, children: _jsx(Portal, { children: _jsx(Drawer.Positioner, { children: _jsx(Drawer.Content, { className: twMerge('flex', 'flex-col', 'border-border-secondary', 'top-[var(--offset-top-mobile)]', 'h-[calc(100%-var(--offset-top-mobile))]', 'lg:border-l', 'lg:top-[var(--offset-top-desktop)]', 'lg:h-[calc(100%-var(--offset-top-desktop))]'), style: {
43
+ return (_jsxs(MessagesPropsProvider, { value: props, children: [_jsx(Drawer.Root, { open: globalStore.messages.open, onOpenChange: ({ open }) => globalStore.messages.setOpen(open), lazyMount: true, unmountOnExit: true, children: _jsx(Portal, { children: _jsx(Drawer.Positioner, { children: _jsx(Drawer.Content, { className: twMerge('flex', 'flex-col', 'border-border-secondary', 'top-[var(--offset-top-mobile)]', 'h-[calc(100%-var(--offset-top-mobile))]', 'lg:border-l', 'lg:top-[var(--offset-top-desktop)]', 'lg:h-[calc(100%-var(--offset-top-desktop))]'), style: {
43
44
  ['--offset-top-mobile']: mobileOffsetTop,
44
45
  ['--offset-top-desktop']: desktopOffsetTop,
45
- }, children: _jsxs("div", { className: "flex flex-col space-y-6", children: [_jsxs("div", { className: "flex items-end justify-between px-4 pt-6", children: [_jsx("p", { className: "text-text-primary-brand text-xl font-semibold", children: "Notifications" }), _jsx(Drawer.CloseTrigger, { className: "p-2", children: _jsx(XIcon, {}) })] }), _jsxs(Tabs.Root, { value: globalStore.messages.tab, onValueChange: (details) => globalStore.messages.setTab(z.enum(TABS).parse(details.value)), lazyMount: true, unmountOnExit: true, children: [_jsx("div", { className: "mb-4 w-full px-4", children: _jsxs(Tabs.List, { className: "border-border-secondary w-full border", children: [_jsx(Tabs.Trigger, { value: "ALL", className: "flex-1/5 ui-selected:text-text-primary-brand text-text-tertiary-600", children: "All" }), _jsxs(Tabs.Trigger, { value: "UNREAD", className: "flex-1/5 ui-selected:text-text-primary-brand text-text-tertiary-600 flex items-center justify-center space-x-2", children: [_jsx("div", { children: "Unread" }), !!unreadMessagesCount && (_jsx("div", { className: "border-border-primary bg-bg-secondary rounded-full border px-2 py-0.5", children: unreadMessagesCount }))] }), _jsx(Tabs.Indicator, { className: "bg-bg-active" })] }) }), _jsx("div", { className: "border-border-secondary w-full border-t" }), TABS.map((tab) => (_jsxs(Tabs.Content, { value: tab, className: "scrollbar:w-2 scrollbar-track:bg-bg-primary-alt scrollbar-track:rounded-full scrollbar-thumb:bg-bg-quaternary scrollbar-thumb:rounded-full max-h-[calc(100vh-197px)] overflow-y-auto p-xl", style: { scrollbarGutter: 'stable' }, children: [messages.length > 0 && (_jsx("div", { className: "flex flex-col space-y-4", children: messages.map((message) => (_jsx(MessageContext, { value: message, children: _jsx(Message, {}) }, message.id))) })), _jsx(InfiniteScroll, { loader: _jsx(SpinnerIcon, { className: "mx-auto size-5" }), hasMore: !!messagesQuery.hasNextPage, loadMore: async () => {
46
+ }, children: _jsxs("div", { className: "flex flex-col space-y-6", children: [_jsxs("div", { className: "flex items-end justify-between px-4 pt-6", children: [_jsx("p", { className: "text-text-primary-brand text-xl font-semibold", children: "Notifications" }), _jsx(Drawer.CloseTrigger, { className: "p-2", children: _jsx(XIcon, {}) })] }), _jsxs(Tabs.Root, { value: globalStore.messages.tab, onValueChange: (details) => globalStore.messages.setTab(z.enum(TABS).parse(details.value)), lazyMount: true, unmountOnExit: true, children: [_jsx("div", { className: "mb-4 w-full px-4", children: _jsxs(Tabs.List, { className: "border-border-secondary w-full border", children: [_jsx(Tabs.Trigger, { value: "ALL", className: "flex-1/5 ui-selected:text-text-primary-brand text-text-tertiary-600", children: "All" }), _jsxs(Tabs.Trigger, { value: "UNREAD", className: "flex-1/5 ui-selected:text-text-primary-brand text-text-tertiary-600 flex items-center justify-center space-x-2", children: [_jsx("div", { children: "Unread" }), !!unreadMessagesCount && (_jsx("div", { className: "border-border-primary bg-bg-secondary rounded-full border px-2 py-0.5", children: unreadMessagesCount }))] }), _jsx(Tabs.Indicator, { className: "bg-bg-active" })] }) }), _jsx("div", { className: "border-border-secondary w-full border-t" }), TABS.map((tab) => (_jsxs(Tabs.Content, { value: tab, className: "scrollbar:w-2 scrollbar-track:bg-bg-primary-alt scrollbar-track:rounded-full scrollbar-thumb:bg-bg-quaternary scrollbar-thumb:rounded-full max-h-[calc(100vh-197px)] overflow-y-auto p-xl", style: { scrollbarGutter: 'stable' }, children: [messages.length > 0 && (_jsx("div", { className: "flex flex-col space-y-4", children: messages.map((message) => (_jsx(MessageProvider, { value: message, children: _jsx(Message, {}) }, message.id))) })), _jsx(InfiniteScroll, { loader: _jsx(SpinnerIcon, { className: "mx-auto size-5" }), hasMore: !!messagesQuery.hasNextPage, loadMore: async () => {
46
47
  await messagesQuery.fetchNextPage();
47
48
  }, className: "mt-4" })] }, tab)))] })] }) }) }) }) }), _jsx(MessagePopup, {})] }));
48
49
  }
@@ -0,0 +1,6 @@
1
+ import type { MessagesProps } from './Messages.lazy';
2
+ export declare const MessagesPropsProvider: (props: {
3
+ value: MessagesProps;
4
+ } & {
5
+ children?: import("react").ReactNode | undefined;
6
+ }) => React.ReactNode, useMessagesPropsContext: () => MessagesProps;
@@ -0,0 +1,2 @@
1
+ import { createContext } from '../../client/utils/createContext.js';
2
+ export const [MessagesPropsProvider, useMessagesPropsContext] = createContext();
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { tz, TZDateMini } from '@date-fns/tz';
4
4
  import { endOfDay, format, startOfDay } from 'date-fns';
5
+ import { usePathname, useRouter, useSearchParams } from 'next/navigation';
5
6
  import { useReducer } from 'react';
6
7
  import { twMerge } from 'tailwind-merge';
7
8
  import { useDepositRecordsQuery } from '../../client/hooks/useDepositRecordsQuery.js';
@@ -19,6 +20,9 @@ import { formatNumber } from '../../utils/formatNumber.js';
19
20
  import { Empty } from '../shared/Empty.js';
20
21
  import { TableFilters } from './TableFilters.js';
21
22
  export function DepositRecordsTable() {
23
+ const router = useRouter();
24
+ const pathname = usePathname();
25
+ const searchParams = useSearchParams();
22
26
  const [state, setState] = useReducer((prev, next) => ({
23
27
  ...prev,
24
28
  ...next,
@@ -26,6 +30,11 @@ export function DepositRecordsTable() {
26
30
  const localeInfo = useLocaleInfo();
27
31
  const { page, hasNextPage, hasPrevPage, next, prev, rows, totalPages, loading, firstPage, } = useInfiniteQueryHelper(useDepositRecordsQuery, {
28
32
  filter: {
33
+ ...(searchParams.has('id') && {
34
+ deposit: {
35
+ equal: searchParams.get('id')?.toString(),
36
+ },
37
+ }),
29
38
  ...(state.type && {
30
39
  type: {
31
40
  equal: state.type,
@@ -59,6 +68,11 @@ export function DepositRecordsTable() {
59
68
  timestamp: value.timestamp,
60
69
  });
61
70
  firstPage();
71
+ if (searchParams.has('id')) {
72
+ const newSearchParams = new URLSearchParams(searchParams);
73
+ newSearchParams.delete('id');
74
+ router.push(`${pathname}?${newSearchParams.toString()}`);
75
+ }
62
76
  }, enabledFilters: {
63
77
  depositType: true,
64
78
  depositStatus: true,
@@ -1,4 +1,2 @@
1
- export interface TransactionRecordsProps {
2
- className?: string;
3
- }
4
- export declare function TransactionRecords(props: TransactionRecordsProps): Promise<import("react/jsx-runtime").JSX.Element>;
1
+ import { type TransactionRecordsProps } from './TransactionRecords.suspense';
2
+ export declare function TransactionRecords(props: TransactionRecordsProps): import("react/jsx-runtime").JSX.Element;
@@ -1,13 +1,7 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { prefetchTransactionRecordsQuery } from '../../server/utils/prefetchTransactionRecordsQuery.js';
3
- import { Tabs } from '../../ui/Tabs/index.js';
4
- import { DepositRecordsTable } from './DepositRecordsTable.js';
5
- import { TransactionRecordsTable } from './TransactionRecordsTable.js';
6
- import { WithdrawalRecordsTable } from './WithdrawalRecordsTable.js';
7
- export async function TransactionRecords(props) {
8
- await prefetchTransactionRecordsQuery({
9
- first: 10,
10
- filter: {},
11
- });
12
- return (_jsxs("div", { className: props.className, children: [_jsx("h2", { className: "text-sm font-semibold leading-tight lg:text-lg", children: "Transactions" }), _jsx("p", { className: "text-text-tertiary-600 mt-xs text-sm leading-tight", children: "View your transaction records" }), _jsxs(Tabs.Root, { className: "mt-lg lg:mt-2xl", defaultValue: "transactions", lazyMount: true, unmountOnExit: true, children: [_jsxs(Tabs.List, { children: [_jsx(Tabs.Trigger, { value: "transactions", children: "All Transactions" }), _jsx(Tabs.Trigger, { value: "deposits", children: "Deposits" }), _jsx(Tabs.Trigger, { value: "withdrawals", children: "Withdrawals" }), _jsx(Tabs.Indicator, {})] }), _jsx("div", { className: "border-border-secondary mt-2xl hidden border-t lg:block" }), _jsx("h3", { className: "text-text-secondary-700 mt-3xl text-sm font-semibold", children: "Table" }), _jsx(Tabs.Content, { value: "transactions", className: "mt-xl", children: _jsx(TransactionRecordsTable, {}) }), _jsx(Tabs.Content, { value: "deposits", className: "mt-xl", children: _jsx(DepositRecordsTable, {}) }), _jsx(Tabs.Content, { value: "withdrawals", className: "mt-xl", children: _jsx(WithdrawalRecordsTable, {}) })] })] }));
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Suspense } from 'react';
4
+ import { TransactionRecords__suspense, } from './TransactionRecords.suspense.js';
5
+ export function TransactionRecords(props) {
6
+ return (_jsx(Suspense, { fallback: null, children: _jsx(TransactionRecords__suspense, { ...props }) }));
13
7
  }
@@ -0,0 +1,4 @@
1
+ export interface TransactionRecordsProps {
2
+ className?: string;
3
+ }
4
+ export declare function TransactionRecords__suspense(props: TransactionRecordsProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,28 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { usePathname, useRouter, useSearchParams } from 'next/navigation';
4
+ import { Suspense } from 'react';
5
+ import { z } from 'zod';
6
+ import { Tabs } from '../../ui/Tabs/index.js';
7
+ import { DepositRecordsTable } from './DepositRecordsTable.js';
8
+ import { TransactionRecordsTable } from './TransactionRecordsTable.js';
9
+ import { WithdrawalRecordsTable } from './WithdrawalRecordsTable.js';
10
+ const TabSchema = z
11
+ .enum(['transactions', 'deposits', 'withdrawals'])
12
+ .optional()
13
+ .nullable()
14
+ .catch('transactions')
15
+ .transform((v) => v ?? 'transactions');
16
+ export function TransactionRecords__suspense(props) {
17
+ const router = useRouter();
18
+ const pathname = usePathname();
19
+ const searchParams = useSearchParams();
20
+ const tab = TabSchema.parse(searchParams.get('tab'));
21
+ const setTab = (value) => {
22
+ const newSearchParams = new URLSearchParams(searchParams);
23
+ newSearchParams.set('tab', value);
24
+ newSearchParams.delete('id');
25
+ router.push(`${pathname}?${newSearchParams.toString()}`);
26
+ };
27
+ return (_jsxs("div", { className: props.className, children: [_jsx("h2", { className: "text-sm font-semibold leading-tight lg:text-lg", children: "Transactions" }), _jsx("p", { className: "text-text-tertiary-600 mt-xs text-sm leading-tight", children: "View your transaction records" }), _jsxs(Tabs.Root, { className: "mt-lg lg:mt-2xl", value: tab, onValueChange: (details) => setTab(TabSchema.parse(details.value)), lazyMount: true, unmountOnExit: true, children: [_jsxs(Tabs.List, { children: [_jsx(Tabs.Trigger, { value: "transactions", children: "All Transactions" }), _jsx(Tabs.Trigger, { value: "deposits", children: "Deposits" }), _jsx(Tabs.Trigger, { value: "withdrawals", children: "Withdrawals" }), _jsx(Tabs.Indicator, {})] }), _jsx("div", { className: "border-border-secondary mt-2xl hidden border-t lg:block" }), _jsx("h3", { className: "text-text-secondary-700 mt-3xl text-sm font-semibold", children: "Table" }), _jsx(Tabs.Content, { value: "transactions", className: "mt-xl", children: _jsx(TransactionRecordsTable, {}) }), _jsx(Tabs.Content, { value: "deposits", className: "mt-xl", children: _jsx(Suspense, { fallback: null, children: _jsx(DepositRecordsTable, {}) }) }), _jsx(Tabs.Content, { value: "withdrawals", className: "mt-xl", children: _jsx(Suspense, { fallback: null, children: _jsx(WithdrawalRecordsTable, {}) }) })] })] }));
28
+ }
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { tz, TZDateMini } from '@date-fns/tz';
4
4
  import { endOfDay, format, startOfDay } from 'date-fns';
5
+ import { usePathname, useRouter, useSearchParams } from 'next/navigation';
5
6
  import { useReducer } from 'react';
6
7
  import { twMerge } from 'tailwind-merge';
7
8
  import { useInfiniteQueryHelper } from '../../client/hooks/useInfiniteQueryHelper.js';
@@ -19,6 +20,9 @@ import { formatNumber } from '../../utils/formatNumber.js';
19
20
  import { Empty } from '../shared/Empty.js';
20
21
  import { TableFilters } from './TableFilters.js';
21
22
  export function WithdrawalRecordsTable() {
23
+ const router = useRouter();
24
+ const pathname = usePathname();
25
+ const searchParams = useSearchParams();
22
26
  const [state, setState] = useReducer((prev, next) => ({
23
27
  ...prev,
24
28
  ...next,
@@ -26,6 +30,11 @@ export function WithdrawalRecordsTable() {
26
30
  const localeInfo = useLocaleInfo();
27
31
  const { page, hasNextPage, hasPrevPage, next, prev, rows, totalPages, loading, firstPage, } = useInfiniteQueryHelper(useWithdrawalRecordsQuery, {
28
32
  filter: {
33
+ ...(searchParams.has('id') && {
34
+ withdrawal: {
35
+ equal: searchParams.get('id')?.toString(),
36
+ },
37
+ }),
29
38
  ...(state.type && {
30
39
  type: {
31
40
  equal: state.type,
@@ -59,6 +68,11 @@ export function WithdrawalRecordsTable() {
59
68
  timestamp: value.timestamp,
60
69
  });
61
70
  firstPage();
71
+ if (searchParams.has('id')) {
72
+ const newSearchParams = new URLSearchParams(searchParams);
73
+ newSearchParams.delete('id');
74
+ router.push(`${pathname}?${newSearchParams.toString()}`);
75
+ }
62
76
  }, enabledFilters: {
63
77
  withdrawalType: true,
64
78
  withdrawalStatus: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opexa/portal-components",
3
- "version": "0.0.143",
3
+ "version": "0.0.145",
4
4
  "exports": {
5
5
  "./ui/*": {
6
6
  "types": "./dist/ui/*/index.d.ts",