Client - display page error if can not fetch app config
This commit is contained in:
parent
0b95b93e06
commit
9fc70fcf23
@ -1,30 +1,51 @@
|
|||||||
<template>
|
<template>
|
||||||
<NavBar />
|
<NavBar />
|
||||||
<div class="app-container">
|
<div v-if="appLoading" class="app-container">
|
||||||
<router-view />
|
<div class="app-loading">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="app-container">
|
||||||
|
<router-view v-if="appConfig" />
|
||||||
|
<NoConfig v-else />
|
||||||
</div>
|
</div>
|
||||||
<Footer />
|
<Footer />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, onBeforeMount } from 'vue'
|
import { computed, ComputedRef, defineComponent, onBeforeMount } from 'vue'
|
||||||
|
|
||||||
import { ROOT_STORE } from '@/store/constants'
|
import { ROOT_STORE } from '@/store/constants'
|
||||||
import { useStore } from '@/use/useStore'
|
import { useStore } from '@/use/useStore'
|
||||||
|
import { IAppConfig } from '@/store/modules/root/interfaces'
|
||||||
import Footer from '@/components/Footer.vue'
|
import Footer from '@/components/Footer.vue'
|
||||||
|
import Loader from '@/components/Common/Loader.vue'
|
||||||
import NavBar from '@/components/NavBar.vue'
|
import NavBar from '@/components/NavBar.vue'
|
||||||
|
import NoConfig from '@/components/NoConfig.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
Footer,
|
Footer,
|
||||||
|
Loader,
|
||||||
NavBar,
|
NavBar,
|
||||||
|
NoConfig,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
const appConfig: ComputedRef<IAppConfig> = computed(
|
||||||
|
() => store.getters[ROOT_STORE.GETTERS.APP_CONFIG]
|
||||||
|
)
|
||||||
|
const appLoading: ComputedRef<boolean> = computed(
|
||||||
|
() => store.getters[ROOT_STORE.GETTERS.APP_LOADING]
|
||||||
|
)
|
||||||
onBeforeMount(() =>
|
onBeforeMount(() =>
|
||||||
store.dispatch(ROOT_STORE.ACTIONS.GET_APPLICATION_CONFIG)
|
store.dispatch(ROOT_STORE.ACTIONS.GET_APPLICATION_CONFIG)
|
||||||
)
|
)
|
||||||
|
return {
|
||||||
|
appConfig,
|
||||||
|
appLoading,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@ -33,5 +54,11 @@
|
|||||||
@import '~@/scss/base';
|
@import '~@/scss/base';
|
||||||
.app-container {
|
.app-container {
|
||||||
height: $app-height;
|
height: $app-height;
|
||||||
|
|
||||||
|
.app-loading {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
31
fittrackee_client/src/components/Common/Loader.vue
Normal file
31
fittrackee_client/src/components/Common/Loader.vue
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<template>
|
||||||
|
<div class="loader" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Loader',
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '~@/scss/base';
|
||||||
|
.loader {
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
border: 14px solid var(--app-loading-color);
|
||||||
|
border-top: 14px solid var(--app-loading-top-color);
|
||||||
|
border-radius: 50%;
|
||||||
|
height: 60px;
|
||||||
|
margin-left: 41%;
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
84
fittrackee_client/src/components/NoConfig.vue
Normal file
84
fittrackee_client/src/components/NoConfig.vue
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<template>
|
||||||
|
<div id="no-config">
|
||||||
|
<div class="error-page">
|
||||||
|
<div class="error-img">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -51 512 512">
|
||||||
|
<g id="error">
|
||||||
|
<path
|
||||||
|
class="error-page-img"
|
||||||
|
d="M 0 0 C 0 11.300781 0 399.777344 0 410 L 512 410 C 512 402.324219 512 2.425781 512 0 Z M 370 71 L 370 30 L 411 30 L 411 71 Z M 30 30 L 340 30 L 340 71 L 30 71 Z M 482 380 L 30 380 L 30 101 L 482 101 Z M 441 71 L 441 30 L 482 30 L 482 71 Z M 441 71 "
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="error-page-img"
|
||||||
|
d="M 325.519531 297.070312 C 294.328125 265.878906 294.328125 215.125 325.519531 183.929688 L 304.304688 162.71875 C 261.417969 205.605469 261.417969 275.390625 304.304688 318.28125 Z M 325.519531 297.070312 "
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="error-page-img"
|
||||||
|
d="M 197.089844 180 L 237.089844 180 L 237.089844 220 L 197.089844 220 Z M 197.089844 180 "
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="error-page-img"
|
||||||
|
d="M 197.089844 261 L 237.089844 261 L 237.089844 301 L 197.089844 301 Z M 197.089844 261 "
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<p class="error-message" v-html="$t('error.APP_ERROR')" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'NoConfig',
|
||||||
|
setup() {
|
||||||
|
const { t } = useI18n()
|
||||||
|
return { t }
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '~@/scss/base';
|
||||||
|
|
||||||
|
#no-config {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
|
||||||
|
padding: $default-padding;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.error-page {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
max-width: 100%;
|
||||||
|
|
||||||
|
.error-img {
|
||||||
|
width: 150px;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
.error-page-img {
|
||||||
|
stroke: none;
|
||||||
|
fill-rule: nonzero;
|
||||||
|
fill: var(--app-color);
|
||||||
|
filter: drop-shadow(10px 10px 10px var(--app-shadow-color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
font-size: 1.2em;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
@media screen and (max-width: $medium-limit) {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -2,6 +2,7 @@
|
|||||||
"ERROR": {
|
"ERROR": {
|
||||||
"UNKNOWN": "Error. Please try again or contact the administrator.",
|
"UNKNOWN": "Error. Please try again or contact the administrator.",
|
||||||
"Invalid credentials": "Invalid credentials.",
|
"Invalid credentials": "Invalid credentials.",
|
||||||
|
"Network Error": "Network Error",
|
||||||
"Password and password confirmation don't match": "Password and password confirmation don't match.",
|
"Password and password confirmation don't match": "Password and password confirmation don't match.",
|
||||||
"Password: 8 characters required": "Password: 8 characters required.",
|
"Password: 8 characters required": "Password: 8 characters required.",
|
||||||
"Username: 3 to 12 characters required": "Username: 3 to 12 characters required.",
|
"Username: 3 to 12 characters required": "Username: 3 to 12 characters required.",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"UNKNOWN": "Error. Please try again or contact the administrator.",
|
"UNKNOWN": "Error. Please try again or contact the administrator.",
|
||||||
|
"APP_ERROR": "The application seems encounter some issues.<br />Please try later or contact the administrator.",
|
||||||
"NOT_FOUND": {
|
"NOT_FOUND": {
|
||||||
"PAGE": "Page not found"
|
"PAGE": "Page not found"
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"ERROR": {
|
"ERROR": {
|
||||||
"UNKNOWN": "Erreur. Veuillez réessayer ou contacter l'administrateur.",
|
"UNKNOWN": "Erreur. Veuillez réessayer ou contacter l'administrateur.",
|
||||||
"Invalid credentials": "Identifiants invalides.",
|
"Invalid credentials": "Identifiants invalides.",
|
||||||
|
"Network Error": "Erreur Réseau",
|
||||||
"Password and password confirmation don't match": "Les mots de passe saisis sont différents.",
|
"Password and password confirmation don't match": "Les mots de passe saisis sont différents.",
|
||||||
"Password: 8 characters required": "8 caractères minimum pour le mot de passe.",
|
"Password: 8 characters required": "8 caractères minimum pour le mot de passe.",
|
||||||
"Username: 3 to 12 characters required": "3 à 12 caractères requis pour le nom.",
|
"Username: 3 to 12 characters required": "3 à 12 caractères requis pour le nom.",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"UNKNOWN": "Erreur. Veuillez réessayer ou contacter l'administrateur.",
|
"UNKNOWN": "Erreur. Veuillez réessayer ou contacter l'administrateur.",
|
||||||
|
"APP_ERROR": "L'application semble rencontrer quelques problèmes.<br />Veuillez réessayer plus tard ou contacter l'administrateur.",
|
||||||
"NOT_FOUND": {
|
"NOT_FOUND": {
|
||||||
"PAGE": "Page introuvable"
|
"PAGE": "Page introuvable"
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
--app-color: #2c3e50;
|
--app-color: #2c3e50;
|
||||||
--app-a-color: #40578a;
|
--app-a-color: #40578a;
|
||||||
--app-shadow-color: lightgrey;
|
--app-shadow-color: lightgrey;
|
||||||
|
--app-loading-color: #f3f3f3;
|
||||||
|
--app-loading-top-color: var(--app-color);
|
||||||
|
|
||||||
--input-border-color: #9da3af;
|
--input-border-color: #9da3af;
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ export const actions: ActionTree<IRootState, IRootState> & IRootActions = {
|
|||||||
context: ActionContext<IRootState, IRootState>
|
context: ActionContext<IRootState, IRootState>
|
||||||
): void {
|
): void {
|
||||||
context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
|
context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
|
||||||
|
context.commit(ROOT_STORE.MUTATIONS.UPDATE_APPLICATION_LOADING, true)
|
||||||
authApi
|
authApi
|
||||||
.get('config')
|
.get('config')
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
@ -23,5 +24,8 @@ export const actions: ActionTree<IRootState, IRootState> & IRootActions = {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => handleError(context, error))
|
.catch((error) => handleError(context, error))
|
||||||
|
.finally(() =>
|
||||||
|
context.commit(ROOT_STORE.MUTATIONS.UPDATE_APPLICATION_LOADING, false)
|
||||||
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ export enum RootActions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum RootGetters {
|
export enum RootGetters {
|
||||||
|
APP_CONFIG = 'APP_CONFIG',
|
||||||
|
APP_LOADING = 'APP_LOADING',
|
||||||
ERROR_MESSAGES = 'ERROR_MESSAGES',
|
ERROR_MESSAGES = 'ERROR_MESSAGES',
|
||||||
LANGUAGE = 'LANGUAGE',
|
LANGUAGE = 'LANGUAGE',
|
||||||
}
|
}
|
||||||
@ -11,5 +13,6 @@ export enum RootMutations {
|
|||||||
EMPTY_ERROR_MESSAGES = 'EMPTY_ERROR_MESSAGES',
|
EMPTY_ERROR_MESSAGES = 'EMPTY_ERROR_MESSAGES',
|
||||||
SET_ERROR_MESSAGES = 'SET_ERROR_MESSAGES',
|
SET_ERROR_MESSAGES = 'SET_ERROR_MESSAGES',
|
||||||
UPDATE_APPLICATION_CONFIG = 'UPDATE_APPLICATION_CONFIG',
|
UPDATE_APPLICATION_CONFIG = 'UPDATE_APPLICATION_CONFIG',
|
||||||
|
UPDATE_APPLICATION_LOADING = 'UPDATE_APPLICATION_LOADING',
|
||||||
UPDATE_LANG = 'UPDATE_LANG',
|
UPDATE_LANG = 'UPDATE_LANG',
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,12 @@ import { ROOT_STORE } from '@/store/constants'
|
|||||||
import { IRootState, IRootGetters } from '@/store/modules/root/interfaces'
|
import { IRootState, IRootGetters } from '@/store/modules/root/interfaces'
|
||||||
|
|
||||||
export const getters: GetterTree<IRootState, IRootState> & IRootGetters = {
|
export const getters: GetterTree<IRootState, IRootState> & IRootGetters = {
|
||||||
|
[ROOT_STORE.GETTERS.APP_CONFIG]: (state: IRootState) => {
|
||||||
|
return state.application.config
|
||||||
|
},
|
||||||
|
[ROOT_STORE.GETTERS.APP_LOADING]: (state: IRootState) => {
|
||||||
|
return state.appLoading
|
||||||
|
},
|
||||||
[ROOT_STORE.GETTERS.ERROR_MESSAGES]: (state: IRootState) => {
|
[ROOT_STORE.GETTERS.ERROR_MESSAGES]: (state: IRootState) => {
|
||||||
return state.errorMessages
|
return state.errorMessages
|
||||||
},
|
},
|
||||||
|
@ -28,6 +28,7 @@ export interface IRootState {
|
|||||||
language: string
|
language: string
|
||||||
errorMessages: string | string[] | null
|
errorMessages: string | string[] | null
|
||||||
application: IApplication
|
application: IApplication
|
||||||
|
appLoading: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRootActions {
|
export interface IRootActions {
|
||||||
@ -37,6 +38,8 @@ export interface IRootActions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IRootGetters {
|
export interface IRootGetters {
|
||||||
|
[ROOT_STORE.GETTERS.APP_CONFIG](state: IRootState): IAppConfig
|
||||||
|
[ROOT_STORE.GETTERS.APP_LOADING](state: IRootState): boolean
|
||||||
[ROOT_STORE.GETTERS.ERROR_MESSAGES](
|
[ROOT_STORE.GETTERS.ERROR_MESSAGES](
|
||||||
state: IRootState
|
state: IRootState
|
||||||
): string | string[] | null
|
): string | string[] | null
|
||||||
|
@ -20,6 +20,12 @@ export const mutations: MutationTree<IRootState> & TRootMutations = {
|
|||||||
) {
|
) {
|
||||||
state.application.config = config
|
state.application.config = config
|
||||||
},
|
},
|
||||||
|
[ROOT_STORE.MUTATIONS.UPDATE_APPLICATION_LOADING](
|
||||||
|
state: IRootState,
|
||||||
|
loading: boolean
|
||||||
|
) {
|
||||||
|
state.appLoading = loading
|
||||||
|
},
|
||||||
[ROOT_STORE.MUTATIONS.UPDATE_LANG](state: IRootState, language: string) {
|
[ROOT_STORE.MUTATIONS.UPDATE_LANG](state: IRootState, language: string) {
|
||||||
state.language = language
|
state.language = language
|
||||||
},
|
},
|
||||||
|
@ -6,4 +6,5 @@ export const state: IRootState = {
|
|||||||
language: 'en',
|
language: 'en',
|
||||||
errorMessages: null,
|
errorMessages: null,
|
||||||
application: <IApplication>{},
|
application: <IApplication>{},
|
||||||
|
appLoading: false,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user