[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 | ||||
| yarn.lock | ||||
| 
 | ||||
| .idea | ||||
| 
 | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ import { defineComponent, ref, onMounted } from 'vue'; | |||
| import MainUserSettings from './settings/MainUserSettings.vue'; | ||||
| import UserSelector from './UserSelector.vue'; | ||||
| import { useMainStore, useUserStore } from '@flaschengeist/api'; | ||||
| import { Notify } from 'quasar'; | ||||
| 
 | ||||
| export default defineComponent({ | ||||
|   name: 'UpdateUser', | ||||
|  | @ -25,12 +26,20 @@ export default defineComponent({ | |||
|     const user = ref(mainStore.currentUser); | ||||
| 
 | ||||
|     onMounted(() => { | ||||
|       void userStore.getUsers(true) | ||||
|     }) | ||||
|       void userStore.getUsers(true); | ||||
|     }); | ||||
| 
 | ||||
|     async function updateUser(value: FG.User) { | ||||
|       await userStore.updateUser(value); | ||||
|       user.value = value; | ||||
|       Notify.create({ | ||||
|         group: false, | ||||
|         type: 'positive', | ||||
|         message: 'Änderungen gespeichert', | ||||
|         timeout: 4000, | ||||
|         progress: true, | ||||
|         actions: [{ icon: 'mdi-close', color: 'white' }], | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     return { | ||||
|  |  | |||
|  | @ -4,7 +4,12 @@ | |||
|       <div v-if="avatar" class="col-4"> | ||||
|         <div style="width: 100%; padding-bottom: 100%; position: relative"> | ||||
|           <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> | ||||
|         </div> | ||||
|       </div> | ||||
|  | @ -41,6 +46,7 @@ export default defineComponent({ | |||
|     const avatar = ref(true); | ||||
|     const name = ref(mainStore.currentUser.firstname); | ||||
|     const avatarLink = ref(mainStore.currentUser.avatar_url); | ||||
|     const avatarError = ref(false); | ||||
| 
 | ||||
|     function error() { | ||||
|       avatar.value = false; | ||||
|  | @ -65,7 +71,7 @@ export default defineComponent({ | |||
|         .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> | ||||
|  |  | |||
|  | @ -66,12 +66,22 @@ | |||
|         filled | ||||
|         label="Avatar" | ||||
|         accept=".jpg, image/*" | ||||
|         max-file-size="204800" | ||||
|         hint="Bilddateien, max. 200 KiB" | ||||
|         hint="Bilddateien nur JPEG" | ||||
|         :clearable="avatar.name !== '' || deleteAvatar" | ||||
|         @update:model-value="imagePreview" | ||||
|         @clear="clear" | ||||
|         @rejected="onAvatarRejected" | ||||
|       > | ||||
|         <template #append> | ||||
|           <q-icon name="mdi-file-image" @click.stop /> | ||||
|         <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" /> | ||||
|             </q-avatar> | ||||
|           </div> | ||||
|         </template> | ||||
|         <template #append v-if="!avatarError && !deleteAvatar"> | ||||
|           <q-btn round color="negative" icon="mdi-trash-can" size="xs" @click="toDeleteAvatar" /> | ||||
|         </template> | ||||
|       </q-file> | ||||
|     </q-card-section> | ||||
|  | @ -106,7 +116,14 @@ | |||
| import { Notify } from 'quasar'; | ||||
| import { IsoDateInput, PasswordInput } from '@flaschengeist/api/components'; | ||||
| 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({ | ||||
|   name: 'MainUserSettings', | ||||
|  | @ -131,13 +148,20 @@ export default defineComponent({ | |||
| 
 | ||||
|     const password = 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 canSetRoles = computed(() => hasPermission('users_set_roles')); | ||||
|     const allRoles = computed(() => userStore.roles.map((role) => role.name)); | ||||
|     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 */ | ||||
|     watchEffect(() => { | ||||
|       if (props.user.userid && props.user.userid !== userModel.value.userid) reset(); | ||||
|  | @ -152,11 +176,11 @@ export default defineComponent({ | |||
|         progress: true, | ||||
|         actions: [{ icon: 'mdi-close', color: 'white' }], | ||||
|       }); | ||||
|       avatar.value = undefined; | ||||
|       avatar.value = new File([], '', {}); | ||||
|     } | ||||
| 
 | ||||
|     function save() { | ||||
|       let changed = userModel.value; | ||||
|     async function save() { | ||||
|       let changed: FG.User = userModel.value; | ||||
|       if (typeof changed.birthday === 'string') changed.birthday = new Date(changed.birthday); | ||||
|       changed = Object.assign(changed, { | ||||
|         password: password.value, | ||||
|  | @ -169,20 +193,26 @@ export default defineComponent({ | |||
| 
 | ||||
|       emit('update:user', changed); | ||||
| 
 | ||||
|       if (avatar.value) | ||||
|         userStore | ||||
|       if (avatar.value instanceof File && 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) { | ||||
|         await userStore.deleteAvatar(changed); | ||||
|       } | ||||
|       password.value = ''; | ||||
|     } | ||||
| 
 | ||||
|     function reset() { | ||||
|       userModel.value = Object.assign({}, props.user); | ||||
|       password.value = ''; | ||||
|       newPassword.value = ''; | ||||
|       imgsrc.value = undefined; | ||||
|       deleteAvatar.value = false; | ||||
|     } | ||||
| 
 | ||||
|     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 { | ||||
|       allRoles, | ||||
|       avatar, | ||||
|  | @ -206,6 +275,13 @@ export default defineComponent({ | |||
|       reset, | ||||
|       save, | ||||
|       userModel, | ||||
|       image, | ||||
|       imagePreview, | ||||
|       clear, | ||||
|       deleteAvatar, | ||||
|       avatarError, | ||||
|       toDeleteAvatar, | ||||
|       error, | ||||
|     }; | ||||
|   }, | ||||
| }); | ||||
|  |  | |||
|  | @ -65,14 +65,20 @@ export default defineComponent({ | |||
|     } | ||||
| 
 | ||||
|     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: 'roles', label: 'Rollen', permissions: [PERMISSIONS.ROLES_EDIT] }, | ||||
|     ]; | ||||
| 
 | ||||
|     const _tabs = computed(() => tabs.filter(tab => { | ||||
|       return tab.permissions.every(permission => hasPermission(permission)) | ||||
|     })) | ||||
|     const _tabs = computed(() => | ||||
|       tabs.filter((tab) => { | ||||
|         return tab.permissions.every((permission) => hasPermission(permission)); | ||||
|       }) | ||||
|     ); | ||||
| 
 | ||||
|     const drawer = ref<boolean>(false); | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ import { useMainStore, useUserStore, useSessionStore } from '@flaschengeist/api' | |||
| import MainUserSettings from '../components/settings/MainUserSettings.vue'; | ||||
| import { defineComponent, onBeforeMount, ref } from 'vue'; | ||||
| import Session from '../components/settings/Session.vue'; | ||||
| import { Notify } from 'quasar'; | ||||
| 
 | ||||
| export default defineComponent({ | ||||
|   name: 'UserSettings', | ||||
|  | @ -38,6 +39,14 @@ export default defineComponent({ | |||
| 
 | ||||
|     async function updateUser(value: FG.User) { | ||||
|       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) { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue