@opexa/portal-components 0.0.273 → 0.0.275

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.
@@ -0,0 +1,2 @@
1
+ import type { Query } from '../../types';
2
+ export declare const useSessionHealthQuery: Query<boolean>;
@@ -0,0 +1,29 @@
1
+ import { useQuery } from '@tanstack/react-query';
2
+ import invariant from 'tiny-invariant';
3
+ import { getSessionHealth } from '../../services/auth.js';
4
+ import { getSessionHealthQueryKey } from '../../utils/queryKeys.js';
5
+ import { getSession } from '../services/getSession.js';
6
+ import { useSessionQuery } from './useSessionQuery.js';
7
+ export const useSessionHealthQuery = (config) => {
8
+ const sessionQuery = useSessionQuery();
9
+ return useQuery({
10
+ gcTime: 1000 * 2,
11
+ staleTime: 1000,
12
+ ...config,
13
+ enabled: config?.enabled === false
14
+ ? false
15
+ : sessionQuery.data?.status === 'authenticated',
16
+ queryKey: getSessionHealthQueryKey(),
17
+ queryFn: async ({ signal }) => {
18
+ const session = await getSession({ signal });
19
+ invariant(session.status === 'authenticated');
20
+ const ok = await getSessionHealth({
21
+ signal,
22
+ headers: {
23
+ Authorization: `Bearer ${session.token}`,
24
+ },
25
+ });
26
+ return ok;
27
+ },
28
+ });
29
+ };
@@ -13,6 +13,7 @@ export function KYCReminder(props) {
13
13
  const globalStore = useGlobalStore(useShallow((ctx) => ({
14
14
  kyc: ctx.kyc,
15
15
  kycReminder: ctx.kycReminder,
16
+ messages: ctx.messages,
16
17
  })));
17
18
  const { data: session, isLoading: sessionLoading } = useSessionQuery();
18
19
  const { data: account, isLoading: accountLoading } = useAccountQuery();
@@ -26,6 +27,7 @@ export function KYCReminder(props) {
26
27
  Boolean(verification?.status === 'APPROVED');
27
28
  const hasMissingData = !isBasicInfoCompleted || !isUploadCompleted || !isVerified;
28
29
  return (_jsx(Dialog.Root, { open: globalStore.kycReminder.open &&
30
+ !globalStore.messages.open &&
29
31
  !sessionLoading &&
30
32
  !accountLoading &&
31
33
  !verificationLoading &&
@@ -31,6 +31,7 @@ export function MessagesPopup() {
31
31
  gameLaunch: ctx.gameLaunch,
32
32
  depositWithdrawal: ctx.depositWithdrawal,
33
33
  kycReminder: ctx.kycReminder,
34
+ signIn: ctx.signIn,
34
35
  })));
35
36
  const markMessageAsReadMutation = useMarkMessageAsReadMutation();
36
37
  const [paused, setPaused] = useState(false);
@@ -72,6 +73,7 @@ export function MessagesPopup() {
72
73
  !globalStore.account__mobile.open &&
73
74
  !globalStore.kyc.open &&
74
75
  !globalStore.kycReminder.open &&
76
+ !globalStore.signIn.open &&
75
77
  !paused,
76
78
  refetchInterval: disclosure.open ? undefined : 1000 * 10,
77
79
  });
@@ -90,10 +92,10 @@ export function MessagesPopup() {
90
92
  if (messages.length <= 0)
91
93
  return;
92
94
  disclosure.setOpen(true);
93
- }, disclosure.open || paused ? null : 2500);
95
+ }, !disclosure.open && !paused ? 2500 : null);
94
96
  return (_jsx(Dialog.Root, { open: disclosure.open, onOpenChange: (details) => {
95
97
  disclosure.setOpen(details.open);
96
- }, 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] overflow-y-auto", children: [_jsx(Dialog.CloseTrigger, { children: _jsx(XIcon, {}) }), _jsxs(Carousel.Root, { page: index, onPageChange: (details) => {
98
+ }, 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] overflow-y-auto 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) => {
97
99
  setIndex(details.page);
98
100
  }, slideCount: messages.length, allowMouseDrag: true, autoplay: false, 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(action.url, {
99
101
  questsPageUrl,
@@ -0,0 +1 @@
1
+ export declare function SessionWatcher(): null;
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+ import { useRouter } from 'next/navigation';
3
+ import { useCallback, useEffect } from 'react';
4
+ import { useSessionHealthQuery } from '../../client/hooks/useSessionHealthQuery.js';
5
+ import { useSignOutMutation } from '../../client/hooks/useSignOutMutation.js';
6
+ export function SessionWatcher() {
7
+ const router = useRouter();
8
+ const query = useSessionHealthQuery({ refetchInterval: 1000 * 5 });
9
+ const healthy = query.data ?? true;
10
+ const mutation = useSignOutMutation();
11
+ const signOut = useCallback(async () => {
12
+ await mutation.mutateAsync();
13
+ router.refresh();
14
+ }, [mutation, router]);
15
+ useEffect(() => {
16
+ if (!healthy)
17
+ signOut();
18
+ }, [healthy, signOut]);
19
+ return null;
20
+ }
@@ -0,0 +1 @@
1
+ export * from './SessionWatcher';
@@ -0,0 +1 @@
1
+ export * from './SessionWatcher.js';
@@ -18,14 +18,14 @@ export declare const GET: (req: NextRequest, { params }: Context) => Promise<Nex
18
18
  __error?: unknown;
19
19
  } | {
20
20
  ok: true;
21
- data: Record<string, unknown>;
21
+ data: import("../types").Session;
22
22
  }> | NextResponse<{
23
23
  ok: false;
24
24
  message: string;
25
25
  __error?: unknown;
26
26
  } | {
27
27
  ok: true;
28
- data: import("../types").Session;
28
+ data: Record<string, unknown>;
29
29
  }>>;
30
30
  export declare const DELETE: (req: NextRequest, { params }: Context) => Promise<NextResponse<{
31
31
  ok: true;
@@ -0,0 +1 @@
1
+ export declare const prefetchSessionHealthQuery: () => Promise<void>;
@@ -0,0 +1,24 @@
1
+ import { cache } from 'react';
2
+ import { getSessionHealth } from '../../services/auth.js';
3
+ import { getQueryClient } from '../../utils/getQueryClient.js';
4
+ import { log } from '../../utils/log.js';
5
+ import { getSessionHealthQueryKey } from '../../utils/queryKeys.js';
6
+ import { getSession } from '../services/getSession.js';
7
+ export const prefetchSessionHealthQuery = cache(async () => {
8
+ const session = await getSession();
9
+ if (session.status === 'unauthenticated')
10
+ return;
11
+ await getQueryClient()
12
+ .prefetchQuery({
13
+ queryKey: getSessionHealthQueryKey(),
14
+ queryFn: async ({ signal }) => {
15
+ return await getSessionHealth({
16
+ signal,
17
+ headers: {
18
+ Authorization: `Bearer ${session.token}`,
19
+ },
20
+ });
21
+ },
22
+ })
23
+ .catch(() => log.text("'prefetchSessionHealthQuery' failed", 'error'));
24
+ });
@@ -69,7 +69,7 @@ export interface RefreshSessionMutation extends Omit<CreateSessionTwoFactorAuthD
69
69
  }
70
70
  export declare function refreshSession(options?: HttpRequestOptions): Promise<RefreshSessionMutation>;
71
71
  export declare function destroySession(options?: HttpRequestOptions): Promise<void>;
72
- export declare function verifySession(options?: HttpRequestOptions): Promise<boolean>;
72
+ export declare function getSessionHealth(options?: HttpRequestOptions): Promise<boolean>;
73
73
  export interface SendVerificationCodeInput {
74
74
  strict?: boolean;
75
75
  channel: 'SMS' | 'EMAIL';
@@ -126,14 +126,13 @@ export async function destroySession(options) {
126
126
  /* ignore */
127
127
  }
128
128
  }
129
- export async function verifySession(options) {
129
+ export async function getSessionHealth(options) {
130
130
  try {
131
- const res = await httpRequest(`${AUTH_ENDPOINT}/session`, options);
132
- return res.ok;
131
+ await httpRequest(`${AUTH_ENDPOINT}/session`, options);
132
+ return true;
133
133
  }
134
134
  catch {
135
- /* Assume session is still valid for unknown errors like Network */
136
- return true;
135
+ return false;
137
136
  }
138
137
  }
139
138
  export async function sendVerificationCode(input, options) {
@@ -45,3 +45,4 @@ export declare const getOnboardingStatusQueryKey: () => QueryKey;
45
45
  export declare const getRecommendedGamesQueryKey: () => QueryKey;
46
46
  export declare const getFileQueryKey: (id: string) => QueryKey;
47
47
  export declare const getSiteQueryKey: () => QueryKey;
48
+ export declare const getSessionHealthQueryKey: () => QueryKey;
@@ -42,3 +42,4 @@ export const getOnboardingStatusQueryKey = () => [PARENT_KEY, 'onboardingStatus'
42
42
  export const getRecommendedGamesQueryKey = () => [PARENT_KEY, 'recommendedGames'].filter(Boolean);
43
43
  export const getFileQueryKey = (id) => [PARENT_KEY, 'file', id].filter(Boolean);
44
44
  export const getSiteQueryKey = () => [PARENT_KEY, 'site', SITE_ID].filter(Boolean);
45
+ export const getSessionHealthQueryKey = () => [PARENT_KEY, 'sessionHealth'].filter(Boolean);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opexa/portal-components",
3
- "version": "0.0.273",
3
+ "version": "0.0.275",
4
4
  "exports": {
5
5
  "./ui/*": {
6
6
  "types": "./dist/ui/*/index.d.ts",