From bdf509d26d483429df4aaf8996b17654da6346d5 Mon Sep 17 00:00:00 2001 From: Konrad Mohrfeldt <km@roko.li> Date: Thu, 30 May 2024 11:18:49 +0200 Subject: [PATCH] refactor: move user selector into separate component --- src/Pages/ShowBasicData.vue | 27 +------------ .../AUserPreview.vue} | 4 +- src/components/identities/AUserSelector.vue | 39 +++++++++++++++++++ src/i18n/de.js | 8 ++-- src/i18n/en.js | 8 ++-- 5 files changed, 53 insertions(+), 33 deletions(-) rename src/components/{UserPreview.vue => identities/AUserPreview.vue} (90%) create mode 100644 src/components/identities/AUserSelector.vue diff --git a/src/Pages/ShowBasicData.vue b/src/Pages/ShowBasicData.vue index 5da93da4..542c741c 100644 --- a/src/Pages/ShowBasicData.vue +++ b/src/Pages/ShowBasicData.vue @@ -246,22 +246,7 @@ :errors="owners.errors" edit-permissions="program.edit__show__owners" > - <ComboBoxSimple - v-model="owners.value" - :disabled="disabled" - :search-provider="searchUsers" - > - <template #default="{ choice, ...itemAttrs }"> - <li v-bind="itemAttrs"> - <UserPreview :user="choice as SteeringUser" transparent /> - </li> - </template> - <template #selected="{ deselect }"> - <template v-for="user in owners.value" :key="user.id"> - <UserPreview :user="user" :removable="!disabled" @remove="deselect(user)" /> - </template> - </template> - </ComboBoxSimple> + <AUserSelector v-model="owners.value" :disabled="disabled" /> </FormGroup> </AFieldset> @@ -395,7 +380,6 @@ import { useUserStore, } from '@/stores' import { useBreadcrumbs } from '@/stores/nav' -import { SteeringUser } from '@/stores/auth' import { sanitizeHTML } from '@/util' import PageHeader from '@/components/PageHeader.vue' @@ -408,11 +392,11 @@ import SafeHTML from '@/components/generic/SafeHTML' import ALinkCollectionEditor from '@/components/generic/ALinkCollectionEditor.vue' import AHTMLEditor from '@/components/generic/AHTMLEditor.vue' import ComboBoxSimple from '@/components/ComboBoxSimple.vue' -import UserPreview from '@/components/UserPreview.vue' import Tag from '@/components/generic/Tag.vue' import ImagePicker from '@/components/images/ImagePicker.vue' import AFieldset from '@/components/generic/AFieldset.vue' import APlaylistEditor from '@/components/playlist/APlaylistEditor.vue' +import AUserSelector from '@/components/identities/AUserSelector.vue' const props = defineProps<{ show: Show @@ -455,13 +439,6 @@ const owners = useRelationList(showStore, () => props.show, 'ownerIds', userStor const { obj: playlist } = useObjectFromStore(() => props.show.defaultPlaylistId, playlistStore) const playlistId = useAPIObjectFieldCopy(showStore, show, 'defaultPlaylistId', { debounce: 0 }) -function searchUsers(query: string, signal: AbortSignal) { - return userStore.list({ - query: new URLSearchParams({ search: query }), - requestInit: { signal }, - }) -} - useBreadcrumbs(() => [ { title: t('navigation.shows'), route: { name: 'shows' } }, { title: props.show.name, route: { name: 'show', params: { showId: props.show.id.toString() } } }, diff --git a/src/components/UserPreview.vue b/src/components/identities/AUserPreview.vue similarity index 90% rename from src/components/UserPreview.vue rename to src/components/identities/AUserPreview.vue index 7b4b7cac..c9ad448d 100644 --- a/src/components/UserPreview.vue +++ b/src/components/identities/AUserPreview.vue @@ -4,11 +4,11 @@ :class="{ 'tw-bg-gray-100': !transparent }" > <span> - <span :aria-label="t('user.username')" class="tw-font-bold tw-block"> + <span :aria-label="t('user.fields.username')" class="tw-font-medium tw-block"> {{ user.username }} </span> <span class="empty:tw-hidden tw-opacity-80 tw-text-xs"> - <span v-if="name" class="tw-block" :aria-label="t('user.name')">{{ name }}</span> + <span v-if="name" class="tw-block" :aria-label="t('user.fields.name')">{{ name }}</span> <span v-if="user.email" class="tw-block">{{ user.email }}</span> </span> </span> diff --git a/src/components/identities/AUserSelector.vue b/src/components/identities/AUserSelector.vue new file mode 100644 index 00000000..b392a64d --- /dev/null +++ b/src/components/identities/AUserSelector.vue @@ -0,0 +1,39 @@ +<template> + <ComboBoxSimple v-model="modelValue" :search-provider="searchUsers" v-bind="props"> + <template #default="{ choice, ...itemAttrs }"> + <li v-bind="itemAttrs"> + <AUserPreview :user="choice as SteeringUser" transparent /> + </li> + </template> + <template #selected="{ deselect, value }"> + <template + v-for="user in ensureArray(value as null | SteeringUser | SteeringUser[])" + :key="user.id" + > + <AUserPreview :user="user" :removable="!props.disabled" @remove="deselect(user)" /> + </template> + </template> + </ComboBoxSimple> +</template> + +<script setup lang="ts"> +import { SteeringUser, useUserStore } from '@/stores/auth' +import ComboBoxSimple, { ComboBoxSimpleProps } from '@/components/ComboBoxSimple.vue' +import AUserPreview from './AUserPreview.vue' + +const modelValue = defineModel<null | SteeringUser | SteeringUser[]>({ required: true }) +const props = defineProps<Omit<ComboBoxSimpleProps<SteeringUser>, 'choices' | 'searchProvider'>>() +const userStore = useUserStore() + +function searchUsers(query: string, signal: AbortSignal) { + return userStore.list({ + query: new URLSearchParams({ search: query }), + requestInit: { signal }, + }) +} + +function ensureArray(value: null | SteeringUser | SteeringUser[]) { + if (value === null) return [] + return Array.isArray(value) ? value : [value] +} +</script> diff --git a/src/i18n/de.js b/src/i18n/de.js index 975c8bdc..b1854cfa 100644 --- a/src/i18n/de.js +++ b/src/i18n/de.js @@ -420,9 +420,11 @@ export default { }, user: { - username: 'Benutzername', - name: 'Name', - email: 'E-Mail', + fields: { + username: 'Benutzername', + name: 'Name', + email: 'E-Mail', + }, }, noteEditor: { diff --git a/src/i18n/en.js b/src/i18n/en.js index 921cb608..da3cec04 100644 --- a/src/i18n/en.js +++ b/src/i18n/en.js @@ -421,9 +421,11 @@ export default { }, user: { - username: 'Username', - name: 'Name', - email: 'Email', + fields: { + username: 'Username', + name: 'Name', + email: 'Email', + }, }, noteEditor: { -- GitLab