Client - add account deletion

This commit is contained in:
Sam 2021-10-13 19:21:53 +02:00
parent 5b470b7786
commit 2729d5dae5
11 changed files with 78 additions and 5 deletions

View File

@ -1,5 +1,12 @@
<template> <template>
<div id="user-profile-edition"> <div id="user-profile-edition">
<Modal
v-if="displayModal"
:title="t('common.CONFIRMATION')"
:message="t('user.CONFIRM_ACCOUNT_DELETION')"
@confirmAction="deleteAccount(user.username)"
@cancelAction="updateDisplayModal(false)"
/>
<Card> <Card>
<template #title>{{ t('user.PROFILE.EDITION') }}</template> <template #title>{{ t('user.PROFILE.EDITION') }}</template>
<template #content> <template #content>
@ -113,6 +120,9 @@
<button class="confirm" type="submit"> <button class="confirm" type="submit">
{{ t('buttons.SUBMIT') }} {{ t('buttons.SUBMIT') }}
</button> </button>
<button class="danger" @click.prevent="updateDisplayModal(true)">
{{ t('buttons.DELETE_MY_ACCOUNT') }}
</button>
<button class="cancel" @click.prevent="$router.go(-1)"> <button class="cancel" @click.prevent="$router.go(-1)">
{{ t('buttons.CANCEL') }} {{ t('buttons.CANCEL') }}
</button> </button>
@ -129,9 +139,11 @@
import { import {
ComputedRef, ComputedRef,
PropType, PropType,
Ref,
computed, computed,
defineComponent, defineComponent,
reactive, reactive,
ref,
onMounted, onMounted,
} from 'vue' } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
@ -139,6 +151,7 @@
import Card from '@/components/Common/Card.vue' import Card from '@/components/Common/Card.vue'
import CustomTextArea from '@/components/Common/CustomTextArea.vue' import CustomTextArea from '@/components/Common/CustomTextArea.vue'
import ErrorMessage from '@/components/Common/ErrorMessage.vue' import ErrorMessage from '@/components/Common/ErrorMessage.vue'
import Modal from '@/components/Common/Modal.vue'
import { ROOT_STORE, USER_STORE } from '@/store/constants' import { ROOT_STORE, USER_STORE } from '@/store/constants'
import { IAuthUserProfile, IUserPayload } from '@/types/user' import { IAuthUserProfile, IUserPayload } from '@/types/user'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
@ -149,6 +162,7 @@
Card, Card,
CustomTextArea, CustomTextArea,
ErrorMessage, ErrorMessage,
Modal,
}, },
props: { props: {
user: { user: {
@ -195,6 +209,7 @@
const errorMessages: ComputedRef<string | string[] | null> = computed( const errorMessages: ComputedRef<string | string[] | null> = computed(
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES] () => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
) )
let displayModal: Ref<boolean> = ref(false)
onMounted(() => { onMounted(() => {
if (props.user) { if (props.user) {
@ -220,16 +235,25 @@
function updateProfile() { function updateProfile() {
store.dispatch(USER_STORE.ACTIONS.UPDATE_USER_PROFILE, userForm) store.dispatch(USER_STORE.ACTIONS.UPDATE_USER_PROFILE, userForm)
} }
function updateDisplayModal(value: boolean) {
displayModal.value = value
}
function deleteAccount(username: string) {
store.dispatch(USER_STORE.ACTIONS.DELETE_ACCOUNT, { username })
}
return { return {
availableLanguages, availableLanguages,
displayModal,
errorMessages, errorMessages,
loading, loading,
registrationDate, registrationDate,
t, t,
userForm, userForm,
weekStart, weekStart,
deleteAccount,
updateBio, updateBio,
updateDisplayModal,
updateProfile, updateProfile,
} }
}, },

View File

@ -1,5 +1,6 @@
{ {
"CANCEL": "Cancel", "CANCEL": "Cancel",
"DELETE_MY_ACCOUNT": "Delete my account",
"FILTER": "Filter", "FILTER": "Filter",
"LOGIN": "Log in", "LOGIN": "Log in",
"NO": "No", "NO": "No",

View File

@ -1,5 +1,6 @@
{ {
"EMAIL": "Email", "EMAIL": "Email",
"CONFIRM_ACCOUNT_DELETION": "Are you sure you want to delete your account? All data will be deleted, this cannot be undone",
"LANGUAGE": "Language", "LANGUAGE": "Language",
"LOGIN": "Login", "LOGIN": "Login",
"LOGOUT": "Logout", "LOGOUT": "Logout",

View File

@ -1,5 +1,6 @@
{ {
"CANCEL": "Annuler", "CANCEL": "Annuler",
"DELETE_MY_ACCOUNT": "Supprimer mon compte",
"FILTER": "Filtrer", "FILTER": "Filtrer",
"LOGIN": "Se connecter", "LOGIN": "Se connecter",
"NO": "Non", "NO": "Non",

View File

@ -1,5 +1,6 @@
{ {
"CONFIRM-PASSWORD": "Confirmation du mot de passe", "CONFIRM-PASSWORD": "Confirmation du mot de passe",
"CONFIRM_ACCOUNT_DELETION": "Etes-vous sûr de vouloir supprimer votre compte ? Toutes les données seront définitivement effacés.",
"EMAIL": "Email", "EMAIL": "Email",
"LANGUAGE": "Langue", "LANGUAGE": "Langue",
"LOGIN": "Se connecter", "LOGIN": "Se connecter",

View File

@ -70,8 +70,8 @@ button {
background: var(--button-cancel-bg-color); background: var(--button-cancel-bg-color);
color: var(--button-cancel-color); color: var(--button-cancel-color);
&:hover { &:hover {
background: var(--app-color); background: var(--app-color);
color: var(--button-hover-color); color: var(--button-hover-color);
} }
} }
@ -79,11 +79,19 @@ button {
background: var(--button-confirm-bg-color); background: var(--button-confirm-bg-color);
color: var(--button-confirm-color); color: var(--button-confirm-color);
&:hover { &:hover {
background: var(--app-color); background: var(--app-color);
color: var(--button-hover-color); color: var(--button-hover-color);
} }
} }
&.danger {
background: var(--button-danger-bg-color);
color: var(--button-danger-color);
&:hover {
background: var(--button-danger-hover-bg-color);
color: var(--button-danger-hover-color);
}
}
} }
.box { .box {

View File

@ -12,6 +12,10 @@
--button-cancel-color: var(--app-color); --button-cancel-color: var(--app-color);
--button-confirm-bg-color: #FFFFFF; --button-confirm-bg-color: #FFFFFF;
--button-confirm-color: var(--app-color); --button-confirm-color: var(--app-color);
--button-danger-bg-color: #FFFFFF;
--button-danger-color: #dc3545;
--button-danger-hover-bg-color: #dc3545;
--button-danger-hover-color: #FFFFFF;
--card-border-color: #c4c7cf; --card-border-color: #c4c7cf;
--input-border-color: #9da3af; --input-border-color: #9da3af;

View File

@ -12,7 +12,11 @@ import {
} from '@/store/constants' } from '@/store/constants'
import { IRootState } from '@/store/modules/root/types' import { IRootState } from '@/store/modules/root/types'
import { IUserActions, IUserState } from '@/store/modules/user/types' import { IUserActions, IUserState } from '@/store/modules/user/types'
import { ILoginOrRegisterData, IUserPayload } from '@/types/user' import {
ILoginOrRegisterData,
IUserDeletionPayload,
IUserPayload,
} from '@/types/user'
import { handleError } from '@/utils' import { handleError } from '@/utils'
export const actions: ActionTree<IUserState, IRootState> & IUserActions = { export const actions: ActionTree<IUserState, IRootState> & IUserActions = {
@ -104,4 +108,22 @@ export const actions: ActionTree<IUserState, IRootState> & IUserActions = {
context.commit(USER_STORE.MUTATIONS.UPDATE_USER_LOADING, false) context.commit(USER_STORE.MUTATIONS.UPDATE_USER_LOADING, false)
) )
}, },
[USER_STORE.ACTIONS.DELETE_ACCOUNT](
context: ActionContext<IUserState, IRootState>,
payload: IUserDeletionPayload
): void {
context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
authApi
.delete(`users/${payload.username}`)
.then((res) => {
if (res.status === 204) {
context
.dispatch(USER_STORE.ACTIONS.LOGOUT)
.then(() => router.push('/'))
} else {
handleError(context, null)
}
})
.catch((error) => handleError(context, error))
},
} }

View File

@ -1,5 +1,6 @@
export enum UserActions { export enum UserActions {
CHECK_AUTH_USER = 'CHECK_AUTH_USER', CHECK_AUTH_USER = 'CHECK_AUTH_USER',
DELETE_ACCOUNT = 'DELETE_ACCOUNT',
GET_USER_PROFILE = 'GET_USER_PROFILE', GET_USER_PROFILE = 'GET_USER_PROFILE',
LOGIN_OR_REGISTER = 'LOGIN_OR_REGISTER', LOGIN_OR_REGISTER = 'LOGIN_OR_REGISTER',
LOGOUT = 'LOGOUT', LOGOUT = 'LOGOUT',

View File

@ -10,6 +10,7 @@ import { IRootState } from '@/store/modules/root/types'
import { import {
IAuthUserProfile, IAuthUserProfile,
ILoginOrRegisterData, ILoginOrRegisterData,
IUserDeletionPayload,
IUserPayload, IUserPayload,
} from '@/types/user' } from '@/types/user'
@ -41,6 +42,11 @@ export interface IUserActions {
context: ActionContext<IUserState, IRootState>, context: ActionContext<IUserState, IRootState>,
payload: IUserPayload payload: IUserPayload
): void ): void
[USER_STORE.ACTIONS.DELETE_ACCOUNT](
context: ActionContext<IUserState, IRootState>,
payload: IUserDeletionPayload
): void
} }
export interface IUserGetters { export interface IUserGetters {

View File

@ -35,6 +35,10 @@ export interface IUserPayload {
password_conf: string password_conf: string
} }
export interface IUserDeletionPayload {
username: string
}
export interface ILoginRegisterFormData { export interface ILoginRegisterFormData {
username: string username: string
email: string email: string