web/satellite: added update your session timeout banner
Added new banner to inform user that they can update their session timeout now. Issue: https://github.com/storj/storj/issues/5772 Change-Id: Icdf2164b80b12954d004537a4f31d30ef6bb12b8
This commit is contained in:
parent
98562d06c8
commit
3f1166b5aa
@ -83,8 +83,11 @@ watch(() => props.dashboardRef, () => {
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 7px 20px rgba(0 0 0 / 15%);
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
margin: 0 1.5rem;
|
||||
@media screen and (max-width: 450px) {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
row-gap: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
@ -123,6 +126,7 @@ watch(() => props.dashboardRef, () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
&__close {
|
||||
@ -130,6 +134,13 @@ watch(() => props.dashboardRef, () => {
|
||||
height: 15px;
|
||||
margin-left: 2.375rem;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
|
||||
@media screen and (max-width: 450px) {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,11 +157,4 @@ watch(() => props.dashboardRef, () => {
|
||||
text-decoration: underline !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
|
||||
.notification-wrap {
|
||||
right: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -0,0 +1,56 @@
|
||||
// Copyright (C) 2023 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<v-banner
|
||||
severity="info"
|
||||
:dashboard-ref="dashboardRef"
|
||||
:on-close="onCloseClick"
|
||||
>
|
||||
<template #text>
|
||||
<p class="medium">
|
||||
You can now update your session timeout from your
|
||||
<span class="link" @click.stop.self="redirectToSettingsPage">account settings</span>
|
||||
</p>
|
||||
</template>
|
||||
</v-banner>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive } from 'vue';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
import { useRouter } from '@/utils/hooks';
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
|
||||
import VBanner from '@/components/common/VBanner.vue';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const nativeRouter = useRouter();
|
||||
const router = reactive(nativeRouter);
|
||||
|
||||
const props = defineProps<{
|
||||
dashboardRef: HTMLElement
|
||||
}>();
|
||||
|
||||
/**
|
||||
* Redirects to settings page.
|
||||
*/
|
||||
function redirectToSettingsPage(): void {
|
||||
onCloseClick();
|
||||
|
||||
if (router.currentRoute.path.includes(RouteConfig.AllProjectsDashboard.path)) {
|
||||
router.push(RouteConfig.AccountSettings.with(RouteConfig.Settings2).path);
|
||||
return;
|
||||
}
|
||||
|
||||
router.push(RouteConfig.Account.with(RouteConfig.Settings).path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes notification.
|
||||
*/
|
||||
function onCloseClick(): void {
|
||||
appStore.closeUpdateSessionTimeoutBanner();
|
||||
}
|
||||
</script>
|
@ -455,6 +455,7 @@ onBeforeUnmount((): void => {
|
||||
<style scoped lang="scss">
|
||||
.project-dashboard {
|
||||
max-width: calc(100vw - 280px - 95px);
|
||||
background-origin: content-box;
|
||||
background-image: url('../../../../static/images/project/background.png');
|
||||
background-position: top right;
|
||||
background-size: 70%;
|
||||
|
@ -7,10 +7,12 @@ import { defineStore } from 'pinia';
|
||||
import { OnboardingOS, PricingPlanInfo } from '@/types/common';
|
||||
import { FetchState } from '@/utils/constants/fetchStateEnum';
|
||||
import { ManageProjectPassphraseStep } from '@/types/managePassphrase';
|
||||
import { LocalData } from '@/utils/localData';
|
||||
|
||||
class AppState {
|
||||
public fetchState = FetchState.LOADING;
|
||||
public isSuccessfulPasswordResetShown = false;
|
||||
public isUpdateSessionTimeoutBanner = !LocalData.getSessionTimeoutBannerAcknowledged();
|
||||
public hasJustLoggedIn = false;
|
||||
public onbAGStepBackRoute = '';
|
||||
public onbAPIKeyStepBackRoute = '';
|
||||
@ -125,6 +127,12 @@ export const useAppStore = defineStore('app', () => {
|
||||
state.isLargeUploadNotificationShown = value;
|
||||
}
|
||||
|
||||
function closeUpdateSessionTimeoutBanner(): void {
|
||||
LocalData.setSessionTimeoutBannerAcknowledged();
|
||||
|
||||
state.isUpdateSessionTimeoutBanner = false;
|
||||
}
|
||||
|
||||
function closeDropdowns(): void {
|
||||
state.activeDropdown = '';
|
||||
}
|
||||
@ -174,6 +182,7 @@ export const useAppStore = defineStore('app', () => {
|
||||
setLargeUploadWarningNotification,
|
||||
setLargeUploadNotification,
|
||||
closeDropdowns,
|
||||
closeUpdateSessionTimeoutBanner,
|
||||
setErrorPage,
|
||||
removeErrorPage,
|
||||
clear,
|
||||
|
@ -9,6 +9,7 @@ export class LocalData {
|
||||
private static bucketWasCreated = 'bucketWasCreated';
|
||||
private static demoBucketCreated = 'demoBucketCreated';
|
||||
private static bucketGuideHidden = 'bucketGuideHidden';
|
||||
private static sessionTimeoutBannerAcknowledged = 'sessionTimeoutBannerAcknowledged';
|
||||
private static serverSideEncryptionBannerHidden = 'serverSideEncryptionBannerHidden';
|
||||
private static serverSideEncryptionModalHidden = 'serverSideEncryptionModalHidden';
|
||||
private static largeUploadNotificationDismissed = 'largeUploadNotificationDismissed';
|
||||
@ -61,6 +62,14 @@ export class LocalData {
|
||||
return value === 'true';
|
||||
}
|
||||
|
||||
public static getSessionTimeoutBannerAcknowledged(): boolean {
|
||||
return Boolean(localStorage.getItem(LocalData.sessionTimeoutBannerAcknowledged));
|
||||
}
|
||||
|
||||
public static setSessionTimeoutBannerAcknowledged(): void {
|
||||
localStorage.setItem(LocalData.sessionTimeoutBannerAcknowledged, 'true');
|
||||
}
|
||||
|
||||
/**
|
||||
* "Disable" showing the server-side encryption banner on the bucket page
|
||||
*/
|
||||
|
@ -16,6 +16,11 @@
|
||||
<BetaSatBar v-if="isBetaSatellite" />
|
||||
<MFARecoveryCodeBar v-if="showMFARecoveryCodeBar" :open-generate-modal="generateNewMFARecoveryCodes" />
|
||||
<div class="banner-container dashboard__wrap__main-area__content-wrap__container__content">
|
||||
<UpdateSessionTimeoutBanner
|
||||
v-if="isUpdateSessionTimeoutBanner && dashboardContent"
|
||||
:dashboard-ref="dashboardContent"
|
||||
/>
|
||||
|
||||
<UpgradeNotification
|
||||
v-if="isPaidTierBannerShown"
|
||||
:open-add-p-m-modal="togglePMModal"
|
||||
@ -167,6 +172,7 @@ import VBanner from '@/components/common/VBanner.vue';
|
||||
import UpgradeNotification from '@/components/notifications/UpgradeNotification.vue';
|
||||
import ProjectLimitBanner from '@/components/notifications/ProjectLimitBanner.vue';
|
||||
import BrandedLoader from '@/components/common/BrandedLoader.vue';
|
||||
import UpdateSessionTimeoutBanner from '@/components/notifications/UpdateSessionTimeoutBanner.vue';
|
||||
|
||||
import CloudIcon from '@/../static/images/notifications/cloudAlert.svg';
|
||||
import WarningIcon from '@/../static/images/notifications/circleWarning.svg';
|
||||
@ -226,6 +232,13 @@ const sessionRefreshInterval = computed((): number => {
|
||||
return sessionDuration.value / 2;
|
||||
});
|
||||
|
||||
/**
|
||||
* Indicates whether the update session timeout notification should be shown.
|
||||
*/
|
||||
const isUpdateSessionTimeoutBanner = computed((): boolean => {
|
||||
return router.currentRoute.name !== RouteConfig.Settings.name && appStore.state.isUpdateSessionTimeoutBanner;
|
||||
});
|
||||
|
||||
/**
|
||||
* Indicates whether to display the session timer for debugging.
|
||||
*/
|
||||
@ -713,10 +726,17 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
try {
|
||||
await usersStore.getUser();
|
||||
await usersStore.getFrozenStatus();
|
||||
await abTestingStore.fetchValues();
|
||||
await usersStore.getSettings();
|
||||
await Promise.all([
|
||||
usersStore.getUser(),
|
||||
usersStore.getFrozenStatus(),
|
||||
abTestingStore.fetchValues(),
|
||||
usersStore.getSettings(),
|
||||
]);
|
||||
|
||||
if (usersStore.state.settings.sessionDuration && appStore.state.isUpdateSessionTimeoutBanner) {
|
||||
appStore.closeUpdateSessionTimeoutBanner();
|
||||
}
|
||||
|
||||
setupSessionTimers();
|
||||
} catch (error) {
|
||||
if (!(error instanceof ErrorUnauthorized)) {
|
||||
@ -898,6 +918,10 @@ onBeforeUnmount(() => {
|
||||
.dashboard__wrap__main-area__content-wrap__container__content {
|
||||
padding: 32px 24px 50px;
|
||||
}
|
||||
|
||||
.banner-container {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
|
@ -18,6 +18,11 @@
|
||||
<div class="all-dashboard__content__divider" />
|
||||
|
||||
<div class="all-dashboard__banners">
|
||||
<UpdateSessionTimeoutBanner
|
||||
v-if="isUpdateSessionTimeoutBanner && dashboardContent"
|
||||
:dashboard-ref="dashboardContent"
|
||||
/>
|
||||
|
||||
<UpgradeNotification
|
||||
v-if="isPaidTierBannerShown"
|
||||
class="all-dashboard__banners__upgrade"
|
||||
@ -151,6 +156,7 @@ import LimitWarningModal from '@/components/modals/LimitWarningModal.vue';
|
||||
import VBanner from '@/components/common/VBanner.vue';
|
||||
import UpgradeNotification from '@/components/notifications/UpgradeNotification.vue';
|
||||
import ProjectLimitBanner from '@/components/notifications/ProjectLimitBanner.vue';
|
||||
import UpdateSessionTimeoutBanner from '@/components/notifications/UpdateSessionTimeoutBanner.vue';
|
||||
|
||||
import LoaderImage from '@/../static/images/common/loadIcon.svg';
|
||||
|
||||
@ -209,6 +215,13 @@ const sessionRefreshInterval = computed((): number => {
|
||||
return sessionDuration.value / 2;
|
||||
});
|
||||
|
||||
/**
|
||||
* Indicates whether the update session timeout notification should be shown.
|
||||
*/
|
||||
const isUpdateSessionTimeoutBanner = computed((): boolean => {
|
||||
return router.currentRoute.name !== RouteConfig.Settings2.name && appStore.state.isUpdateSessionTimeoutBanner;
|
||||
});
|
||||
|
||||
/**
|
||||
* Indicates whether to display the session timer for debugging.
|
||||
*/
|
||||
@ -427,7 +440,7 @@ async function handleInactive(): Promise<void> {
|
||||
} catch (error) {
|
||||
if (error instanceof ErrorUnauthorized) return;
|
||||
|
||||
await notify.error(error.message, AnalyticsErrorEventSource.OVERALL_SESSION_EXPIRED_ERROR);
|
||||
notify.error(error.message, AnalyticsErrorEventSource.OVERALL_SESSION_EXPIRED_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@ -439,7 +452,7 @@ async function generateNewMFARecoveryCodes(): Promise<void> {
|
||||
await usersStore.generateUserMFARecoveryCodes();
|
||||
toggleMFARecoveryModal();
|
||||
} catch (error) {
|
||||
await notify.error(error.message, AnalyticsErrorEventSource.ALL_PROJECT_DASHBOARD);
|
||||
notify.error(error.message, AnalyticsErrorEventSource.ALL_PROJECT_DASHBOARD);
|
||||
}
|
||||
}
|
||||
|
||||
@ -520,7 +533,7 @@ function restartSessionTimers(): void {
|
||||
inactivityModalShown.value = true;
|
||||
inactivityTimerId.value = setTimeout(async () => {
|
||||
await clearStoreAndTimers();
|
||||
await notify.notify('Your session was timed out.');
|
||||
notify.notify('Your session was timed out.');
|
||||
}, inactivityModalTime);
|
||||
}, sessionDuration.value - inactivityModalTime);
|
||||
|
||||
@ -553,7 +566,7 @@ async function refreshSession(): Promise<void> {
|
||||
try {
|
||||
LocalData.setSessionExpirationDate(await auth.refreshSession());
|
||||
} catch (error) {
|
||||
await notify.error((error instanceof ErrorUnauthorized) ? 'Your session was timed out.' : error.message, AnalyticsErrorEventSource.ALL_PROJECT_DASHBOARD);
|
||||
notify.error((error instanceof ErrorUnauthorized) ? 'Your session was timed out.' : error.message, AnalyticsErrorEventSource.ALL_PROJECT_DASHBOARD);
|
||||
await handleInactive();
|
||||
isSessionRefreshing.value = false;
|
||||
return;
|
||||
@ -594,10 +607,17 @@ onMounted(async () => {
|
||||
});
|
||||
|
||||
try {
|
||||
await usersStore.getUser();
|
||||
await usersStore.getFrozenStatus();
|
||||
await abTestingStore.fetchValues();
|
||||
await usersStore.getSettings();
|
||||
await Promise.all([
|
||||
usersStore.getUser(),
|
||||
usersStore.getFrozenStatus(),
|
||||
abTestingStore.fetchValues(),
|
||||
usersStore.getSettings(),
|
||||
]);
|
||||
|
||||
if (usersStore.state.settings.sessionDuration && appStore.state.isUpdateSessionTimeoutBanner) {
|
||||
appStore.closeUpdateSessionTimeoutBanner();
|
||||
}
|
||||
|
||||
setupSessionTimers();
|
||||
} catch (error) {
|
||||
if (!(error instanceof ErrorUnauthorized)) {
|
||||
@ -614,26 +634,26 @@ onMounted(async () => {
|
||||
agStore.stopWorker();
|
||||
await agStore.startWorker();
|
||||
} catch (error) {
|
||||
await notify.error(`Unable to set access grants wizard. ${error.message}`, AnalyticsErrorEventSource.ALL_PROJECT_DASHBOARD);
|
||||
notify.error(`Unable to set access grants wizard. ${error.message}`, AnalyticsErrorEventSource.ALL_PROJECT_DASHBOARD);
|
||||
}
|
||||
|
||||
try {
|
||||
const couponType = await billingStore.setupAccount();
|
||||
if (couponType === CouponType.NoCoupon) {
|
||||
await notify.error(`The coupon code was invalid, and could not be applied to your account`, AnalyticsErrorEventSource.ALL_PROJECT_DASHBOARD);
|
||||
notify.error(`The coupon code was invalid, and could not be applied to your account`, AnalyticsErrorEventSource.ALL_PROJECT_DASHBOARD);
|
||||
}
|
||||
|
||||
if (couponType === CouponType.SignupCoupon) {
|
||||
await notify.success(`The coupon code was added successfully`);
|
||||
notify.success(`The coupon code was added successfully`);
|
||||
}
|
||||
} catch (error) {
|
||||
await notify.error(`Unable to setup account. ${error.message}`, AnalyticsErrorEventSource.ALL_PROJECT_DASHBOARD);
|
||||
notify.error(`Unable to setup account. ${error.message}`, AnalyticsErrorEventSource.ALL_PROJECT_DASHBOARD);
|
||||
}
|
||||
|
||||
try {
|
||||
await billingStore.getCreditCards();
|
||||
} catch (error) {
|
||||
await notify.error(`Unable to get credit cards. ${error.message}`, AnalyticsErrorEventSource.ALL_PROJECT_DASHBOARD);
|
||||
notify.error(`Unable to get credit cards. ${error.message}`, AnalyticsErrorEventSource.ALL_PROJECT_DASHBOARD);
|
||||
}
|
||||
|
||||
try {
|
||||
@ -718,15 +738,6 @@ onBeforeUnmount(() => {
|
||||
&__banners {
|
||||
margin-bottom: 20px;
|
||||
|
||||
&__billing {
|
||||
position: initial;
|
||||
margin-top: 20px;
|
||||
|
||||
& :deep(.notification-wrap__content) {
|
||||
position: initial;
|
||||
}
|
||||
}
|
||||
|
||||
&__upgrade,
|
||||
&__project-limit,
|
||||
&__freeze,
|
||||
|
Loading…
Reference in New Issue
Block a user