Client - update password update in user account
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<div class="password-input">
|
||||
<input
|
||||
id="password"
|
||||
:disabled="disabled"
|
||||
:placeholder="placeholder"
|
||||
:required="required"
|
||||
@ -18,13 +19,21 @@
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="checkStrength" class="form-info">
|
||||
<i class="fa fa-info-circle" aria-hidden="true" />
|
||||
{{ $t('user.PASSWORD_INFO') }}
|
||||
</div>
|
||||
<PasswordStrength v-if="checkStrength" :password="passwordValue" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Ref, ref, toRefs, watch, withDefaults } from 'vue'
|
||||
|
||||
import PasswordStrength from '@/components/Common/PasswordStength.vue'
|
||||
|
||||
interface Props {
|
||||
checkStrength?: boolean
|
||||
disabled?: boolean
|
||||
password?: string
|
||||
placeholder?: string
|
||||
@ -32,10 +41,13 @@
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
checkStrength: false,
|
||||
disabled: false,
|
||||
password: '',
|
||||
required: false,
|
||||
})
|
||||
const { disabled, password, placeholder, required } = toRefs(props)
|
||||
const { checkStrength, disabled, password, placeholder, required } =
|
||||
toRefs(props)
|
||||
|
||||
const showPassword: Ref<boolean> = ref(false)
|
||||
const passwordValue: Ref<string> = ref('')
|
||||
|
@ -38,14 +38,13 @@
|
||||
watch,
|
||||
} from 'vue'
|
||||
|
||||
import { ROOT_STORE } from '@/store/constants'
|
||||
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
|
||||
import { useStore } from '@/use/useStore'
|
||||
import { getPasswordStrength, setZxcvbnOptions } from '@/utils/password'
|
||||
|
||||
interface Props {
|
||||
password: string
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const { password } = toRefs(props)
|
||||
|
||||
@ -53,6 +52,9 @@
|
||||
const language: ComputedRef<string> = computed(
|
||||
() => store.getters[ROOT_STORE.GETTERS.LANGUAGE]
|
||||
)
|
||||
const isSuccess: ComputedRef<boolean> = computed(
|
||||
() => store.getters[AUTH_USER_STORE.GETTERS.IS_SUCCESS]
|
||||
)
|
||||
const passwordScore: Ref<number> = ref(0)
|
||||
const passwordStrength: Ref<string> = ref('')
|
||||
const passwordSuggestions: Ref<string[]> = ref([])
|
||||
@ -77,7 +79,11 @@
|
||||
watch(
|
||||
() => password.value,
|
||||
async (newPassword) => {
|
||||
calculatePasswordStrength(newPassword)
|
||||
if (isSuccess.value) {
|
||||
passwordStrength.value = ''
|
||||
} else {
|
||||
calculatePasswordStrength(newPassword)
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<div id="user-infos-edition">
|
||||
<Modal
|
||||
v-if="displayModal"
|
||||
:title="$t('common.CONFIRMATION')"
|
||||
:message="$t('user.CONFIRM_ACCOUNT_DELETION')"
|
||||
@confirmAction="deleteAccount(user.username)"
|
||||
@cancelAction="updateDisplayModal(false)"
|
||||
/>
|
||||
<div class="profile-form form-box">
|
||||
<ErrorMessage :message="errorMessages" v-if="errorMessages" />
|
||||
<div class="info-box success-message" v-if="isSuccess">
|
||||
{{ $t('user.PROFILE.SUCCESSFUL_UPDATE') }}
|
||||
</div>
|
||||
<form :class="{ errors: formErrors }" @submit.prevent="updateProfile">
|
||||
<label class="form-items" for="email">
|
||||
{{ $t('user.EMAIL') }}
|
||||
<input id="email" :value="user.email" disabled />
|
||||
</label>
|
||||
<label class="form-items" for="password-field">
|
||||
{{ $t('user.PASSWORD') }}
|
||||
<PasswordInput
|
||||
id="password-field"
|
||||
:disabled="loading"
|
||||
:checkStrength="true"
|
||||
:password="userForm.password"
|
||||
:isSuccess="false"
|
||||
:required="true"
|
||||
@updatePassword="updatePassword"
|
||||
@passwordError="invalidateForm"
|
||||
/>
|
||||
</label>
|
||||
<div class="form-buttons">
|
||||
<button class="confirm" type="submit">
|
||||
{{ $t('buttons.SUBMIT') }}
|
||||
</button>
|
||||
<button class="cancel" @click.prevent="$router.push('/profile')">
|
||||
{{ $t('buttons.CANCEL') }}
|
||||
</button>
|
||||
<button class="danger" @click.prevent="updateDisplayModal(true)">
|
||||
{{ $t('buttons.DELETE_MY_ACCOUNT') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
ComputedRef,
|
||||
Ref,
|
||||
computed,
|
||||
reactive,
|
||||
ref,
|
||||
toRefs,
|
||||
onMounted,
|
||||
watch,
|
||||
onUnmounted,
|
||||
} from 'vue'
|
||||
|
||||
import PasswordInput from '@/components/Common/PasswordInput.vue'
|
||||
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
|
||||
import { IUserProfile, IUserAccountPayload } from '@/types/user'
|
||||
import { useStore } from '@/use/useStore'
|
||||
|
||||
interface Props {
|
||||
user: IUserProfile
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const { user } = toRefs(props)
|
||||
|
||||
const store = useStore()
|
||||
const userForm: IUserAccountPayload = reactive({
|
||||
email: '',
|
||||
password: '',
|
||||
})
|
||||
const loading = computed(
|
||||
() => store.getters[AUTH_USER_STORE.GETTERS.USER_LOADING]
|
||||
)
|
||||
const isSuccess: ComputedRef<boolean> = computed(
|
||||
() => store.getters[AUTH_USER_STORE.GETTERS.IS_SUCCESS]
|
||||
)
|
||||
const errorMessages: ComputedRef<string | string[] | null> = computed(
|
||||
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
|
||||
)
|
||||
const formErrors = ref(false)
|
||||
const displayModal: Ref<boolean> = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
if (props.user) {
|
||||
updateUserForm(props.user)
|
||||
}
|
||||
})
|
||||
|
||||
function invalidateForm() {
|
||||
formErrors.value = true
|
||||
}
|
||||
function updateUserForm(user: IUserProfile) {
|
||||
userForm.email = user.email
|
||||
}
|
||||
function updatePassword(password: string) {
|
||||
userForm.password = password
|
||||
}
|
||||
function updateProfile() {
|
||||
store.dispatch(AUTH_USER_STORE.ACTIONS.UPDATE_USER_ACCOUNT, {
|
||||
password: userForm.password,
|
||||
})
|
||||
}
|
||||
function updateDisplayModal(value: boolean) {
|
||||
displayModal.value = value
|
||||
}
|
||||
function deleteAccount(username: string) {
|
||||
store.dispatch(AUTH_USER_STORE.ACTIONS.DELETE_ACCOUNT, { username })
|
||||
}
|
||||
|
||||
onUnmounted(() =>
|
||||
store.commit(AUTH_USER_STORE.MUTATIONS.UPDATE_IS_SUCCESS, false)
|
||||
)
|
||||
|
||||
watch(
|
||||
() => isSuccess.value,
|
||||
async (isSuccessValue) => {
|
||||
if (isSuccessValue) {
|
||||
updatePassword('')
|
||||
formErrors.value = false
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/scss/vars.scss';
|
||||
|
||||
.form-items {
|
||||
.password-input {
|
||||
::v-deep(.show-password) {
|
||||
font-weight: normal;
|
||||
font-size: 0.8em;
|
||||
margin-top: -4px;
|
||||
padding-left: 0;
|
||||
}
|
||||
::v-deep(.form-info) {
|
||||
font-weight: normal;
|
||||
padding-left: $default-padding;
|
||||
}
|
||||
::v-deep(.password-strength-details) {
|
||||
font-weight: normal;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-buttons {
|
||||
flex-direction: row;
|
||||
@media screen and (max-width: $x-small-limit) {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.success-message {
|
||||
margin: $default-margin * 2 0;
|
||||
background-color: var(--success-background-color);
|
||||
color: var(--success-color);
|
||||
}
|
||||
</style>
|
@ -1,32 +1,12 @@
|
||||
<template>
|
||||
<div id="user-infos-edition">
|
||||
<Modal
|
||||
v-if="displayModal"
|
||||
:title="$t('common.CONFIRMATION')"
|
||||
:message="$t('user.CONFIRM_ACCOUNT_DELETION')"
|
||||
@confirmAction="deleteAccount(user.username)"
|
||||
@cancelAction="updateDisplayModal(false)"
|
||||
/>
|
||||
<div class="profile-form form-box">
|
||||
<ErrorMessage :message="errorMessages" v-if="errorMessages" />
|
||||
<form @submit.prevent="updateProfile">
|
||||
<label class="form-items" for="email">
|
||||
{{ $t('user.EMAIL') }}
|
||||
<input id="email" :value="user.email" disabled />
|
||||
</label>
|
||||
<label class="form-items" for="registrationDate">
|
||||
{{ $t('user.PROFILE.REGISTRATION_DATE') }}
|
||||
<input id="registrationDate" :value="registrationDate" disabled />
|
||||
</label>
|
||||
<label class="form-items" for="password">
|
||||
{{ $t('user.PASSWORD') }}
|
||||
<PasswordInput
|
||||
id="password"
|
||||
:disabled="loading"
|
||||
@updatePassword="updatePassword"
|
||||
/>
|
||||
</label>
|
||||
<hr />
|
||||
<label class="form-items" for="first_name">
|
||||
{{ $t('user.PROFILE.FIRST_NAME') }}
|
||||
<input
|
||||
@ -74,9 +54,6 @@
|
||||
<button class="cancel" @click.prevent="$router.push('/profile')">
|
||||
{{ $t('buttons.CANCEL') }}
|
||||
</button>
|
||||
<button class="danger" @click.prevent="updateDisplayModal(true)">
|
||||
{{ $t('buttons.DELETE_MY_ACCOUNT') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -85,17 +62,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { format } from 'date-fns'
|
||||
import {
|
||||
ComputedRef,
|
||||
Ref,
|
||||
computed,
|
||||
reactive,
|
||||
ref,
|
||||
toRefs,
|
||||
onMounted,
|
||||
} from 'vue'
|
||||
import { ComputedRef, computed, reactive, onMounted } from 'vue'
|
||||
|
||||
import PasswordInput from '@/components/Common/PasswordInput.vue'
|
||||
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
|
||||
import { IUserProfile, IUserPayload } from '@/types/user'
|
||||
import { useStore } from '@/use/useStore'
|
||||
@ -107,9 +75,7 @@
|
||||
|
||||
const store = useStore()
|
||||
|
||||
const { user } = toRefs(props)
|
||||
const userForm: IUserPayload = reactive({
|
||||
password: '',
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
birth_date: '',
|
||||
@ -127,7 +93,6 @@
|
||||
const errorMessages: ComputedRef<string | string[] | null> = computed(
|
||||
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
|
||||
)
|
||||
let displayModal: Ref<boolean> = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
if (props.user) {
|
||||
@ -147,18 +112,9 @@
|
||||
function updateBio(value: string) {
|
||||
userForm.bio = value
|
||||
}
|
||||
function updatePassword(password: string) {
|
||||
userForm.password = password
|
||||
}
|
||||
function updateProfile() {
|
||||
store.dispatch(AUTH_USER_STORE.ACTIONS.UPDATE_USER_PROFILE, userForm)
|
||||
}
|
||||
function updateDisplayModal(value: boolean) {
|
||||
displayModal.value = value
|
||||
}
|
||||
function deleteAccount(username: string) {
|
||||
store.dispatch(AUTH_USER_STORE.ACTIONS.DELETE_ACCOUNT, { username })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -34,7 +34,7 @@
|
||||
const store = useStore()
|
||||
|
||||
const { user, tab } = toRefs(props)
|
||||
const tabs = ['PROFILE', 'PICTURE', 'PREFERENCES', 'SPORTS']
|
||||
const tabs = ['PROFILE', 'ACCOUNT', 'PICTURE', 'PREFERENCES', 'SPORTS']
|
||||
const loading = computed(
|
||||
() => store.getters[AUTH_USER_STORE.GETTERS.USER_LOADING]
|
||||
)
|
||||
|
@ -64,21 +64,10 @@
|
||||
: $t('user.PASSWORD')
|
||||
"
|
||||
:password="formData.password"
|
||||
:checkStrength="['reset', 'register'].includes(action)"
|
||||
@updatePassword="updatePassword"
|
||||
@passwordError="invalidateForm"
|
||||
/>
|
||||
|
||||
<div
|
||||
v-if="['reset', 'register'].includes(action)"
|
||||
class="form-info"
|
||||
>
|
||||
<i class="fa fa-info-circle" aria-hidden="true" />
|
||||
{{ $t('user.PASSWORD_INFO') }}
|
||||
</div>
|
||||
<PasswordStrength
|
||||
v-if="['reset', 'register'].includes(action)"
|
||||
:password="formData.password"
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" :disabled="registration_disabled">
|
||||
{{ $t(buttonText) }}
|
||||
@ -118,7 +107,6 @@
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
import PasswordInput from '@/components/Common/PasswordInput.vue'
|
||||
import PasswordStrength from '@/components/Common/PasswordStength.vue'
|
||||
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
|
||||
import { TAppConfig } from '@/types/application'
|
||||
import { ILoginRegisterFormData } from '@/types/user'
|
||||
@ -234,13 +222,6 @@
|
||||
font-style: italic;
|
||||
padding: 0 $default-padding;
|
||||
}
|
||||
.form-info {
|
||||
color: var(--alert-color);
|
||||
font-size: 0.8em;
|
||||
margin-top: -0.2 * $default-margin;
|
||||
padding: 0 $default-padding * 1.5;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: $default-margin;
|
||||
border: solid 1px var(--app-color);
|
||||
|
@ -35,8 +35,9 @@
|
||||
|
||||
function getPath(tab: string) {
|
||||
switch (tab) {
|
||||
case 'ACCOUNT':
|
||||
case 'PICTURE':
|
||||
return '/profile/edit/picture'
|
||||
return `/profile/edit/${tab.toLocaleLowerCase()}`
|
||||
case 'PREFERENCES':
|
||||
case 'SPORTS':
|
||||
return `/profile${
|
||||
@ -52,7 +53,10 @@
|
||||
<style lang="scss">
|
||||
@import '~@/scss/vars.scss';
|
||||
|
||||
.profile-tabs {
|
||||
margin: $default-margin 0 $default-margin;
|
||||
.profile-tabs-checkboxes {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: $default-margin * 0.5;
|
||||
}
|
||||
</style>
|
||||
|
Reference in New Issue
Block a user