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>