@pagamio/frontend-commons-lib
Version:
Pagamio library for Frontend reusable components like the form engine and table container
97 lines (96 loc) • 3.85 kB
JavaScript
import { useCallback, useEffect, useRef, useState } from 'react';
import { useAuth } from '../../auth';
/**
* Hook to manage session expiration and refresh logic.
* Tracks the session's remaining time and provides functionality to refresh the session or handle expiration.
*
* @param options - Configuration options for the session timer.
* @param options.onSessionExpired - Callback invoked when the session expires.
* @param options.onSessionRefreshed - Callback invoked when the session is successfully refreshed.
* @param options.onRefreshError - Callback invoked when an error occurs during session refresh.
* @param options.expiryThreshold - Time in milliseconds before session expiry to show the modal (default: 60000ms or 60s).
*
* @returns An object containing:
* - `showModal`: Boolean indicating whether the session expiry modal should be shown.
* - `countdown`: The remaining time in seconds before session expiry.
* - `loading`: Boolean indicating whether a session refresh is in progress.
* - `modalDismissed`: Boolean indicating whether the modal has been dismissed.
* - `handleCloseModal`: Function to close the session expiry modal.
* - `handleRefreshToken`: Function to refresh the session token.
*/
export function useSessionTimer({ onSessionExpired, onSessionRefreshed, onRefreshError, expiryThreshold = 60000, } = {}) {
const { logout, authService } = useAuth();
const [showModal, setShowModal] = useState(false);
const [modalDismissed, setModalDismissed] = useState(false);
const [countdown, setCountdown] = useState(60);
const [loading, setLoading] = useState(false);
const intervalRef = useRef(null);
useEffect(() => {
const expiresAt = authService.getAccessTokenExpiry();
if (!expiresAt)
return;
intervalRef.current = setInterval(() => {
const timeRemaining = expiresAt - Date.now();
if (timeRemaining <= 0) {
setModalDismissed(true);
setShowModal(false);
logout();
onSessionExpired?.();
return;
}
if (timeRemaining <= expiryThreshold) {
if (!modalDismissed) {
setShowModal(true);
setCountdown(Math.ceil(timeRemaining / 1000));
}
}
else {
setShowModal(false);
}
}, 1000);
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, [authService, logout, modalDismissed, expiryThreshold, onSessionExpired]);
/**
* Closes the session expiry modal and marks it as dismissed.
*/
const handleCloseModal = useCallback(() => {
setShowModal(false);
setModalDismissed(true);
}, []);
/**
* Refreshes the session token.
* Handles success and error cases, and updates the loading state.
*/
const handleRefreshToken = useCallback(async () => {
try {
setLoading(true);
handleCloseModal();
const success = await authService.refreshTokens();
if (success) {
onSessionRefreshed?.();
}
else {
throw new Error('Failed to refresh session');
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Error refreshing session';
onRefreshError?.(new Error(errorMessage));
}
finally {
setLoading(false);
}
}, [authService, handleCloseModal, onSessionRefreshed, onRefreshError]);
return {
showModal,
countdown,
loading,
modalDismissed,
handleCloseModal,
handleRefreshToken,
};
}