web/satellite: added new session expired modal

Added new modal for already expired session which is triggered after timeout instead of auto-redirecting to login page

Issue:
https://github.com/storj/storj/issues/5771

Change-Id: I8385ddfd9b8988c1d6130b6f0d19f1399a92d8fb
This commit is contained in:
Vitalii 2023-04-21 15:24:52 +03:00 committed by Storj Robot
parent 80561323a5
commit 15b370fa9f
4 changed files with 141 additions and 16 deletions

View File

@ -2,11 +2,11 @@
// See LICENSE for copying information.
<template>
<div ref="modal" class="mask" tabindex="0" @keydown.esc="onClose">
<div class="mask__wrapper" @click.self="onClose">
<div ref="modal" class="mask" tabindex="0" @keydown.esc="closeHandler">
<div class="mask__wrapper" @click.self="closeHandler">
<div class="mask__wrapper__container">
<slot name="content" />
<div class="mask__wrapper__container__close" @click="onClose">
<div v-if="isClosable" class="mask__wrapper__container__close" @click="closeHandler">
<CloseCrossIcon />
</div>
</div>
@ -21,10 +21,23 @@ import CloseCrossIcon from '@/../static/images/common/closeCross.svg';
const props = withDefaults(defineProps<{
onClose?: () => void;
}>(), { onClose: () => () => {} });
isClosable?: boolean;
}>(), {
onClose: () => () => {},
isClosable: true,
});
const modal = ref<HTMLElement>();
/**
* Holds on close modal logic.
*/
function closeHandler(): void {
if (props.isClosable) {
props.onClose();
}
}
onMounted((): void => {
modal.value?.focus();
});

View File

@ -0,0 +1,76 @@
// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<VModal :is-closable="false">
<template #content>
<div class="modal">
<div class="modal__header">
<Icon class="modal__header__icon" />
<h1 class="modal__header__title">Session Expired</h1>
</div>
<p class="modal__info">
To protect your account and data, youve been automatically logged out. You can change your session
timeout preferences in your account settings.
</p>
<VButton
label="Go to login"
width="100%"
height="40px"
font-size="14px"
border-radius="10px"
:on-press="onRedirect"
/>
</div>
</template>
</VModal>
</template>
<script setup lang="ts">
import VButton from '@/components/common/VButton.vue';
import VModal from '@/components/common/VModal.vue';
import Icon from '@/../static/images/session/inactivityTimer.svg';
const props = defineProps<{
onRedirect: () => void;
}>();
</script>
<style scoped lang="scss">
.modal {
max-width: 410px;
padding: 32px;
box-sizing: border-box;
font-family: 'font_regular', sans-serif;
&__header {
display: flex;
align-items: center;
margin-bottom: 32px;
&__icon {
margin-right: 16px;
min-width: 40px;
width: 40px;
height: 40px;
}
&__title {
font-family: 'font_bold', sans-serif;
font-size: 24px;
line-height: 31px;
letter-spacing: -0.02em;
color: var(--c-black);
}
}
&__info {
font-size: 16px;
line-height: 24px;
color: var(--c-black);
margin-bottom: 40px;
text-align: left;
}
}
</style>

View File

@ -115,7 +115,7 @@
:on-upgrade="togglePMModal"
/>
<AllModals />
<!-- IMPORTANT! Make sure this modal is positioned as the last element here so that it is shown on top of everything else -->
<!-- IMPORTANT! Make sure these 2 modals are positioned as the last elements here so that they are shown on top of everything else -->
<InactivityModal
v-if="inactivityModalShown"
:on-continue="refreshSession"
@ -123,6 +123,7 @@
:on-close="closeInactivityModal"
:initial-seconds="inactivityModalTime / 1000"
/>
<SessionExpiredModal v-if="sessionExpiredModalShown" :on-redirect="redirectToLogin" />
</div>
</template>
@ -155,6 +156,7 @@ import { useObjectBrowserStore } from '@/store/modules/objectBrowserStore';
import UploadNotification from '@/components/notifications/UploadNotification.vue';
import NavigationArea from '@/components/navigation/NavigationArea.vue';
import InactivityModal from '@/components/modals/InactivityModal.vue';
import SessionExpiredModal from '@/components/modals/SessionExpiredModal.vue';
import BetaSatBar from '@/components/infoBars/BetaSatBar.vue';
import MFARecoveryCodeBar from '@/components/infoBars/MFARecoveryCodeBar.vue';
import AllModals from '@/components/modals/AllModals.vue';
@ -195,6 +197,7 @@ const inactivityTimerId = ref<ReturnType<typeof setTimeout> | null>();
const sessionRefreshTimerId = ref<ReturnType<typeof setTimeout> | null>();
const debugTimerId = ref<ReturnType<typeof setTimeout> | null>();
const inactivityModalShown = ref<boolean>(false);
const sessionExpiredModalShown = ref<boolean>(false);
const isSessionActive = ref<boolean>(false);
const isSessionRefreshing = ref<boolean>(false);
const isHundredLimitModalShown = ref<boolean>(false);
@ -503,8 +506,8 @@ function restartSessionTimers(): void {
if (isSessionActive.value) return;
inactivityModalShown.value = true;
inactivityTimerId.value = setTimeout(async () => {
await handleInactive();
await notify.notify('Your session was timed out.');
await clearStoreAndTimers();
notify.notify('Your session was timed out.');
}, inactivityModalTime);
}, sessionDuration.value - inactivityModalTime);
@ -569,12 +572,19 @@ async function refreshSession(): Promise<void> {
}
/**
* Performs logout and cleans event listeners and session timers.
* Redirects to log in screen.
*/
async function handleInactive(): Promise<void> {
await analytics.pageVisit(RouteConfig.Login.path);
await router.push(RouteConfig.Login.path);
function redirectToLogin(): void {
analytics.pageVisit(RouteConfig.Login.path);
router.push(RouteConfig.Login.path);
sessionExpiredModalShown.value = false;
}
/**
* Clears pinia stores and timers.
*/
async function clearStoreAndTimers(): Promise<void> {
await Promise.all([
pmStore.clear(),
projectsStore.clear(),
@ -594,6 +604,14 @@ async function handleInactive(): Promise<void> {
});
clearSessionTimers();
inactivityModalShown.value = false;
sessionExpiredModalShown.value = true;
}
/**
* Performs logout and cleans event listeners and session timers.
*/
async function handleInactive(): Promise<void> {
await clearStoreAndTimers();
try {
await auth.logout();

View File

@ -109,6 +109,7 @@
:on-close="closeInactivityModal"
:initial-seconds="inactivityModalTime / 1000"
/>
<SessionExpiredModal v-if="sessionExpiredModalShown" :on-redirect="redirectToLogin" />
</div>
</template>
@ -141,6 +142,7 @@ import { useNotificationsStore } from '@/store/modules/notificationsStore';
import { useObjectBrowserStore } from '@/store/modules/objectBrowserStore';
import InactivityModal from '@/components/modals/InactivityModal.vue';
import SessionExpiredModal from '@/components/modals/SessionExpiredModal.vue';
import BetaSatBar from '@/components/infoBars/BetaSatBar.vue';
import MFARecoveryCodeBar from '@/components/infoBars/MFARecoveryCodeBar.vue';
import AllModals from '@/components/modals/AllModals.vue';
@ -179,6 +181,7 @@ const debugTimerId = ref<ReturnType<typeof setTimeout> | null>(null);
const debugTimerText = ref<string>('');
const resetActivityEvents: string[] = ['keypress', 'mousemove', 'mousedown', 'touchmove'];
const inactivityModalShown = ref<boolean>(false);
const sessionExpiredModalShown = ref<boolean>(false);
const isSessionActive = ref<boolean>(false);
const isSessionRefreshing = ref<boolean>(false);
const isHundredLimitModalShown = ref<boolean>(false);
@ -371,12 +374,19 @@ async function redirectToBillingPage(): Promise<void> {
}
/**
* Performs logout and cleans event listeners and session timers.
* Redirects to log in screen.
*/
async function handleInactive(): Promise<void> {
await analytics.pageVisit(RouteConfig.Login.path);
await router.push(RouteConfig.Login.path);
function redirectToLogin(): void {
analytics.pageVisit(RouteConfig.Login.path);
router.push(RouteConfig.Login.path);
sessionExpiredModalShown.value = false;
}
/**
* Clears pinia stores and timers.
*/
async function clearStoreAndTimers(): Promise<void> {
await Promise.all([
pmStore.clear(),
projectsStore.clear(),
@ -396,6 +406,14 @@ async function handleInactive(): Promise<void> {
});
clearSessionTimers();
inactivityModalShown.value = false;
sessionExpiredModalShown.value = true;
}
/**
* Performs logout and cleans event listeners and session timers.
*/
async function handleInactive(): Promise<void> {
await clearStoreAndTimers();
try {
await auth.logout();
@ -491,7 +509,7 @@ function restartSessionTimers(): void {
if (isSessionActive.value) return;
inactivityModalShown.value = true;
inactivityTimerId.value = setTimeout(async () => {
await handleInactive();
await clearStoreAndTimers();
await notify.notify('Your session was timed out.');
}, inactivityModalTime);
}, sessionDuration.value - inactivityModalTime);