diff --git a/src/web/components/sessionTimer/SessionTimer.jsx b/src/web/components/sessionTimer/SessionTimer.jsx new file mode 100644 index 0000000000..6af1f28fb0 --- /dev/null +++ b/src/web/components/sessionTimer/SessionTimer.jsx @@ -0,0 +1,54 @@ +import {useEffect, useState} from 'react'; + +import useUserSessionTimeout from 'web/utils/useUserSessionTimeout'; +import date from 'gmp/models/date'; +import {RefreshCcw} from 'lucide-react'; +import Divider from 'web/components/layout/divider'; +import {ActionIcon} from '@mantine/core'; +import useTranslation from 'web/hooks/useTranslation'; + +const SessionTimer = () => { + const [sessionTimeout, renewSession] = useUserSessionTimeout(); + const [timeLeft, setTimeLeft] = useState(''); + const [_] = useTranslation(); + + useEffect(() => { + const updateTimeLeft = () => { + if (!sessionTimeout) { + return
Session timer is currently unavailable.
; + } + const now = date(); + const duration = date.duration(sessionTimeout.diff(now)); + if (duration.asSeconds() <= 0) { + setTimeLeft('00:00'); + } else { + const formatted = + Math.floor(duration.asMinutes()) + + ':' + + ('0' + duration.seconds()).slice(-2); + setTimeLeft(formatted); + } + }; + + updateTimeLeft(); + const intervalId = setInterval(updateTimeLeft, 1000); + + return () => clearInterval(intervalId); + }, [sessionTimeout]); + + return ( + + {timeLeft} + + + + + ); +}; + +export default SessionTimer; diff --git a/src/web/components/structure/header.jsx b/src/web/components/structure/header.jsx index 8f8de43026..c56f272874 100644 --- a/src/web/components/structure/header.jsx +++ b/src/web/components/structure/header.jsx @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import React, {useCallback} from 'react'; +import {useCallback} from 'react'; import {useHistory} from 'react-router-dom'; @@ -30,6 +30,7 @@ import useGmp from 'web/utils/useGmp'; import LogoutIcon from 'web/components/icon/logouticon'; import MySettingsIcon from 'web/components/icon/mysettingsicon'; import LanguageSwitch from './languageswitch'; +import SessionTimer from '../sessionTimer/SessionTimer'; const Header = () => { const gmp = useGmp(); @@ -73,6 +74,7 @@ const Header = () => { languageSwitch={} menuPoints={menuPoints} isLoggedIn={loggedIn} + sessionTimer={} username={username} logoLink="/" /> diff --git a/src/web/utils/__tests__/useUserSessionTimeout.jsx b/src/web/utils/__tests__/useUserSessionTimeout.jsx index 9689be606f..34214a7fe9 100644 --- a/src/web/utils/__tests__/useUserSessionTimeout.jsx +++ b/src/web/utils/__tests__/useUserSessionTimeout.jsx @@ -22,16 +22,19 @@ import date from 'gmp/models/date'; import {setSessionTimeout as setSessionTimeoutAction} from 'web/store/usersettings/actions'; -import {rendererWith, fireEvent} from '../testing'; +import {rendererWith} from '../testing'; import useUserSessionTimeout from '../useUserSessionTimeout'; const TestUserSessionTimeout = () => { const [sessionTimeout, setSessionTimeout] = useUserSessionTimeout(); return ( - setSessionTimeout(date('2020-03-10'))}> + ); }; @@ -47,20 +50,4 @@ describe('useUserSessionTimeout tests', () => { expect(element).toHaveTextContent(/^10-10-19$/); }); - - test('should allow to set the users session timeout', () => { - const {render, store} = rendererWith({store: true}); - - const timeout = date('2019-10-10'); - - store.dispatch(setSessionTimeoutAction(timeout)); - - const {element} = render(); - - expect(element).toHaveTextContent(/^10-10-19$/); - - fireEvent.click(element); - - expect(element).toHaveTextContent(/^10-03-20$/); - }); }); diff --git a/src/web/utils/useUserSessionTimeout.jsx b/src/web/utils/useUserSessionTimeout.jsx index 761600e4a1..317fe4c063 100644 --- a/src/web/utils/useUserSessionTimeout.jsx +++ b/src/web/utils/useUserSessionTimeout.jsx @@ -19,13 +19,29 @@ import {useSelector, useDispatch} from 'react-redux'; import {getSessionTimeout} from 'web/store/usersettings/selectors'; import {setSessionTimeout} from 'web/store/usersettings/actions'; +import useGmp from 'web/utils/useGmp'; + +/** + * Custom hook to manage user session timeout. + * + * This hook provides the current session timeout, represented as a moment object, and a function to renew the session timeout through an API call. + * The `renewSessionAndUpdateTimeout` function makes an API call to renew the session and updates the session timeout based on the response, also represented as a moment object. + * This function does not require any parameters and will update the session timeout to the new value obtained from the API response. + * + * @returns {Array} An array containing the current `sessionTimeout` as a moment object and the `renewSessionAndUpdateTimeout` function. + */ const useUserSessionTimeout = () => { + const gmp = useGmp(); const dispatch = useDispatch(); - return [ - useSelector(getSessionTimeout), - timeout => dispatch(setSessionTimeout(timeout)), - ]; + const sessionTimeout = useSelector(getSessionTimeout); + + const renewSessionAndUpdateTimeout = async () => { + const response = await gmp.user.renewSession(); + dispatch(setSessionTimeout(response.data)); + }; + + return [sessionTimeout, renewSessionAndUpdateTimeout]; }; export default useUserSessionTimeout;