@opexa/portal-components 0.0.370 → 0.0.372

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 @@
1
+ export declare function useIdle(timeout: number): boolean;
@@ -0,0 +1,35 @@
1
+ 'use client';
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ const IDLE_EVENTS = [
4
+ 'scroll',
5
+ 'resize',
6
+ 'keydown',
7
+ 'mousedown',
8
+ 'touchstart',
9
+ 'mousemove',
10
+ ];
11
+ export function useIdle(timeout) {
12
+ const [isIdle, setIsIdle] = useState(false);
13
+ const handleWorkerMessage = useCallback(() => {
14
+ setIsIdle(true);
15
+ }, []);
16
+ useEffect(() => {
17
+ const worker = new Worker('/idle-worker.js');
18
+ worker.onmessage = handleWorkerMessage;
19
+ const handleActivity = () => {
20
+ setIsIdle(false);
21
+ worker.postMessage({ command: 'reset', idleTime: timeout });
22
+ };
23
+ worker.postMessage({ command: 'start', idleTime: timeout });
24
+ for (const event of IDLE_EVENTS) {
25
+ window.addEventListener(event, handleActivity);
26
+ }
27
+ return () => {
28
+ worker.terminate();
29
+ for (const event of IDLE_EVENTS) {
30
+ window.removeEventListener(event, handleActivity);
31
+ }
32
+ };
33
+ }, [timeout, handleWorkerMessage]);
34
+ return isIdle;
35
+ }
@@ -0,0 +1 @@
1
+ export declare function useIdleLogout(timer?: number): void;
@@ -0,0 +1,82 @@
1
+ 'use client';
2
+ import { useRouter } from 'next/navigation';
3
+ import { useEffect, useRef } from 'react';
4
+ import { toaster } from '../utils/toaster.js';
5
+ import { useIdle } from './useIdle.js';
6
+ import { useSessionQuery } from './useSessionQuery.js';
7
+ import { useSignOutMutation } from './useSignOutMutation.js';
8
+ const IDLE_TIMESTAMP_KEY = 'idle-logout-timestamp';
9
+ const DEFAULT_IDLE_TIMER = 1000 * 60 * 15; // 15 minutes
10
+ export function useIdleLogout(timer = DEFAULT_IDLE_TIMER) {
11
+ const router = useRouter();
12
+ const sessionQuery = useSessionQuery();
13
+ const logoutInitiated = useRef(false);
14
+ const isLoggingOut = useRef(false);
15
+ const signOutMutation = useSignOutMutation({
16
+ onSuccess: () => {
17
+ router.refresh();
18
+ localStorage.removeItem(IDLE_TIMESTAMP_KEY);
19
+ },
20
+ onError: () => {
21
+ isLoggingOut.current = false;
22
+ },
23
+ });
24
+ const isIdle = useIdle(timer);
25
+ const sessionStatusRef = useRef(sessionQuery.data?.status);
26
+ sessionStatusRef.current = sessionQuery.data?.status;
27
+ useEffect(() => {
28
+ const handleUnload = () => {
29
+ if (sessionStatusRef.current === 'authenticated' && !isLoggingOut.current) {
30
+ localStorage.setItem(IDLE_TIMESTAMP_KEY, Date.now().toString());
31
+ }
32
+ };
33
+ if (sessionQuery.data?.status === 'authenticated') {
34
+ const lastActivityTimestamp = localStorage.getItem(IDLE_TIMESTAMP_KEY);
35
+ if (lastActivityTimestamp) {
36
+ localStorage.removeItem(IDLE_TIMESTAMP_KEY);
37
+ const timeElapsed = Date.now() - parseInt(lastActivityTimestamp, 10);
38
+ if (timeElapsed > timer) {
39
+ if (!logoutInitiated.current) {
40
+ logoutInitiated.current = true;
41
+ setTimeout(() => {
42
+ toaster.warning({
43
+ title: 'You have been away for a while.',
44
+ description: 'You have been logged out for inactivity.',
45
+ });
46
+ isLoggingOut.current = true;
47
+ signOutMutation.mutate();
48
+ }, 0);
49
+ }
50
+ return;
51
+ }
52
+ }
53
+ window.addEventListener('beforeunload', handleUnload);
54
+ }
55
+ else {
56
+ localStorage.removeItem(IDLE_TIMESTAMP_KEY);
57
+ }
58
+ return () => {
59
+ window.removeEventListener('beforeunload', handleUnload);
60
+ handleUnload();
61
+ };
62
+ }, [sessionQuery.data?.status, signOutMutation, timer]);
63
+ useEffect(() => {
64
+ if (isIdle && sessionQuery.data?.status === 'authenticated') {
65
+ if (logoutInitiated.current) {
66
+ return;
67
+ }
68
+ logoutInitiated.current = true;
69
+ setTimeout(() => {
70
+ toaster.warning({
71
+ title: 'You have been idle for a while.',
72
+ description: 'You will be logged out for inactivity.',
73
+ });
74
+ isLoggingOut.current = true;
75
+ signOutMutation.mutate();
76
+ }, 0);
77
+ }
78
+ else {
79
+ logoutInitiated.current = false;
80
+ }
81
+ }, [isIdle, sessionQuery.data?.status, signOutMutation]);
82
+ }
@@ -164,7 +164,7 @@ export function PisoPayDeposit() {
164
164
  promo: data.promo,
165
165
  }),
166
166
  });
167
- }), noValidate: true, children: [_jsxs(Field.Root, { invalid: !!form.formState.errors.amount, className: "mt-3xl", children: [_jsx(Field.Label, { children: "Enter amount you want to withdraw" }), _jsx(Field.Input, { type: "number", ...form.register('amount') }), _jsx(Field.ErrorText, { children: form.formState.errors.amount?.message })] }), _jsx(AmountChoices, { value: parseDecimal(form.watch('amount').trim().replace(/,/g, ''), 0), onChange: (value) => {
167
+ }), noValidate: true, children: [_jsxs(Field.Root, { invalid: !!form.formState.errors.amount, className: "mt-3xl", children: [_jsx(Field.Label, { children: "Enter the amount you want to deposit" }), _jsx(Field.Input, { type: "number", ...form.register('amount') }), _jsx(Field.ErrorText, { children: form.formState.errors.amount?.message })] }), _jsx(AmountChoices, { value: parseDecimal(form.watch('amount').trim().replace(/,/g, ''), 0), onChange: (value) => {
168
168
  form.setValue('amount', value.toString(), {
169
169
  shouldTouch: true,
170
170
  shouldDirty: true,
@@ -103,7 +103,7 @@ export function QRPHDepositForm() {
103
103
  }, [form, minimumAmount]);
104
104
  if (context.view !== 'form')
105
105
  return null;
106
- return (_jsxs("form", { onSubmit: form.handleSubmit(context.generateQRCode), noValidate: true, children: [_jsxs(Field.Root, { invalid: !!form.formState.errors.amount, className: "mt-3xl", children: [_jsx(Field.Label, { children: "Enter amount you want to withdraw" }), _jsx(Field.Input, { type: "number", ...form.register('amount') }), _jsx(Field.ErrorText, { children: form.formState.errors.amount?.message })] }), _jsx(AmountChoices, { value: parseDecimal(form.watch('amount'), 0), onChange: (value) => {
106
+ return (_jsxs("form", { onSubmit: form.handleSubmit(context.generateQRCode), noValidate: true, children: [_jsxs(Field.Root, { invalid: !!form.formState.errors.amount, className: "mt-3xl", children: [_jsx(Field.Label, { children: "Enter the amount you want to deposit" }), _jsx(Field.Input, { type: "number", ...form.register('amount') }), _jsx(Field.ErrorText, { children: form.formState.errors.amount?.message })] }), _jsx(AmountChoices, { value: parseDecimal(form.watch('amount'), 0), onChange: (value) => {
107
107
  form.setValue('amount', value.toString(), {
108
108
  shouldTouch: true,
109
109
  shouldDirty: true,
@@ -0,0 +1,7 @@
1
+ export interface IdleLogoutProps {
2
+ /**
3
+ * Idle timer in milliseconds before logout. Defaults to 15 minutes (900000 ms).
4
+ */
5
+ timer?: number;
6
+ }
7
+ export declare function IdleLogout({ timer }: IdleLogoutProps): null;
@@ -0,0 +1,6 @@
1
+ 'use client';
2
+ import { useIdleLogout } from '../../client/hooks/useIdleLogout.js';
3
+ export function IdleLogout({ timer }) {
4
+ useIdleLogout(timer);
5
+ return null;
6
+ }
@@ -268,8 +268,8 @@ export function SignUpDefaultForm() {
268
268
  }
269
269
  }, {
270
270
  until: (ok) => ok,
271
- maxAttempt: 5,
272
- interval: 300,
271
+ maxAttempt: 8,
272
+ interval: 250,
273
273
  });
274
274
  await pollUpdateAccount();
275
275
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opexa/portal-components",
3
- "version": "0.0.370",
3
+ "version": "0.0.372",
4
4
  "exports": {
5
5
  "./ui/*": {
6
6
  "types": "./dist/ui/*/index.d.ts",