Add timeout modal.
Build and Deploy Web App / build-and-deploy (push) Successful in 20s
Details
Build and Deploy Web App / build-and-deploy (push) Successful in 20s
Details
This commit is contained in:
parent
7455a55766
commit
83db4baa5b
|
|
@ -0,0 +1,53 @@
|
|||
<script setup lang="ts">
|
||||
import { useAuthStore } from '@/stores/auth-store'
|
||||
import { useTemplateRef, ref, computed } from 'vue'
|
||||
import ModalWrapper from './common/ModalWrapper.vue'
|
||||
import AppButton from './common/AppButton.vue'
|
||||
|
||||
const timeoutModal = useTemplateRef("timeoutModal")
|
||||
const secondsUntilLogout = ref(30)
|
||||
const timeoutTimerId = ref<number | undefined>()
|
||||
const timePhrase = computed(() => {
|
||||
if (secondsUntilLogout.value !== 1) {
|
||||
return secondsUntilLogout.value + " seconds"
|
||||
}
|
||||
return secondsUntilLogout.value + " second"
|
||||
})
|
||||
|
||||
const authStore = useAuthStore()
|
||||
|
||||
function start() {
|
||||
if (timeoutModal.value?.isOpen()) return
|
||||
secondsUntilLogout.value = 30
|
||||
timeoutModal.value?.show()
|
||||
timeoutTimerId.value = window.setInterval(() => {
|
||||
secondsUntilLogout.value = secondsUntilLogout.value - 1
|
||||
if (secondsUntilLogout.value <= 0) {
|
||||
authStore.onUserLoggedOut()
|
||||
window.clearInterval(timeoutTimerId.value)
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
function dismissTimeout() {
|
||||
window.clearInterval(timeoutTimerId.value)
|
||||
timeoutModal.value?.close()
|
||||
}
|
||||
|
||||
defineExpose({ start })
|
||||
</script>
|
||||
<template>
|
||||
<ModalWrapper ref="timeoutModal">
|
||||
<template v-slot:default>
|
||||
<p>
|
||||
You've been inactive for a while, so to ensure the safety of your
|
||||
personal information, you will be logged out in
|
||||
<strong>{{ timePhrase }}</strong>
|
||||
unless you click below to remain logged in.
|
||||
</p>
|
||||
</template>
|
||||
<template v-slot:buttons>
|
||||
<AppButton @click="dismissTimeout()">Stay Logged In</AppButton>
|
||||
</template>
|
||||
</ModalWrapper>
|
||||
</template>
|
||||
|
|
@ -23,24 +23,20 @@ function close(returnValue?: string) {
|
|||
dialog.value?.close(returnValue)
|
||||
}
|
||||
|
||||
defineExpose({ show, close })
|
||||
function isOpen(): boolean {
|
||||
return dialog.value?.open ?? false
|
||||
}
|
||||
|
||||
defineExpose({ show, close, isOpen })
|
||||
</script>
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<dialog
|
||||
ref="dialog"
|
||||
class="app-modal-dialog"
|
||||
:id="id"
|
||||
>
|
||||
<dialog ref="dialog" class="app-modal-dialog" :id="id">
|
||||
<slot></slot>
|
||||
|
||||
<div class="app-modal-dialog-actions">
|
||||
<slot name="buttons">
|
||||
<AppButton
|
||||
button-style="secondary"
|
||||
@click="close()"
|
||||
>Close</AppButton
|
||||
>
|
||||
<AppButton button-style="secondary" @click="close()">Close</AppButton>
|
||||
</slot>
|
||||
</div>
|
||||
</dialog>
|
||||
|
|
|
|||
|
|
@ -7,14 +7,23 @@ pages.
|
|||
import { AuthApiClient } from '@/api/auth'
|
||||
import { getSelectedProfile } from '@/api/profile'
|
||||
import { secondsUntilExpired } from '@/api/token-util'
|
||||
import IdleTimeoutModal from '@/components/IdleTimeoutModal.vue'
|
||||
import { useAuthStore } from '@/stores/auth-store'
|
||||
import { onMounted, ref, type Ref } from 'vue'
|
||||
import { useIdleObserver } from '@idle-observer/vue3'
|
||||
import { onMounted, ref, useTemplateRef, type Ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const authStore = useAuthStore()
|
||||
|
||||
const IDLE_TIMEOUT_SECONDS = 300
|
||||
const idleTimeoutModal = useTemplateRef("idleTimeoutModal")
|
||||
useIdleObserver({
|
||||
timeout: IDLE_TIMEOUT_SECONDS * 1000,
|
||||
onIdle: () => idleTimeoutModal.value?.start()
|
||||
})
|
||||
|
||||
const authCheckTimer: Ref<number | undefined> = ref(undefined)
|
||||
|
||||
onMounted(async () => {
|
||||
|
|
@ -61,31 +70,24 @@ async function checkAuth() {
|
|||
<div>
|
||||
<header class="app-header-bar">
|
||||
<div>
|
||||
<h1
|
||||
class="app-header-text"
|
||||
@click="onHeaderClicked()"
|
||||
>
|
||||
<h1 class="app-header-text" @click="onHeaderClicked()">
|
||||
Finnow
|
||||
</h1>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
class="app-user-widget"
|
||||
@click="router.push('/me')"
|
||||
>
|
||||
<span class="app-user-widget" @click="router.push('/me')">
|
||||
<font-awesome-icon icon="fa-user"></font-awesome-icon>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="app-logout-button"
|
||||
@click="authStore.onUserLoggedOut()"
|
||||
>
|
||||
<span class="app-logout-button" @click="authStore.onUserLoggedOut()">
|
||||
<font-awesome-icon icon="fa-solid fa-arrow-right-from-bracket"></font-awesome-icon>
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<RouterView></RouterView>
|
||||
|
||||
<IdleTimeoutModal ref="idleTimeoutModal" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue