UNPKG

@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
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, }; }