fix(settings) Some cleanup + large preview of avatar

This commit is contained in:
Ferdinand Thiessen 2021-11-29 18:16:21 +01:00
parent 868a3f3383
commit 2baa813eb8
1 changed files with 76 additions and 74 deletions

View File

@ -1,4 +1,15 @@
<template>
<q-dialog v-model="preview" auto-close square>
<q-card class="q-dialog-plugin">
<q-img :src="image" fit="contain">
<template #error>
<div style="width: 100%; height: 100%" class="row justify-center">
<img style="height: 100%; background: white" src="no-image.svg" />
</div>
</template>
</q-img>
</q-card>
</q-dialog>
<q-form @submit="save" @reset="reset">
<q-card-section class="fit row justify-start content-center items-center">
<q-input
@ -62,26 +73,32 @@
/>
<q-file
v-model="avatar"
class="col-xs-12 col-sm-6 q-pa-sm"
filled
clearable
label="Avatar"
accept=".jpg, image/*"
hint="Bilddateien nur JPEG"
:clearable="avatar.name !== '' || deleteAvatar"
@update:model-value="imagePreview"
@clear="clear"
accept="image/*, .jpg, .png"
class="col-xs-12 col-sm-6 q-pa-sm"
@clear="avatar = undefined"
@rejected="onAvatarRejected"
>
<template #file="{ file }">
<div class="full-width row justify-center">
<q-avatar size="265px">
<q-img v-if="!avatarError || file.name !== ''" :src="image" @error="error" />
<q-img v-else src="no-image.svg" />
<template #before>
<q-avatar @click="preview = true">
<q-img
style="min-width: 100%; min-height: 100%"
:src="image"
@error="hasAvatar = false"
>
<template #error><img style="width: 100%" src="no-image.svg" /></template
></q-img>
</q-avatar>
</div>
</template>
<template #append v-if="!avatarError && !deleteAvatar">
<q-btn round color="negative" icon="mdi-trash-can" size="xs" @click="toDeleteAvatar" />
<template #append>
<q-icon
v-if="!avatar && hasAvatar"
:name="deleteAvatar ? 'mdi-delete-restore' : 'mdi-delete'"
class="cursor-pointer"
@click="deleteAvatar = !deleteAvatar"
/>
</template>
</q-file>
</q-card-section>
@ -117,13 +134,15 @@ import { Notify } from 'quasar';
import { IsoDateInput, PasswordInput } from '@flaschengeist/api/components';
import { defineComponent, computed, ref, onBeforeMount, PropType, watchEffect } from 'vue';
import {
avatarURL,
hasPermission,
notEmpty,
isEmail,
useMainStore,
useUserStore,
api,
isAxiosError,
} from '@flaschengeist/api';
import { PERMISSIONS } from '../../permissions';
export default defineComponent({
name: 'MainUserSettings',
@ -146,27 +165,41 @@ export default defineComponent({
void userStore.getRoles(false);
});
const preview = ref(false);
const password = ref('');
const newPassword = ref('');
const avatar = ref<File>(new File([], '', {}));
const avatarError = ref(false);
const avatar = ref<File>();
const userModel = ref(Object.assign({}, props.user));
const previewURL = ref<string>(); //< Preview of an avatar as data URL
const canSetRoles = computed(() => hasPermission('users_set_roles'));
const allRoles = computed(() => userStore.roles.map((role) => role.name));
const canSetRoles = computed(() => hasPermission(PERMISSIONS.SET_ROLES));
const isCurrentUser = computed(() => userModel.value.userid === mainStore.currentUser.userid);
const _deleteAvatar = ref(false);
const deleteAvatar = computed({
get: () => _deleteAvatar.value,
set: (val: boolean) => (_deleteAvatar.value = val),
});
const deleteAvatar = ref(false);
const hasAvatar = ref(true);
/* Reset model if props changed */
watchEffect(() => {
if (props.user.userid && props.user.userid !== userModel.value.userid) reset();
});
watchEffect(() => {
if (avatar.value && avatar.value instanceof File) {
let reader = new FileReader();
reader.onload = (e) => {
previewURL.value = <string | undefined>(e.target?.result || undefined);
};
reader.readAsDataURL(avatar.value);
} else previewURL.value = undefined;
});
/**
* Notify user is file does not fulfil the requirements
*/
function onAvatarRejected() {
Notify.create({
group: false,
@ -179,6 +212,9 @@ export default defineComponent({
avatar.value = new File([], '', {});
}
/**
* Save changes, emit user model, directly uploads / deletes avatar by using the API
*/
async function save() {
let changed: FG.User = userModel.value;
if (typeof changed.birthday === 'string') changed.birthday = new Date(changed.birthday);
@ -193,16 +229,14 @@ export default defineComponent({
emit('update:user', changed);
if (avatar.value instanceof File && avatar.value.name)
if (avatar.value !== undefined && avatar.value.name) {
await userStore
.uploadAvatar(changed, avatar.value instanceof File ? avatar.value : avatar.value[0])
.catch((response: Response) => {
if (response && response.status == 400) {
onAvatarRejected();
}
});
if (deleteAvatar.value) {
.uploadAvatar(changed, avatar.value)
.catch((response) => isAxiosError(response, 400) && onAvatarRejected());
hasAvatar.value = true;
} else if (deleteAvatar.value) {
await userStore.deleteAvatar(changed);
hasAvatar.value = false
}
password.value = '';
}
@ -211,9 +245,9 @@ export default defineComponent({
userModel.value = Object.assign({}, props.user);
password.value = '';
newPassword.value = '';
imgsrc.value = undefined;
avatar.value = undefined;
previewURL.value = undefined;
deleteAvatar.value = false;
avatarError.value = false;
}
function isFreeUID(val: string) {
@ -223,49 +257,23 @@ export default defineComponent({
);
}
const imgsrc = ref();
const image = computed(() => {
if (imgsrc.value) {
return <string>imgsrc.value;
if (previewURL.value) {
return previewURL.value;
}
if (props.user.avatar_url && !deleteAvatar.value) {
return `${api.defaults.baseURL || ''}${props.user.avatar_url}`;
if (!deleteAvatar.value) {
return avatarURL(props.user);
}
return 'no-image.svg';
});
function imagePreview() {
if (avatar.value && avatar.value instanceof File) {
let reader = new FileReader();
reader.onload = (e) => {
imgsrc.value = e.target?.result;
};
reader.readAsDataURL(avatar.value);
}
}
function clear(val: File) {
avatar.value = new File([], '', {});
imgsrc.value = undefined;
deleteAvatar.value = false;
}
function toDeleteAvatar() {
avatar.value = new File([], '', {});
imgsrc.value = undefined;
deleteAvatar.value = true;
}
function error() {
avatarError.value = true;
}
return {
allRoles,
avatar,
canSetRoles,
deleteAvatar,
hasAvatar,
image,
isCurrentUser,
isEmail,
isFreeUID,
@ -273,16 +281,10 @@ export default defineComponent({
notEmpty,
onAvatarRejected,
password,
preview,
reset,
save,
userModel,
image,
imagePreview,
clear,
deleteAvatar,
avatarError,
toDeleteAvatar,
error,
};
},
});