web/satellite: update session timeout modals
This change opens up the "set session timeout" modal for users to set a custom timeout duration if they haven't already. It also fixes a few UI/UX issues on the modal including toggling on the dashboard. Issue: https://github.com/storj/storj/issues/5770 Change-Id: I0e71e191049b242e638ca36214d6dd33f78ae5fe
This commit is contained in:
parent
e0542c2d24
commit
034431e4a8
@ -2,7 +2,7 @@
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<VModal :on-close="withLoading(onClose)">
|
||||
<VModal :on-close="() => withLoading(onClose)">
|
||||
<template #content>
|
||||
<div class="timeout-modal">
|
||||
<div class="timeout-modal__header">
|
||||
@ -32,7 +32,7 @@
|
||||
font-size="13px"
|
||||
is-white
|
||||
class="timeout-modal__buttons__button"
|
||||
:on-press="withLoading(onClose)"
|
||||
:on-press="() => withLoading(onClose)"
|
||||
:is-disabled="isLoading"
|
||||
/>
|
||||
<VButton
|
||||
@ -42,7 +42,7 @@
|
||||
border-radius="10px"
|
||||
font-size="13px"
|
||||
class="timeout-modal__buttons__button save"
|
||||
:on-press="withLoading(save)"
|
||||
:on-press="() => withLoading(save)"
|
||||
:is-disabled="isLoading || !hasChanged"
|
||||
/>
|
||||
</div>
|
||||
@ -54,11 +54,13 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { useNotify, useRouter } from '@/utils/hooks';
|
||||
import { Duration } from '@/utils/time';
|
||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||
import { useUsersStore } from '@/store/modules/usersStore';
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
import { useLoading } from '@/composables/useLoading';
|
||||
import { RouteConfig } from '@/router';
|
||||
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import VModal from '@/components/common/VModal.vue';
|
||||
@ -69,8 +71,9 @@ import Icon from '@/../static/images/session/inactivityTimer.svg';
|
||||
const appStore = useAppStore();
|
||||
const usersStore = useUsersStore();
|
||||
const notify = useNotify();
|
||||
const router = useRouter();
|
||||
const { isLoading, withLoading } = useLoading();
|
||||
|
||||
const isLoading = ref(false);
|
||||
const sessionDuration = ref<Duration | null>(null);
|
||||
|
||||
/**
|
||||
@ -128,18 +131,6 @@ async function save() {
|
||||
function onClose(): void {
|
||||
appStore.removeActiveModal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a function that disables modal interaction during execution.
|
||||
*/
|
||||
function withLoading(fn: () => Promise<void>): () => Promise<void> {
|
||||
return async () => {
|
||||
if (isLoading.value) return;
|
||||
isLoading.value = true;
|
||||
await fn();
|
||||
isLoading.value = false;
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@ -153,7 +144,7 @@ function withLoading(fn: () => Promise<void>): () => Promise<void> {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
margin: 20px 0;
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
flex-direction: column;
|
||||
@ -161,6 +152,11 @@ function withLoading(fn: () => Promise<void>): () => Promise<void> {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 28px;
|
||||
|
@ -3,15 +3,21 @@
|
||||
|
||||
<template>
|
||||
<div class="selector">
|
||||
<div v-click-outside="closeSelector" tabindex="0" class="selector__content" @keyup.enter="toggleSelector" @click="toggleSelector">
|
||||
<div tabindex="0" class="selector__content" @keyup.enter="toggleSelector" @click.stop="toggleSelector">
|
||||
<span v-if="selected" class="selector__content__label">{{ selected?.shortString }}</span>
|
||||
<span v-else class="selector__content__label">Select duration</span>
|
||||
<arrow-down-icon class="selector__content__arrow" :class="{ open: isOpen }" />
|
||||
</div>
|
||||
<div v-if="isOpen" class="selector__dropdown">
|
||||
<div
|
||||
v-if="isOpen"
|
||||
v-click-outside="closeSelector"
|
||||
tabindex="0"
|
||||
class="selector__dropdown"
|
||||
>
|
||||
<div
|
||||
v-for="(option, index) in options"
|
||||
:key="index" tabindex="0"
|
||||
:key="index"
|
||||
tabindex="0"
|
||||
class="selector__dropdown__item"
|
||||
:class="{ selected: isSelected(option) }"
|
||||
@click.stop="() => select(option)"
|
||||
|
@ -9,6 +9,14 @@
|
||||
</div>
|
||||
<div class="notification-wrap__content-area__message-area">
|
||||
<p class="notification-wrap__content-area__message">{{ notification.message }}</p>
|
||||
|
||||
<p v-if="isTimeoutMentioned && notOnSettingsPage" class="notification-wrap__content-area__account-msg">
|
||||
To change this go to your
|
||||
<router-link :to="settingsRoute" class="notification-wrap__content-area__account-msg__link">
|
||||
account settings
|
||||
</router-link>
|
||||
</p>
|
||||
|
||||
<a
|
||||
v-if="isSupportLinkMentioned"
|
||||
:href="requestURL"
|
||||
@ -28,16 +36,20 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
|
||||
import { DelayedNotification } from '@/types/DelayedNotification';
|
||||
import { useNotificationsStore } from '@/store/modules/notificationsStore';
|
||||
import { useConfigStore } from '@/store/modules/configStore';
|
||||
import { RouteConfig } from '@/router';
|
||||
import { useRouter } from '@/utils/hooks';
|
||||
|
||||
import CloseIcon from '@/../static/images/notifications/close.svg';
|
||||
|
||||
const configStore = useConfigStore();
|
||||
const notificationsStore = useNotificationsStore();
|
||||
const nativeRouter = useRouter();
|
||||
const router = reactive(nativeRouter);
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
notification: DelayedNotification;
|
||||
@ -47,6 +59,20 @@ const props = withDefaults(defineProps<{
|
||||
|
||||
const isClassActive = ref<boolean>(false);
|
||||
|
||||
/**
|
||||
* Returns the correct settings route based on if we're on all projects dashboard.
|
||||
*/
|
||||
const settingsRoute = computed((): string => {
|
||||
if (
|
||||
router.currentRoute.path.includes(RouteConfig.AllProjectsDashboard.path)
|
||||
|| router.currentRoute.path.includes(RouteConfig.AccountSettings.path)
|
||||
) {
|
||||
return RouteConfig.AccountSettings.with(RouteConfig.Settings2).path;
|
||||
}
|
||||
|
||||
return RouteConfig.Account.with(RouteConfig.Settings).path;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns the URL for the general request page from the store.
|
||||
*/
|
||||
@ -54,6 +80,22 @@ const requestURL = computed((): string => {
|
||||
return configStore.state.config.generalRequestURL;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns whether we are not on a settings page.
|
||||
*/
|
||||
const notOnSettingsPage = computed((): boolean => {
|
||||
return router.currentRoute.name !== RouteConfig.Settings.name
|
||||
&& router.currentRoute.name !== RouteConfig.Settings2.name;
|
||||
});
|
||||
|
||||
/**
|
||||
* Indicates if session timeout is mentioned in message.
|
||||
* Temporal solution, can be changed later.
|
||||
*/
|
||||
const isTimeoutMentioned = computed((): boolean => {
|
||||
return props.notification.message.toLowerCase().includes('session timeout');
|
||||
});
|
||||
|
||||
/**
|
||||
* Indicates if support word is mentioned in message.
|
||||
* Temporal solution, can be changed later.
|
||||
@ -139,6 +181,17 @@ onMounted((): void => {
|
||||
cursor: pointer;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
&__account-msg {
|
||||
margin-top: 20px;
|
||||
|
||||
&__link {
|
||||
display: block;
|
||||
color: var(--c-black);
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__buttons-group {
|
||||
|
@ -94,7 +94,7 @@ export abstract class RouteConfig {
|
||||
public static BillingPaymentMethods2 = new NavigationLink('payment-methods', 'Payment Methods 2');
|
||||
public static BillingHistory = new NavigationLink('billing-history', 'Billing History');
|
||||
// this duplicates the path of BillingHistory so that they can be used interchangeably in BillingArea.vue
|
||||
public static BillingHistory2 = new NavigationLink('billing-history2', 'Billing History 2');
|
||||
public static BillingHistory2 = new NavigationLink('billing-history', 'Billing History 2');
|
||||
public static BillingCoupons = new NavigationLink('coupons', 'Coupons');
|
||||
public static BillingCoupons2 = new NavigationLink('coupons', 'Billing Coupons');
|
||||
|
||||
|
@ -123,7 +123,7 @@
|
||||
<!-- 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"
|
||||
:on-continue="() => refreshSession(true)"
|
||||
:on-logout="handleInactive"
|
||||
:on-close="closeInactivityModal"
|
||||
:initial-seconds="inactivityModalTime / 1000"
|
||||
@ -570,8 +570,9 @@ function selectProject(fetchedProjects: Project[]): void {
|
||||
|
||||
/**
|
||||
* Refreshes session and resets session timers.
|
||||
* @param manual - whether the user manually refreshed session. i.e.: clicked "Stay Logged In".
|
||||
*/
|
||||
async function refreshSession(): Promise<void> {
|
||||
async function refreshSession(manual = false): Promise<void> {
|
||||
isSessionRefreshing.value = true;
|
||||
|
||||
try {
|
||||
@ -588,6 +589,10 @@ async function refreshSession(): Promise<void> {
|
||||
inactivityModalShown.value = false;
|
||||
isSessionActive.value = false;
|
||||
isSessionRefreshing.value = false;
|
||||
|
||||
if (manual && !usersStore.state.settings.sessionDuration) {
|
||||
appStore.updateActiveModal(MODALS.editSessionTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,7 +109,7 @@
|
||||
</div>
|
||||
<InactivityModal
|
||||
v-if="inactivityModalShown"
|
||||
:on-continue="refreshSession"
|
||||
:on-continue="() => refreshSession(true)"
|
||||
:on-logout="handleInactive"
|
||||
:on-close="closeInactivityModal"
|
||||
:initial-seconds="inactivityModalTime / 1000"
|
||||
@ -559,8 +559,9 @@ function restartSessionTimers(): void {
|
||||
|
||||
/**
|
||||
* Refreshes session and resets session timers.
|
||||
* @param manual - whether the user manually refreshed session. i.e.: clicked "Stay Logged In".
|
||||
*/
|
||||
async function refreshSession(): Promise<void> {
|
||||
async function refreshSession(manual = false): Promise<void> {
|
||||
isSessionRefreshing.value = true;
|
||||
|
||||
try {
|
||||
@ -577,6 +578,10 @@ async function refreshSession(): Promise<void> {
|
||||
inactivityModalShown.value = false;
|
||||
isSessionActive.value = false;
|
||||
isSessionRefreshing.value = false;
|
||||
|
||||
if (manual && !usersStore.state.settings.sessionDuration) {
|
||||
appStore.updateActiveModal(MODALS.editSessionTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user