mirror of
https://github.com/OpenBankProject/API-Explorer-II.git
synced 2026-02-06 10:47:04 +00:00
inactivity timeout refactor for Vue
This commit is contained in:
parent
fea483833c
commit
7c24d821a5
1
components.d.ts
vendored
1
components.d.ts
vendored
@ -7,6 +7,7 @@ export {}
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AutoLogout: typeof import('./src/components/AutoLogout.vue')['default']
|
||||
ChatMessage: typeof import('./src/components/ChatMessage.vue')['default']
|
||||
ChatWidget: typeof import('./src/components/ChatWidget.vue')['default']
|
||||
ChatWidgetOld: typeof import('./src/components/ChatWidgetOld.vue')['default']
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
function addSeconds(date, seconds) {
|
||||
date.setSeconds(date.getSeconds() + seconds);
|
||||
return date;
|
||||
}
|
||||
|
||||
export function showCountdownTimer() {
|
||||
|
||||
// Get current date and time
|
||||
var now = new Date().getTime();
|
||||
let distance = countDownDate - now;
|
||||
|
||||
// Output the result in an element with id="countdown-timer-span"
|
||||
let elementId = ("countdown-timer-span");
|
||||
document.getElementById(elementId).innerHTML = "in " + Math.floor(distance / 1000) + "s";
|
||||
|
||||
// If the count down is over release resources
|
||||
if (distance < 0) {
|
||||
destroyCountdownTimer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Set the date we're counting down to
|
||||
let countDownDate = addSeconds(new Date(), 5);
|
||||
|
||||
let showTimerInterval = null;
|
||||
|
||||
export function destroyCountdownTimer() {
|
||||
clearInterval(showTimerInterval);
|
||||
}
|
||||
|
||||
export function resetCountdownTimer(seconds) {
|
||||
destroyCountdownTimer(); // Destroy previous timer if any
|
||||
countDownDate = addSeconds(new Date(), seconds); // Set the date we're counting down to
|
||||
showTimerInterval = setInterval(showCountdownTimer, 1000); // Update the count down every 1 second
|
||||
}
|
||||
142
src/components/AutoLogout.vue
Normal file
142
src/components/AutoLogout.vue
Normal file
@ -0,0 +1,142 @@
|
||||
<script setup lang="ts">
|
||||
import { ElNotification, NotificationHandle } from 'element-plus';
|
||||
import { ref, computed, h, onMounted, onBeforeUnmount } from 'vue';
|
||||
|
||||
// Props can be defined with defineProps
|
||||
const props = defineProps({
|
||||
// Define your props here
|
||||
});
|
||||
|
||||
// Types of events that will reset the timeout
|
||||
const events = ['click', 'mousemove', 'keydown', 'keypress', 'mousedown', 'scroll', 'load'];
|
||||
|
||||
// Set timers
|
||||
let warningTimeout: NodeJS.Timeout;
|
||||
let logoutTimeout: NodeJS.Timeout;
|
||||
|
||||
let logoutTime: number;
|
||||
let countdownInterval: NodeJS.Timeout;
|
||||
|
||||
// Methods
|
||||
function setTimers() {
|
||||
|
||||
// Should use a function here to get suggested timeout from OBP
|
||||
const timeoutInSeconds = async () => {}
|
||||
|
||||
const warningDelay = 1000 * 4; // 4 seconds for development, change later
|
||||
const logoutDelay = 1000 * 15; // 15 seconds for development, change later
|
||||
|
||||
logoutTime = Date.now() + logoutDelay;
|
||||
|
||||
warningTimeout = setTimeout(warningMessage, warningDelay); // 4 seconds for development, change later
|
||||
logoutTimeout = setTimeout(logout, logoutDelay); // 15 seconds for development, change later
|
||||
|
||||
}
|
||||
|
||||
let warningNotification: NotificationHandle;
|
||||
|
||||
async function getOBPSuggestedTimeout() {
|
||||
const obpApiHost = import.meta.env.VITE_OBP_API_HOST;
|
||||
let timeoutInSeconds: number;
|
||||
// Fetch the suggested timeout from the OBP API
|
||||
|
||||
const response = await fetch(`${obpApiHost}/obp/v5.1.0/ui/suggested-session-timeout`);
|
||||
const json = await response.json();
|
||||
if(json.timeout_in_seconds) {
|
||||
timeoutInSeconds = json.timeout_in_seconds;
|
||||
console.log(`Suggested value ${timeoutInSeconds} is used`);
|
||||
} else {
|
||||
timeoutInSeconds = 5 * 60 + 1; // Set default value to 301 seconds
|
||||
console.log(`Default value ${timeoutInSeconds} is used`);
|
||||
}
|
||||
|
||||
return timeoutInSeconds;
|
||||
}
|
||||
|
||||
function resetTimeout() {
|
||||
// Logic to reset the timeout
|
||||
clearTimeout(warningTimeout);
|
||||
clearTimeout(logoutTimeout);
|
||||
clearInterval(countdownInterval);
|
||||
|
||||
|
||||
if (warningNotification) {
|
||||
warningNotification.close();
|
||||
}
|
||||
|
||||
setTimers();
|
||||
}
|
||||
|
||||
function warningMessage() {
|
||||
// Logic to show warning message
|
||||
console.log('Warning: You will be logged out soon');
|
||||
|
||||
let secondsLeft = ref(Math.ceil((logoutTime - Date.now()) / 1000));
|
||||
// Update the countdown every second
|
||||
countdownInterval = setInterval(() => {
|
||||
secondsLeft.value = Math.ceil((logoutTime - Date.now()) / 1000);
|
||||
|
||||
// If time's up or almost up, clear the interval
|
||||
if (secondsLeft.value <= 0) {
|
||||
clearInterval(countdownInterval);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}, 1000);
|
||||
|
||||
warningNotification = ElNotification({
|
||||
title: 'Inactivity Warning',
|
||||
message: () => h('p', null, [
|
||||
h('span', null, 'You will be logged out in'),
|
||||
h('strong', { style: 'color: red' }, ` ${secondsLeft.value} `),
|
||||
h('span', null, 'seconds.'),
|
||||
])
|
||||
,
|
||||
type: 'warning',
|
||||
duration: 0,
|
||||
position: 'top-left',
|
||||
showClose: false,
|
||||
})
|
||||
}
|
||||
|
||||
function logout() {
|
||||
// Logic to log out the user
|
||||
console.log('Logging out...');
|
||||
document.getElementById("logoff")?.click(); // If the ID of the logout button changes, this will not work
|
||||
}
|
||||
|
||||
// Lifecycle hooks
|
||||
onMounted(() => {
|
||||
events.forEach(event => {
|
||||
window.addEventListener(event, resetTimeout);
|
||||
})
|
||||
|
||||
setTimers();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
// Cleanup code before component is unmounted
|
||||
clearTimeout(warningTimeout);
|
||||
clearTimeout(logoutTimeout);
|
||||
clearInterval(countdownInterval);
|
||||
events.forEach(event => {
|
||||
window.removeEventListener(event, resetTimeout);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Your component styles here */
|
||||
</style>
|
||||
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- Your component content here -->
|
||||
</div>
|
||||
</template>
|
||||
@ -60,7 +60,8 @@ const headerLinksBackgroundColor = ref(headerLinksBackgroundColorSetting)
|
||||
const clearActiveTab = () => {
|
||||
const activeLinks = document.querySelectorAll('.router-link')
|
||||
for (const active of activeLinks) {
|
||||
if (active.id) {
|
||||
// Skip login and logoff buttons
|
||||
if (active.id && active.id !== 'login' && active.id !== 'logoff') {
|
||||
active.style.backgroundColor = 'transparent'
|
||||
active.style.color = '#39455f'
|
||||
}
|
||||
@ -163,11 +164,11 @@ const getCurrentPath = () => {
|
||||
<arrow-down />
|
||||
</el-icon>
|
||||
</span>-->
|
||||
<a v-bind:href="'/api/connect?redirect='+ encodeURIComponent(getCurrentPath())" v-show="isShowLoginButton" class="login-button router-link">
|
||||
<a v-bind:href="'/api/connect?redirect='+ encodeURIComponent(getCurrentPath())" v-show="isShowLoginButton" class="login-button router-link" id="login">
|
||||
{{ $t('header.login') }}
|
||||
</a>
|
||||
<span v-show="isShowLogOffButton" class="login-user">{{ loginUsername }}</span>
|
||||
<a v-bind:href="'/api/user/logoff?redirect=' + encodeURIComponent(getCurrentPath())" v-show="isShowLogOffButton" class="logoff-button router-link">
|
||||
<a v-bind:href="'/api/user/logoff?redirect=' + encodeURIComponent(getCurrentPath())" v-show="isShowLogOffButton" class="logoff-button router-link" id="logoff">
|
||||
{{ $t('header.logoff') }}
|
||||
</a>
|
||||
</RouterView>
|
||||
@ -233,8 +234,8 @@ nav {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.login-button,
|
||||
.logoff-button {
|
||||
a.login-button,
|
||||
a.logoff-button {
|
||||
margin: 5px;
|
||||
color: #ffffff;
|
||||
background-color: #32b9ce;
|
||||
|
||||
@ -28,14 +28,26 @@
|
||||
<script setup lang="ts">
|
||||
import SearchNav from '../components/SearchNav.vue'
|
||||
import Menu from '../components/Menu.vue'
|
||||
import AutoLogout from '../components/AutoLogout.vue'
|
||||
import ChatWidget from '../components/ChatWidget.vue'
|
||||
import Collections from '../components/Collections.vue'
|
||||
import { inject } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { getCurrentUser } from '../obp'
|
||||
|
||||
const isLoggedIn = ref(false);
|
||||
|
||||
onMounted(async () => {
|
||||
const currentUser = await getCurrentUser()
|
||||
const currentResponseKeys = Object.keys(currentUser)
|
||||
isLoggedIn.value = currentResponseKeys.includes('username')
|
||||
})
|
||||
|
||||
|
||||
const isChatbotEnabled = import.meta.env.VITE_CHATBOT_ENABLED === 'true'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<AutoLogout v-if=isLoggedIn />
|
||||
<el-container class="root">
|
||||
<el-aside class="search-nav" width="20%">
|
||||
<!--Left-->
|
||||
|
||||
Loading…
Reference in New Issue
Block a user