290 lines
8.4 KiB
Vue
290 lines
8.4 KiB
Vue
<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_${
|
|
emailUpdate && appConfig.is_email_sending_enabled ? 'EMAIL_' : ''
|
|
}UPDATE`
|
|
)
|
|
}}
|
|
</div>
|
|
<form :class="{ errors: formErrors }" @submit.prevent="updateProfile">
|
|
<label class="form-items" for="email">
|
|
{{ $t('user.EMAIL') }}*
|
|
<input
|
|
id="email"
|
|
v-model="userForm.email"
|
|
:disabled="loading"
|
|
:required="true"
|
|
@invalid="invalidateForm"
|
|
/>
|
|
</label>
|
|
<label class="form-items" for="password-field">
|
|
{{ $t('user.CURRENT_PASSWORD') }}*
|
|
<PasswordInput
|
|
id="password-field"
|
|
:disabled="loading"
|
|
:password="userForm.password"
|
|
:required="true"
|
|
@updatePassword="updatePassword"
|
|
@passwordError="invalidateForm"
|
|
/>
|
|
</label>
|
|
<label class="form-items" for="new-password-field">
|
|
{{ $t('user.NEW_PASSWORD') }}
|
|
<PasswordInput
|
|
id="new-password-field"
|
|
:disabled="loading"
|
|
:checkStrength="true"
|
|
:password="userForm.new_password"
|
|
:isSuccess="false"
|
|
@updatePassword="updateNewPassword"
|
|
@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>
|
|
<button class="confirm" v-if="canRequestExport()" @click.prevent="requestExport">
|
|
{{ $t('buttons.REQUEST_DATA_EXPORT') }}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
<div class="data-export">
|
|
<span class="info-box">
|
|
<i class="fa fa-info-circle" aria-hidden="true" />
|
|
{{ $t('user.EXPORT_REQUEST.ONLY_ONE_EXPORT_PER_DAY') }}
|
|
</span>
|
|
<div v-if="exportRequest" class="data-export-archive">
|
|
{{$t('user.EXPORT_REQUEST.DATA_EXPORT')}}
|
|
({{ exportRequestDate }}):
|
|
<span
|
|
v-if="exportRequest.status=== 'successful'"
|
|
class="archive-link"
|
|
@click.prevent="downloadArchive(exportRequest.file_name)"
|
|
>
|
|
<i class="fa fa-download" aria-hidden="true" />
|
|
{{ $t("user.EXPORT_REQUEST.DOWNLOAD_ARCHIVE") }}
|
|
({{ getReadableFileSize(exportRequest.file_size) }})
|
|
</span>
|
|
<span v-else>
|
|
{{ $t(`user.EXPORT_REQUEST.STATUS.${exportRequest.status}`)}}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { isBefore, subDays } from 'date-fns'
|
|
import {
|
|
ComputedRef,
|
|
Ref,
|
|
computed,
|
|
reactive,
|
|
ref,
|
|
toRefs,
|
|
onMounted,
|
|
watch,
|
|
onUnmounted,
|
|
} from 'vue'
|
|
|
|
import authApi from "@/api/authApi";
|
|
import PasswordInput from '@/components/Common/PasswordInput.vue'
|
|
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
|
|
import { TAppConfig } from '@/types/application'
|
|
import {IAuthUserProfile, IUserAccountPayload, IExportRequest} from '@/types/user'
|
|
import { useStore } from '@/use/useStore'
|
|
import { formatDate } from '@/utils/dates'
|
|
import { getReadableFileSize } from '@/utils/files'
|
|
|
|
interface Props {
|
|
user: IAuthUserProfile
|
|
}
|
|
const props = defineProps<Props>()
|
|
const { user } = toRefs(props)
|
|
|
|
const store = useStore()
|
|
const userForm: IUserAccountPayload = reactive({
|
|
email: '',
|
|
password: '',
|
|
new_password: '',
|
|
})
|
|
const loading = computed(
|
|
() => store.getters[AUTH_USER_STORE.GETTERS.USER_LOADING]
|
|
)
|
|
const appConfig: ComputedRef<TAppConfig> = computed(
|
|
() => store.getters[ROOT_STORE.GETTERS.APP_CONFIG]
|
|
)
|
|
const isSuccess: ComputedRef<boolean> = computed(
|
|
() => store.getters[AUTH_USER_STORE.GETTERS.IS_SUCCESS]
|
|
)
|
|
const emailUpdate = ref(false)
|
|
const errorMessages: ComputedRef<string | string[] | null> = computed(
|
|
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
|
|
)
|
|
const formErrors = ref(false)
|
|
const displayModal: Ref<boolean> = ref(false)
|
|
const exportRequest: ComputedRef<IExportRequest | null> = computed(
|
|
() => store.getters[AUTH_USER_STORE.GETTERS.EXPORT_REQUEST]
|
|
)
|
|
const exportRequestDate: ComputedRef<string | null> = computed(
|
|
() => getExportRequestDate()
|
|
)
|
|
|
|
onMounted(() => {
|
|
if (props.user) {
|
|
store.dispatch(AUTH_USER_STORE.ACTIONS.GET_REQUEST_DATA_EXPORT)
|
|
updateUserForm(props.user)
|
|
}
|
|
})
|
|
|
|
function invalidateForm() {
|
|
formErrors.value = true
|
|
}
|
|
function updateUserForm(user: IAuthUserProfile) {
|
|
userForm.email = user.email
|
|
}
|
|
function updatePassword(password: string) {
|
|
userForm.password = password
|
|
}
|
|
function updateNewPassword(new_password: string) {
|
|
userForm.new_password = new_password
|
|
}
|
|
function getExportRequestDate() {
|
|
return exportRequest.value ? formatDate(
|
|
exportRequest.value.created_at,
|
|
user.value.timezone,
|
|
user.value.date_format,
|
|
true,
|
|
null, true
|
|
) : null
|
|
}
|
|
|
|
function canRequestExport() {
|
|
return exportRequestDate.value
|
|
? isBefore(new Date(exportRequestDate.value), subDays(new Date(), 1))
|
|
: true
|
|
}
|
|
function updateProfile() {
|
|
const payload: IUserAccountPayload = {
|
|
email: userForm.email,
|
|
password: userForm.password,
|
|
}
|
|
if (userForm.new_password) {
|
|
payload.new_password = userForm.new_password
|
|
}
|
|
emailUpdate.value = userForm.email !== user.value.email
|
|
store.dispatch(AUTH_USER_STORE.ACTIONS.UPDATE_USER_ACCOUNT, payload)
|
|
}
|
|
function updateDisplayModal(value: boolean) {
|
|
displayModal.value = value
|
|
}
|
|
function deleteAccount(username: string) {
|
|
store.dispatch(AUTH_USER_STORE.ACTIONS.DELETE_ACCOUNT, { username })
|
|
}
|
|
function requestExport() {
|
|
store.dispatch(AUTH_USER_STORE.ACTIONS.REQUEST_DATA_EXPORT)
|
|
}
|
|
async function downloadArchive(filename: string) {
|
|
await authApi
|
|
.get(`/auth/profile/export/${filename}`, {
|
|
responseType: 'blob',
|
|
})
|
|
.then((response) => {
|
|
const archiveFileUrl = window.URL.createObjectURL(
|
|
new Blob([response.data], { type: 'application/zip' })
|
|
)
|
|
const archive_link = document.createElement('a')
|
|
archive_link.href = archiveFileUrl
|
|
archive_link.setAttribute('download', filename)
|
|
document.body.appendChild(archive_link)
|
|
archive_link.click()
|
|
})
|
|
}
|
|
|
|
onUnmounted(() => {
|
|
store.commit(AUTH_USER_STORE.MUTATIONS.UPDATE_IS_SUCCESS, false)
|
|
store.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
|
|
})
|
|
|
|
watch(
|
|
() => isSuccess.value,
|
|
async (isSuccessValue) => {
|
|
if (isSuccessValue) {
|
|
updatePassword('')
|
|
updateNewPassword('')
|
|
updateUserForm(user.value)
|
|
formErrors.value = false
|
|
}
|
|
}
|
|
)
|
|
watch(
|
|
() => user.value.email,
|
|
async () => {
|
|
updateUserForm(user.value)
|
|
}
|
|
)
|
|
</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;
|
|
}
|
|
}
|
|
|
|
.data-export {
|
|
padding: $default-padding 0;
|
|
.data-export-archive {
|
|
padding-top: $default-padding*2;
|
|
font-size: .9em;
|
|
|
|
.archive-link {
|
|
color: var(--app-a-color);
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
}
|
|
</style>
|