Enable refresh_token when it's about to expire(5 minutes)
This commit is contained in:
parent
c1fb9cfa50
commit
8632070391
@ -19,6 +19,7 @@
|
|||||||
"echarts": "^5.5.1",
|
"echarts": "^5.5.1",
|
||||||
"graphql": "^16.9.0",
|
"graphql": "^16.9.0",
|
||||||
"graphql-tag": "^2.12.6",
|
"graphql-tag": "^2.12.6",
|
||||||
|
"jwt-decode": "^4.0.0",
|
||||||
"pdfjs-dist": "^4.3.136",
|
"pdfjs-dist": "^4.3.136",
|
||||||
"pinia": "^2.1.6",
|
"pinia": "^2.1.6",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
|
|||||||
@ -78,6 +78,14 @@ export default {
|
|||||||
|
|
||||||
UserAuthApi.signinByEmail(this.email, this.password)
|
UserAuthApi.signinByEmail(this.email, this.password)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
|
// Extract the necessary data from the response
|
||||||
|
const { access_token, refresh_token, expires_in } = response.data;
|
||||||
|
|
||||||
|
// Save tokens and expiration time in localStorage
|
||||||
|
localStorage.setItem('access_token', access_token);
|
||||||
|
localStorage.setItem('refresh_token', refresh_token);
|
||||||
|
localStorage.setItem('expires_in', expires_in);
|
||||||
|
|
||||||
let signinAction = response.data.signin_result
|
let signinAction = response.data.signin_result
|
||||||
switch (signinAction) {
|
switch (signinAction) {
|
||||||
case signinActionEnum.EXISTING_USER_PASSWORD_REQUIRED:
|
case signinActionEnum.EXISTING_USER_PASSWORD_REQUIRED:
|
||||||
|
|||||||
@ -1,20 +1,39 @@
|
|||||||
<template>
|
<template>
|
||||||
<empty-content :loading="loading" :empty="requestGroups?.length === 0" />
|
<empty-content :loading="loading" :empty="requestGroups?.length === 0" />
|
||||||
<div class="request-hub">
|
<div class="request-hub">
|
||||||
<div v-for="(group, index) in requestGroups" :key="index" class="request-invitations" :id="group.name">
|
<div
|
||||||
|
v-for="(group, index) in requestGroups"
|
||||||
|
:key="index"
|
||||||
|
class="request-invitations"
|
||||||
|
:id="group.name"
|
||||||
|
>
|
||||||
<div v-if="group.data" id="request-invitation-container">
|
<div v-if="group.data" id="request-invitation-container">
|
||||||
<div class="accordion accordion-list" v-for="(request, index) in group.data" :key="index" :id="request.id">
|
<div
|
||||||
|
class="accordion accordion-list"
|
||||||
|
v-for="(request, index) in group.data"
|
||||||
|
:key="index"
|
||||||
|
:id="request.id"
|
||||||
|
>
|
||||||
<div class="accordion-item my-3">
|
<div class="accordion-item my-3">
|
||||||
<h2 class="accordion-header">
|
<h2 class="accordion-header">
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
<button
|
||||||
:data-bs-target="'#collapse' + index" aria-expanded="false" :aria-controls="'collapse' + index">
|
class="accordion-button collapsed"
|
||||||
|
type="button"
|
||||||
|
data-bs-toggle="collapse"
|
||||||
|
:data-bs-target="'#collapse' + index"
|
||||||
|
aria-expanded="false"
|
||||||
|
:aria-controls="'collapse' + index"
|
||||||
|
>
|
||||||
<div class="dashed-container request-content-container">
|
<div class="dashed-container request-content-container">
|
||||||
<div class="request-content-issuer-container">
|
<div class="request-content-issuer-container">
|
||||||
<label class="request-content-label" for="request-content-issuer-box">{{ $t('Issuer') }}</label>
|
<label class="request-content-label" for="request-content-issuer-box">{{
|
||||||
|
$t('Issuer')
|
||||||
|
}}</label>
|
||||||
<div class="request-content-box" id="request-content-issuer-box">
|
<div class="request-content-box" id="request-content-issuer-box">
|
||||||
<span class="request-content-issuer-text">
|
<span class="request-content-issuer-text">
|
||||||
{{ request.issuer_profile.first_name }}
|
{{ request.issuer_profile.first_name }}
|
||||||
{{ request.issuer_profile.last_name }}</span>
|
{{ request.issuer_profile.last_name }}</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="request-content-title-container">
|
<div class="request-content-title-container">
|
||||||
@ -48,8 +67,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</h2>
|
</h2>
|
||||||
<div :id="'collapse' + index" class="accordion-collapse collapse"
|
<div
|
||||||
data-bs-parent="#request-invitation-container">
|
:id="'collapse' + index"
|
||||||
|
class="accordion-collapse collapse"
|
||||||
|
data-bs-parent="#request-invitation-container"
|
||||||
|
>
|
||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
<div class="request-description-container">
|
<div class="request-description-container">
|
||||||
<button class="make-proposal-button" type="button" @click="Propose(request)">
|
<button class="make-proposal-button" type="button" @click="Propose(request)">
|
||||||
@ -59,13 +81,23 @@
|
|||||||
{{ $t('Message') }}
|
{{ $t('Message') }}
|
||||||
</button>
|
</button>
|
||||||
<div class="request-description-content" v-html="request.content"></div>
|
<div class="request-description-content" v-html="request.content"></div>
|
||||||
<div class="pdf-actions" v-for="(file, index) in request.attached_files" :key="index">
|
<div
|
||||||
<button class="btn btn-link" data-bs-toggle="modal" data-bs-target="#pdf-viewer"
|
class="pdf-actions"
|
||||||
@click="previewAttachedFile(request.id, file.document_id, file.file_name)">
|
v-for="(file, index) in request.attached_files"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="btn btn-link"
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target="#pdf-viewer"
|
||||||
|
@click="previewAttachedFile(request.id, file.document_id, file.file_name)"
|
||||||
|
>
|
||||||
{{ $t('Preview') }}{{ file.file_name }}
|
{{ $t('Preview') }}{{ file.file_name }}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-link"
|
<button
|
||||||
@click="downloadAttachedFile(request.id, file.document_id, file.file_name)">
|
class="btn btn-link"
|
||||||
|
@click="downloadAttachedFile(request.id, file.document_id, file.file_name)"
|
||||||
|
>
|
||||||
{{ $t('Download') }}{{ file.file_name }}
|
{{ $t('Download') }}{{ file.file_name }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -76,45 +108,82 @@
|
|||||||
> -->
|
> -->
|
||||||
<div class="issuer-achievement-container" id="issuer-achievement-container">
|
<div class="issuer-achievement-container" id="issuer-achievement-container">
|
||||||
<div class="issuer-achievement-isssuer-container">
|
<div class="issuer-achievement-isssuer-container">
|
||||||
<label class="issuer-achievement-label" for="issuer-achievement-isssuer-content-div">{{ $t('Name')
|
<label
|
||||||
}}</label>
|
class="issuer-achievement-label"
|
||||||
<div class="issuer-achievement-content-container" id="issuer-achievement-isssuer-content-div">
|
for="issuer-achievement-isssuer-content-div"
|
||||||
|
>{{ $t('Name') }}</label
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="issuer-achievement-content-container"
|
||||||
|
id="issuer-achievement-isssuer-content-div"
|
||||||
|
>
|
||||||
<span class="issuer-achievement-issuer-text">
|
<span class="issuer-achievement-issuer-text">
|
||||||
{{ request.issuer_profile.first_name }}
|
{{ request.issuer_profile.first_name }}
|
||||||
{{ request.issuer_profile.last_name }}</span>
|
{{ request.issuer_profile.last_name }}</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="issuer-achievement-stay-container">
|
<div class="issuer-achievement-stay-container">
|
||||||
<label class="issuer-achievement-label" for="issuer-achievement-stay-content-div">{{ $t('Stay on Freeleaps') }} </label>
|
<label
|
||||||
<div class="issuer-achievement-content-container" id="issuer-achievement-stay-content-div">
|
class="issuer-achievement-label"
|
||||||
|
for="issuer-achievement-stay-content-div"
|
||||||
|
>{{ $t('Stay on Freeleaps') }}
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
class="issuer-achievement-content-container"
|
||||||
|
id="issuer-achievement-stay-content-div"
|
||||||
|
>
|
||||||
<span class="issuer-achievement-stay-content-text">
|
<span class="issuer-achievement-stay-content-text">
|
||||||
{{ request.issuer_achievement.activeness.days_of_staying_on }}
|
{{ request.issuer_achievement.activeness.days_of_staying_on }}
|
||||||
{{ $t('day(s)') }}</span>
|
{{ $t('day(s)') }}</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="issuer-achievement-paid-container">
|
<div class="issuer-achievement-paid-container">
|
||||||
<label class="issuer-achievement-label" for="issuer-achievement-paid-content-div">{{ $t('Total payment') }}</label>
|
<label
|
||||||
<div class="issuer-achievement-content-container" id="issuer-achievement-stay-content-div">
|
class="issuer-achievement-label"
|
||||||
|
for="issuer-achievement-paid-content-div"
|
||||||
|
>{{ $t('Total payment') }}</label
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="issuer-achievement-content-container"
|
||||||
|
id="issuer-achievement-stay-content-div"
|
||||||
|
>
|
||||||
<span class="issuer-achievement-paid-content-text">
|
<span class="issuer-achievement-paid-content-text">
|
||||||
{{ request.issuer_achievement.issuer.spending.total }}
|
{{ request.issuer_achievement.issuer.spending.total }}
|
||||||
{{ request.issuer_achievement.issuer.spending.currency }}</span>
|
{{ request.issuer_achievement.issuer.spending.currency }}</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="issuer-achievement-deposit-container">
|
<div class="issuer-achievement-deposit-container">
|
||||||
<label class="issuer-achievement-label" for="issuer-achievement-deposit-content-div">{{
|
<label
|
||||||
$t('Deposit') }}</label>
|
class="issuer-achievement-label"
|
||||||
<div class="issuer-achievement-content-container" id="issuer-achievement-deposit-content-div">
|
for="issuer-achievement-deposit-content-div"
|
||||||
|
>{{ $t('Deposit') }}</label
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="issuer-achievement-content-container"
|
||||||
|
id="issuer-achievement-deposit-content-div"
|
||||||
|
>
|
||||||
<span class="issuer-achievement-deposit-content-text">
|
<span class="issuer-achievement-deposit-content-text">
|
||||||
{{ request.issuer_achievement.issuer.deposit.available }}
|
{{ request.issuer_achievement.issuer.deposit.available }}
|
||||||
{{ request.issuer_achievement.issuer.deposit.currency }}</span>
|
{{ request.issuer_achievement.issuer.deposit.currency }}</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="issuer-achievement-credit-container">
|
<div class="issuer-achievement-credit-container">
|
||||||
<label class="issuer-achievement-label" for="issuer-achievement-credit-content-div">{{
|
<label
|
||||||
$t('Credit') }}</label>
|
class="issuer-achievement-label"
|
||||||
<div class="issuer-achievement-content-container" id="issuer-achievement-credit-content-div">
|
for="issuer-achievement-credit-content-div"
|
||||||
|
>{{ $t('Credit') }}</label
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="issuer-achievement-content-container"
|
||||||
|
id="issuer-achievement-credit-content-div"
|
||||||
|
>
|
||||||
<span class="issuer-achievement-credit-content-text">
|
<span class="issuer-achievement-credit-content-text">
|
||||||
{{ request.issuer_achievement.activeness.credit }}</span>
|
{{ request.issuer_achievement.activeness.credit }}</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -126,12 +195,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal fade" id="pdf-viewer" tabindex="-1" aria-labelledby="pdf-viewer-label" aria-hidden="true">
|
<div
|
||||||
|
class="modal fade"
|
||||||
|
id="pdf-viewer"
|
||||||
|
tabindex="-1"
|
||||||
|
aria-labelledby="pdf-viewer-label"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<div class="modal-dialog modal-xl">
|
<div class="modal-dialog modal-xl">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h1 class="modal-title fs-5" id="pdf-viewer-label">{{ pdfDocument.title }}</h1>
|
<h1 class="modal-title fs-5" id="pdf-viewer-label">{{ pdfDocument.title }}</h1>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn-close"
|
||||||
|
data-bs-dismiss="modal"
|
||||||
|
aria-label="Close"
|
||||||
|
></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<PDFReader :doc="pdfDocument.doc" />
|
<PDFReader :doc="pdfDocument.doc" />
|
||||||
@ -213,7 +293,7 @@ export default {
|
|||||||
.then((response) => {
|
.then((response) => {
|
||||||
console.log('resposne', response)
|
console.log('resposne', response)
|
||||||
// create file link in browser's memory
|
// create file link in browser's memory
|
||||||
// const href = URL.createObjectURL(response.data)
|
// const ahref = URL.createObjectURL(response.data.download_url)
|
||||||
|
|
||||||
// create "a" HTML element with href to file & click
|
// create "a" HTML element with href to file & click
|
||||||
const link = document.createElement('a')
|
const link = document.createElement('a')
|
||||||
|
|||||||
@ -1,7 +1,75 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import { jwtDecode } from 'jwt-decode';
|
||||||
|
|
||||||
const backendAxios = axios.create({
|
const backendAxios = axios.create({
|
||||||
baseURL: ''
|
baseURL: '',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Function to check if the token has expired
|
||||||
|
function isTokenExpired(token) {
|
||||||
|
// Ensure token is a non-empty string
|
||||||
|
if (!token || typeof token !== 'string') {
|
||||||
|
console.error('Invalid token: must be a non-empty string')
|
||||||
|
return true // Treat it as expired
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const decodedToken = jwtDecode(token)
|
||||||
|
console.log('this is decoded token', decodedToken)
|
||||||
|
const now = Math.floor(Date.now() / 1000)
|
||||||
|
// Buffer as 5 minu = 300 seconds
|
||||||
|
return decodedToken.exp - 300 < now
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error decoding token:', error)
|
||||||
|
return true // Treat it as expired if decoding fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interceptor for handling token expiration and refreshing
|
||||||
|
backendAxios.interceptors.request.use(
|
||||||
|
async (config) => {
|
||||||
|
let accessToken = localStorage.getItem('access_token')
|
||||||
|
const refreshToken = localStorage.getItem('refresh_token')
|
||||||
|
|
||||||
|
// Check if the access token is expired
|
||||||
|
if (!accessToken || isTokenExpired(accessToken)) {
|
||||||
|
if (!refreshToken) {
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// If access token is expired, refresh it using the refresh token
|
||||||
|
const response = await axios.post('/api/user/signin/refresh-token', {}, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${refreshToken}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
accessToken = response.data.access_token
|
||||||
|
const new_refreshToken = response.data.refresh_token
|
||||||
|
|
||||||
|
// Save the new access token to localStorage
|
||||||
|
localStorage.setItem('access_token', accessToken)
|
||||||
|
localStorage.setItem('refresh_token', new_refreshToken)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Token refresh failed. Redirecting to login.')
|
||||||
|
// Optionally, handle token refresh failure (e.g., redirect to login)
|
||||||
|
window.location.href = '/front-door'
|
||||||
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the (new) access token to the request headers
|
||||||
|
if (accessToken) {
|
||||||
|
config.headers.Authorization = `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
export { backendAxios }
|
export { backendAxios }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user