import React, { Fragment, useEffect, useRef, useState } from 'react' import { Dialog, Transition } from '@headlessui/react' import PropTypes from 'prop-types' import useHasMounted from '@/hooks/useHasMounted' export default function SessionTimeout ({ i18n, user, onTimeout, onCancelTimeout }) { const TIME = 30 const hasMounted = useHasMounted() const countTimerRef = useRef() const [tick, setTick] = useState(0) const [countTimer, setCountTimer] = useState() // contador que lleva el control de tiempo en segundos para mostrar antes de cerrar sesion const [timerIsOn, setTimerIsOn] = useState(false) // verifica si el dialogo debe ser mostrado const idleTimer = useRef(null) // variable de control para el proceso de conteo // realiza el conteo regresivo const timedCount = () => { if (countTimerRef.current <= 0) { clearInterval(idleTimer.current) setTimerIsOn(false) setCountTimer(TIME) onTimeout() return } setCountTimer(countTimerRef.current - 1) } // inicia el conteo regresivo const startIdleMonitor = (expiracion = 0) => { if (expiracion < TIME * 1000) { countTimerRef.current = Math.round(expiracion / 1000) // tiempo restante } else { countTimerRef.current = TIME } setCountTimer(countTimerRef.current) setTimerIsOn(true) timedCount() idleTimer.current = setInterval(timedCount, 1000) } const calendarizeIdle = () => { // const fecha_inicio_sesion = new Date(user.fecha_inicio_sesion.slice(0, -1)) // uso de localtime quita Z al final del string const fecha_fin_sesion = new Date(user?.fecha_fin_sesion?.slice(0, -1)) // uso de localtime quita Z al final del string // const fecha_fin_sesion = new Date(user.fecha_fin_sesion) const expiracion = Math.round(fecha_fin_sesion.getTime() - (new Date()).getTime()) // valida cuando se realiza un F5 o reload del navegador (user.tiempo_expiracion * 60 * 1000) if (expiracion <= 0) { return // no debe calendarizar porque la sesion ya vencio } const timeInMillis = expiracion - (TIME * 1000) const processTimer = setTimeout(startIdleMonitor, timeInMillis > 0 ? timeInMillis : 0, expiracion) return () => clearTimeout(processTimer) } // cancela el conteo regresivo aumentando el tiempo de expiracion const stopIdleMonitor = async () => { await onCancelTimeout() clearInterval(idleTimer.current) setTimerIsOn(false) setCountTimer(TIME) // force rerender to update view setTick((tick) => tick + 1) // await new Promise(resolve => setTimeout(resolve, 2000)) // espera obligada para actualizacion DB } useEffect(() => { if (timerIsOn === false && tick > 0) { return calendarizeIdle() } }, [timerIsOn, tick]) useEffect(() => { countTimerRef.current = countTimer }, [countTimer]) useEffect(() => { if (!user || user === null) { if (idleTimer && idleTimer.current) { clearInterval(idleTimer.current) } } return () => clearInterval(idleTimer.current) }, [user]) useEffect(() => { if (hasMounted) { return calendarizeIdle() } // eslint-disable-next-line react-hooks/exhaustive-deps }, [hasMounted]) return ( <> { timerIsOn && timerIsOn === true && { }}>
{i18n.t('common.sessionToFinish')}

{countTimer}

} ) } SessionTimeout.propTypes = { i18n: PropTypes.object, user: PropTypes.object, onTimeout: PropTypes.func, onCancelTimeout: PropTypes.func } SessionTimeout.defaultProps = { i18n: { t: () => { return 'txtNone' } }, user: {}, onTimeout: () => {}, onCancelTimeout: () => {} }