Client - error message style (wip)

Need some updates api side.
This commit is contained in:
Sam 2021-08-15 10:50:39 +02:00
parent 4bbfb800cb
commit 6c770ed76b
15 changed files with 114 additions and 27 deletions

View File

@ -0,0 +1,41 @@
<template>
<div class="error-message">
<ul v-if="Array.isArray(message)">
<li v-for="(submessage, index) in message" :key="index">
{{ t(submessage) }}
</li>
</ul>
<div v-else>{{ t(message) }}</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { useI18n } from 'vue-i18n'
export default defineComponent({
name: 'ErrorMessage',
props: {
message: [String, Array],
},
setup() {
const { t } = useI18n()
return {
t,
}
},
})
</script>
<style scoped lang="scss">
@import '~@/scss/base';
.error-message {
background: var(--error-background-color);
color: var(--error-color);
border-radius: 4px;
margin: $default-margin;
padding: $default-padding;
}
</style>

View File

@ -36,9 +36,7 @@
</div> </div>
<button type="submit">{{ t(buttonText) }}</button> <button type="submit">{{ t(buttonText) }}</button>
</form> </form>
<p v-if="errorMessage"> <ErrorMessage :message="errorMessages" v-if="errorMessages" />
{{ errorMessage }}
</p>
</div> </div>
</div> </div>
</div> </div>
@ -51,9 +49,13 @@
import { IFormData } from '@/interfaces' import { IFormData } from '@/interfaces'
import { ROOT_STORE, USER_STORE } from '@/store/constants' import { ROOT_STORE, USER_STORE } from '@/store/constants'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
import ErrorMessage from '@/components/Common/ErrorMessage.vue'
export default defineComponent({ export default defineComponent({
name: 'LoginForm', name: 'LoginForm',
components: {
ErrorMessage,
},
props: { props: {
action: { action: {
type: String, type: String,
@ -73,8 +75,8 @@
const buttonText: ComputedRef<string> = computed(() => const buttonText: ComputedRef<string> = computed(() =>
props.action === 'register' ? 'buttons.REGISTER' : 'buttons.LOGIN' props.action === 'register' ? 'buttons.REGISTER' : 'buttons.LOGIN'
) )
const errorMessage: ComputedRef<string | null> = computed( const errorMessages: ComputedRef<string | string[] | null> = computed(
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGE] () => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
) )
function onSubmit(actionType: string) { function onSubmit(actionType: string) {
@ -87,7 +89,7 @@
return { return {
t, t,
buttonText, buttonText,
errorMessage, errorMessages,
formData, formData,
onSubmit, onSubmit,
} }
@ -119,6 +121,7 @@
@media screen and (max-width: $medium-limit) { @media screen and (max-width: $medium-limit) {
height: auto; height: auto;
margin-bottom: 50px;
} }
} }
</style> </style>

View File

@ -0,0 +1,10 @@
{
"ERROR": {
"UNKNOWN": "Error. Please try again or contact the administrator.",
"Invalid credentials": "Invalid credentials.",
"Password and password confirmation don't match": "Password and password confirmation don't match.",
"Password: 8 characters required": "Password: 8 characters required.",
"Username: 3 to 12 characters required": "Username: 3 to 12 characters required.",
"Valid email must be provided": "Valid email must be provided."
}
}

View File

@ -1,4 +1,5 @@
import AdministrationTranslations from './administration.json' import AdministrationTranslations from './administration.json'
import ApiTranslations from './api.json'
import ButtonsTranslations from './buttons.json' import ButtonsTranslations from './buttons.json'
import CommonTranslations from './common.json' import CommonTranslations from './common.json'
import DashboardTranslations from './dashboard.json' import DashboardTranslations from './dashboard.json'
@ -9,6 +10,7 @@ import WorkoutsTranslations from './workouts.json'
export default { export default {
administration: AdministrationTranslations, administration: AdministrationTranslations,
api: ApiTranslations,
buttons: ButtonsTranslations, buttons: ButtonsTranslations,
common: CommonTranslations, common: CommonTranslations,
dashboard: DashboardTranslations, dashboard: DashboardTranslations,

View File

@ -0,0 +1,10 @@
{
"ERROR": {
"UNKNOWN": "Erreur. Veuillez réessayer ou contacter l'administrateur.",
"Invalid credentials": "Identifiants invalides.",
"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.",
"Username: 3 to 12 characters required": "3 à 12 caractères requis pour le nom.",
"Valid email must be provided": "L'email fourni n'est pas valide."
}
}

View File

@ -1,4 +1,5 @@
import AdministrationTranslations from './administration.json' import AdministrationTranslations from './administration.json'
import ApiTranslations from './api.json'
import ButtonsTranslations from './buttons.json' import ButtonsTranslations from './buttons.json'
import CommonTranslations from './common.json' import CommonTranslations from './common.json'
import DashboardTranslations from './dashboard.json' import DashboardTranslations from './dashboard.json'
@ -9,6 +10,7 @@ import WorkoutsTranslations from './workouts.json'
export default { export default {
administration: AdministrationTranslations, administration: AdministrationTranslations,
api: ApiTranslations,
buttons: ButtonsTranslations, buttons: ButtonsTranslations,
common: CommonTranslations, common: CommonTranslations,
dashboard: DashboardTranslations, dashboard: DashboardTranslations,

View File

@ -14,4 +14,7 @@
--footer-border-color: #ebeef3; --footer-border-color: #ebeef3;
--footer-color: #8b8c8c; --footer-color: #8b8c8c;
--error-background-color: #ffd2d2;
--error-color: #db1924;
} }

View File

@ -1,10 +1,10 @@
export enum RootGetters { export enum RootGetters {
ERROR_MESSAGE = 'ERROR_MESSAGE', ERROR_MESSAGES = 'ERROR_MESSAGES',
LANGUAGE = 'LANGUAGE', LANGUAGE = 'LANGUAGE',
} }
export enum RootMutations { export enum RootMutations {
EMPTY_ERROR_MESSAGE = 'EMPTY_ERROR_MESSAGE', EMPTY_ERROR_MESSAGES = 'EMPTY_ERROR_MESSAGES',
SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE', SET_ERROR_MESSAGES = 'SET_ERROR_MESSAGES',
UPDATE_LANG = 'UPDATE_LANG', UPDATE_LANG = 'UPDATE_LANG',
} }

View File

@ -4,8 +4,8 @@ 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.ERROR_MESSAGE]: (state: IRootState) => { [ROOT_STORE.GETTERS.ERROR_MESSAGES]: (state: IRootState) => {
return state.errorMessage return state.errorMessages
}, },
[ROOT_STORE.GETTERS.LANGUAGE]: (state: IRootState) => { [ROOT_STORE.GETTERS.LANGUAGE]: (state: IRootState) => {
return state.language return state.language

View File

@ -3,10 +3,12 @@ import { ROOT_STORE } from '@/store/constants'
export interface IRootState { export interface IRootState {
root: boolean root: boolean
language: string language: string
errorMessage: string | null errorMessages: string | string[] | null
} }
export interface IRootGetters { export interface IRootGetters {
[ROOT_STORE.GETTERS.ERROR_MESSAGE](state: IRootState): string | null [ROOT_STORE.GETTERS.ERROR_MESSAGES](
state: IRootState
): string | string[] | null
[ROOT_STORE.GETTERS.LANGUAGE](state: IRootState): string [ROOT_STORE.GETTERS.LANGUAGE](state: IRootState): string
} }

View File

@ -5,14 +5,14 @@ import { IRootState } from '@/store/modules/root/interfaces'
import { TRootMutations } from '@/store/modules/root/types' import { TRootMutations } from '@/store/modules/root/types'
export const mutations: MutationTree<IRootState> & TRootMutations = { export const mutations: MutationTree<IRootState> & TRootMutations = {
[ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGE](state: IRootState) { [ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES](state: IRootState) {
state.errorMessage = null state.errorMessages = null
}, },
[ROOT_STORE.MUTATIONS.SET_ERROR_MESSAGE]( [ROOT_STORE.MUTATIONS.SET_ERROR_MESSAGES](
state: IRootState, state: IRootState,
errorMessage: string errorMessages: string
) { ) {
state.errorMessage = errorMessage state.errorMessages = errorMessages
}, },
[ROOT_STORE.MUTATIONS.UPDATE_LANG](state: IRootState, language: string) { [ROOT_STORE.MUTATIONS.UPDATE_LANG](state: IRootState, language: string) {
state.language = language state.language = language

View File

@ -3,5 +3,5 @@ import { IRootState } from '@/store/modules/root/interfaces'
export const state: IRootState = { export const state: IRootState = {
root: true, root: true,
language: 'en', language: 'en',
errorMessage: null, errorMessages: null,
} }

View File

@ -4,8 +4,11 @@ import { ROOT_STORE } from '@/store/constants'
import { IRootGetters, IRootState } from '@/store/modules/root/interfaces' import { IRootGetters, IRootState } from '@/store/modules/root/interfaces'
export type TRootMutations<S = IRootState> = { export type TRootMutations<S = IRootState> = {
[ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGE](state: S): void [ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES](state: S): void
[ROOT_STORE.MUTATIONS.SET_ERROR_MESSAGE](state: S, errorMessage: string): void [ROOT_STORE.MUTATIONS.SET_ERROR_MESSAGES](
state: S,
errorMessages: string
): void
[ROOT_STORE.MUTATIONS.UPDATE_LANG](state: S, language: string): void [ROOT_STORE.MUTATIONS.UPDATE_LANG](state: S, language: string): void
} }

View File

@ -30,7 +30,7 @@ export const actions: ActionTree<IUserState, IRootState> & IUserActions = {
[USER_STORE.ACTIONS.GET_USER_PROFILE]( [USER_STORE.ACTIONS.GET_USER_PROFILE](
context: ActionContext<IUserState, IRootState> context: ActionContext<IUserState, IRootState>
): void { ): void {
context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGE) context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
authApi authApi
.get('auth/profile') .get('auth/profile')
.then((res) => { .then((res) => {
@ -49,7 +49,7 @@ export const actions: ActionTree<IUserState, IRootState> & IUserActions = {
context: ActionContext<IUserState, IRootState>, context: ActionContext<IUserState, IRootState>,
data: ILoginOrRegisterData data: ILoginOrRegisterData
): void { ): void {
context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGE) context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
api api
.post(`/auth/${data.actionType}`, data.formData) .post(`/auth/${data.actionType}`, data.formData)
.then((res) => { .then((res) => {
@ -71,7 +71,7 @@ export const actions: ActionTree<IUserState, IRootState> & IUserActions = {
): void { ): void {
localStorage.removeItem('authToken') localStorage.removeItem('authToken')
context.commit(USER_STORE.MUTATIONS.CLEAR_AUTH_USER_TOKEN) context.commit(USER_STORE.MUTATIONS.CLEAR_AUTH_USER_TOKEN)
context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGE) context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
router.push('/login') router.push('/login')
}, },
} }

View File

@ -10,12 +10,15 @@ export const getApiUrl = (): string => {
: 'http://localhost:5000/api' : 'http://localhost:5000/api'
} }
// TODO: update api error messages to remove these workarounds
const removeLastEndOfLine = (text: string): string => text.replace(/\n$/gm, '')
const removeLastDot = (text: string): string => text.replace(/\.$/gm, '')
export const handleError = ( export const handleError = (
context: ActionContext<IUserState, IRootState>, context: ActionContext<IUserState, IRootState>,
error: AxiosError | null, error: AxiosError | null,
msg = 'error.UNKNOWN' msg = 'UNKNOWN'
): void => { ): void => {
const errorMessage = !error let errorMessages = !error
? msg ? msg
: error.response : error.response
? error.response.data.message ? error.response.data.message
@ -24,5 +27,13 @@ export const handleError = (
: error.message : error.message
? error.message ? error.message
: msg : msg
context.commit(ROOT_STORE.MUTATIONS.SET_ERROR_MESSAGE, errorMessage) errorMessages = removeLastEndOfLine(errorMessages)
context.commit(
ROOT_STORE.MUTATIONS.SET_ERROR_MESSAGES,
errorMessages.includes('\n')
? errorMessages
.split('\n')
.map((m: string) => `api.ERROR.${removeLastDot(m)}`)
: `api.ERROR.${removeLastDot(errorMessages)}`
)
} }