[avatare] delete avatare, improve show avatar
This commit is contained in:
parent
c5bdebb94f
commit
bf2edc3c03
|
@ -3,3 +3,5 @@ yarn-error.log
|
||||||
# No need for sharing this
|
# No need for sharing this
|
||||||
yarn.lock
|
yarn.lock
|
||||||
|
|
||||||
|
.idea
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { defineComponent, ref, onMounted } from 'vue';
|
||||||
import MainUserSettings from './settings/MainUserSettings.vue';
|
import MainUserSettings from './settings/MainUserSettings.vue';
|
||||||
import UserSelector from './UserSelector.vue';
|
import UserSelector from './UserSelector.vue';
|
||||||
import { useMainStore, useUserStore } from '@flaschengeist/api';
|
import { useMainStore, useUserStore } from '@flaschengeist/api';
|
||||||
|
import { Notify } from 'quasar';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'UpdateUser',
|
name: 'UpdateUser',
|
||||||
|
@ -25,12 +26,20 @@ export default defineComponent({
|
||||||
const user = ref(mainStore.currentUser);
|
const user = ref(mainStore.currentUser);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
void userStore.getUsers(true)
|
void userStore.getUsers(true);
|
||||||
})
|
});
|
||||||
|
|
||||||
async function updateUser(value: FG.User) {
|
async function updateUser(value: FG.User) {
|
||||||
await userStore.updateUser(value);
|
await userStore.updateUser(value);
|
||||||
user.value = value;
|
user.value = value;
|
||||||
|
Notify.create({
|
||||||
|
group: false,
|
||||||
|
type: 'positive',
|
||||||
|
message: 'Änderungen gespeichert',
|
||||||
|
timeout: 4000,
|
||||||
|
progress: true,
|
||||||
|
actions: [{ icon: 'mdi-close', color: 'white' }],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -4,7 +4,12 @@
|
||||||
<div v-if="avatar" class="col-4">
|
<div v-if="avatar" class="col-4">
|
||||||
<div style="width: 100%; padding-bottom: 100%; position: relative">
|
<div style="width: 100%; padding-bottom: 100%; position: relative">
|
||||||
<q-avatar style="position: absolute; top: 0; left: 0; width: 100%; height: 100%">
|
<q-avatar style="position: absolute; top: 0; left: 0; width: 100%; height: 100%">
|
||||||
<img :src="api.defaults.baseURL + avatarLink" :onerror="error" />
|
<q-img
|
||||||
|
v-if="!avatarError"
|
||||||
|
:src="api.defaults.baseURL + avatarLink"
|
||||||
|
@error="avatarError = true"
|
||||||
|
/>
|
||||||
|
<q-img v-else src="no-image.svg" />
|
||||||
</q-avatar>
|
</q-avatar>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -41,6 +46,7 @@ export default defineComponent({
|
||||||
const avatar = ref(true);
|
const avatar = ref(true);
|
||||||
const name = ref(mainStore.currentUser.firstname);
|
const name = ref(mainStore.currentUser.firstname);
|
||||||
const avatarLink = ref(mainStore.currentUser.avatar_url);
|
const avatarLink = ref(mainStore.currentUser.avatar_url);
|
||||||
|
const avatarError = ref(false);
|
||||||
|
|
||||||
function error() {
|
function error() {
|
||||||
avatar.value = false;
|
avatar.value = false;
|
||||||
|
@ -65,7 +71,7 @@ export default defineComponent({
|
||||||
.filter((user) => user.userid !== mainStore.currentUser.userid)
|
.filter((user) => user.userid !== mainStore.currentUser.userid)
|
||||||
);
|
);
|
||||||
|
|
||||||
return { avatar, avatarLink, error, name, hasBirthday, birthday, api };
|
return { avatar, avatarLink, error, name, hasBirthday, birthday, api, avatarError };
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -66,12 +66,22 @@
|
||||||
filled
|
filled
|
||||||
label="Avatar"
|
label="Avatar"
|
||||||
accept=".jpg, image/*"
|
accept=".jpg, image/*"
|
||||||
max-file-size="204800"
|
hint="Bilddateien nur JPEG"
|
||||||
hint="Bilddateien, max. 200 KiB"
|
:clearable="avatar.name !== '' || deleteAvatar"
|
||||||
|
@update:model-value="imagePreview"
|
||||||
|
@clear="clear"
|
||||||
@rejected="onAvatarRejected"
|
@rejected="onAvatarRejected"
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #file="{ file }">
|
||||||
<q-icon name="mdi-file-image" @click.stop />
|
<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" />
|
||||||
|
</q-avatar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #append v-if="!avatarError && !deleteAvatar">
|
||||||
|
<q-btn round color="negative" icon="mdi-trash-can" size="xs" @click="toDeleteAvatar" />
|
||||||
</template>
|
</template>
|
||||||
</q-file>
|
</q-file>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
@ -106,7 +116,14 @@
|
||||||
import { Notify } from 'quasar';
|
import { Notify } from 'quasar';
|
||||||
import { IsoDateInput, PasswordInput } from '@flaschengeist/api/components';
|
import { IsoDateInput, PasswordInput } from '@flaschengeist/api/components';
|
||||||
import { defineComponent, computed, ref, onBeforeMount, PropType, watchEffect } from 'vue';
|
import { defineComponent, computed, ref, onBeforeMount, PropType, watchEffect } from 'vue';
|
||||||
import { hasPermission, notEmpty, isEmail, useMainStore, useUserStore } from '@flaschengeist/api';
|
import {
|
||||||
|
hasPermission,
|
||||||
|
notEmpty,
|
||||||
|
isEmail,
|
||||||
|
useMainStore,
|
||||||
|
useUserStore,
|
||||||
|
api,
|
||||||
|
} from '@flaschengeist/api';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'MainUserSettings',
|
name: 'MainUserSettings',
|
||||||
|
@ -131,13 +148,20 @@ export default defineComponent({
|
||||||
|
|
||||||
const password = ref('');
|
const password = ref('');
|
||||||
const newPassword = ref('');
|
const newPassword = ref('');
|
||||||
const avatar = ref<File | FileList | string[]>();
|
const avatar = ref<File>(new File([], '', {}));
|
||||||
|
const avatarError = ref(false);
|
||||||
const userModel = ref(Object.assign({}, props.user));
|
const userModel = ref(Object.assign({}, props.user));
|
||||||
|
|
||||||
const canSetRoles = computed(() => hasPermission('users_set_roles'));
|
const canSetRoles = computed(() => hasPermission('users_set_roles'));
|
||||||
const allRoles = computed(() => userStore.roles.map((role) => role.name));
|
const allRoles = computed(() => userStore.roles.map((role) => role.name));
|
||||||
const isCurrentUser = computed(() => userModel.value.userid === mainStore.currentUser.userid);
|
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),
|
||||||
|
});
|
||||||
|
|
||||||
/* Reset model if props changed */
|
/* Reset model if props changed */
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (props.user.userid && props.user.userid !== userModel.value.userid) reset();
|
if (props.user.userid && props.user.userid !== userModel.value.userid) reset();
|
||||||
|
@ -152,11 +176,11 @@ export default defineComponent({
|
||||||
progress: true,
|
progress: true,
|
||||||
actions: [{ icon: 'mdi-close', color: 'white' }],
|
actions: [{ icon: 'mdi-close', color: 'white' }],
|
||||||
});
|
});
|
||||||
avatar.value = undefined;
|
avatar.value = new File([], '', {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {
|
async function save() {
|
||||||
let changed = userModel.value;
|
let changed: FG.User = userModel.value;
|
||||||
if (typeof changed.birthday === 'string') changed.birthday = new Date(changed.birthday);
|
if (typeof changed.birthday === 'string') changed.birthday = new Date(changed.birthday);
|
||||||
changed = Object.assign(changed, {
|
changed = Object.assign(changed, {
|
||||||
password: password.value,
|
password: password.value,
|
||||||
|
@ -169,20 +193,26 @@ export default defineComponent({
|
||||||
|
|
||||||
emit('update:user', changed);
|
emit('update:user', changed);
|
||||||
|
|
||||||
if (avatar.value)
|
if (avatar.value instanceof File && avatar.value.name)
|
||||||
userStore
|
await userStore
|
||||||
.uploadAvatar(changed, avatar.value instanceof File ? avatar.value : avatar.value[0])
|
.uploadAvatar(changed, avatar.value instanceof File ? avatar.value : avatar.value[0])
|
||||||
.catch((response: Response) => {
|
.catch((response: Response) => {
|
||||||
if (response && response.status == 400) {
|
if (response && response.status == 400) {
|
||||||
onAvatarRejected();
|
onAvatarRejected();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (deleteAvatar.value) {
|
||||||
|
await userStore.deleteAvatar(changed);
|
||||||
|
}
|
||||||
|
password.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
userModel.value = Object.assign({}, props.user);
|
userModel.value = Object.assign({}, props.user);
|
||||||
password.value = '';
|
password.value = '';
|
||||||
newPassword.value = '';
|
newPassword.value = '';
|
||||||
|
imgsrc.value = undefined;
|
||||||
|
deleteAvatar.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFreeUID(val: string) {
|
function isFreeUID(val: string) {
|
||||||
|
@ -192,6 +222,45 @@ export default defineComponent({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const imgsrc = ref();
|
||||||
|
|
||||||
|
const image = computed(() => {
|
||||||
|
if (imgsrc.value) {
|
||||||
|
return <string>imgsrc.value;
|
||||||
|
}
|
||||||
|
if (props.user.avatar_url && !deleteAvatar.value) {
|
||||||
|
return `${api.defaults.baseURL || ''}${props.user.avatar_url}`;
|
||||||
|
}
|
||||||
|
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 {
|
return {
|
||||||
allRoles,
|
allRoles,
|
||||||
avatar,
|
avatar,
|
||||||
|
@ -206,6 +275,13 @@ export default defineComponent({
|
||||||
reset,
|
reset,
|
||||||
save,
|
save,
|
||||||
userModel,
|
userModel,
|
||||||
|
image,
|
||||||
|
imagePreview,
|
||||||
|
clear,
|
||||||
|
deleteAvatar,
|
||||||
|
avatarError,
|
||||||
|
toDeleteAvatar,
|
||||||
|
error,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -65,14 +65,20 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabs: Tab[] = [
|
const tabs: Tab[] = [
|
||||||
{ name: 'user', label: 'Mitglieder', permissions: [PERMISSIONS.EDIT_OTHER, PERMISSIONS.SET_ROLES] },
|
{
|
||||||
|
name: 'user',
|
||||||
|
label: 'Mitglieder',
|
||||||
|
permissions: [PERMISSIONS.EDIT_OTHER, PERMISSIONS.SET_ROLES],
|
||||||
|
},
|
||||||
{ name: 'newUser', label: 'Neues Mitglied', permissions: [PERMISSIONS.SET_ROLES] },
|
{ name: 'newUser', label: 'Neues Mitglied', permissions: [PERMISSIONS.SET_ROLES] },
|
||||||
{ name: 'roles', label: 'Rollen', permissions: [PERMISSIONS.ROLES_EDIT] },
|
{ name: 'roles', label: 'Rollen', permissions: [PERMISSIONS.ROLES_EDIT] },
|
||||||
];
|
];
|
||||||
|
|
||||||
const _tabs = computed(() => tabs.filter(tab => {
|
const _tabs = computed(() =>
|
||||||
return tab.permissions.every(permission => hasPermission(permission))
|
tabs.filter((tab) => {
|
||||||
}))
|
return tab.permissions.every((permission) => hasPermission(permission));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const drawer = ref<boolean>(false);
|
const drawer = ref<boolean>(false);
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import { useMainStore, useUserStore, useSessionStore } from '@flaschengeist/api'
|
||||||
import MainUserSettings from '../components/settings/MainUserSettings.vue';
|
import MainUserSettings from '../components/settings/MainUserSettings.vue';
|
||||||
import { defineComponent, onBeforeMount, ref } from 'vue';
|
import { defineComponent, onBeforeMount, ref } from 'vue';
|
||||||
import Session from '../components/settings/Session.vue';
|
import Session from '../components/settings/Session.vue';
|
||||||
|
import { Notify } from 'quasar';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'UserSettings',
|
name: 'UserSettings',
|
||||||
|
@ -38,6 +39,14 @@ export default defineComponent({
|
||||||
|
|
||||||
async function updateUser(value: FG.User) {
|
async function updateUser(value: FG.User) {
|
||||||
await userStore.updateUser(value);
|
await userStore.updateUser(value);
|
||||||
|
Notify.create({
|
||||||
|
group: false,
|
||||||
|
type: 'positive',
|
||||||
|
message: 'Änderungen gespeichert',
|
||||||
|
timeout: 4000,
|
||||||
|
progress: true,
|
||||||
|
actions: [{ icon: 'mdi-close', color: 'white' }],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeSession(s: FG.Session) {
|
function removeSession(s: FG.Session) {
|
||||||
|
|
Loading…
Reference in New Issue