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:
parent
80561323a5
commit
15b370fa9f
@ -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();
|
||||
});
|
||||
|
76
web/satellite/src/components/modals/SessionExpiredModal.vue
Normal file
76
web/satellite/src/components/modals/SessionExpiredModal.vue
Normal 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, you’ve 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>
|
@ -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();
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user