Skip to content
Snippets Groups Projects
ShowBasicData.vue 14.7 KiB
Newer Older
  • Learn to ignore specific revisions
  •     <PageHeader
          :title="t('navigation.show.basicData')"
          :lead="show.name"
          :editing-metadata="show"
        />
    
          class="tw-grid tw-gap-6 tw-items-start tw-grid-cols-1 xl:tw-grid-cols-2 2xl:tw-grid-cols-3 tw-mb-6 tw-max-w-[1600px]"
    
        >
          <AFieldset
            class="tw-bg-white tw-col-span-full 2xl:tw-col-span-2"
            :title="t('show.section.basic.title')"
    
            <FormGroup
              v-slot="attrs"
              :label="t('show.fields.name')"
              :is-saving="name.isSaving"
              :errors="name.errors"
              class="tw-col-span-2"
    
              edit-permissions="edit__show__name"
    
            >
              <input v-bind="attrs" v-model="name.value" type="text" @blur="name.save" />
              <ADescription class="tw-text-xs">
                <span>{{ t('show.slugDetail.title') }}: </span>
                <code
                  class="tw-text-inherit tw-bg-gray-200 tw-px-2 tw-py-1 tw-rounded tw-text-gray-500"
                >
                  {{ show.slug }}
                </code>
                <br />
                <SafeHTML
                  :html="
                    t('show.slugDetail.editRemark', {
                      dangerZone: t('show.housekeeping.title'),
                      dangerZoneId: 'danger-zone',
                    })
                  "
                  sanitize-preset="safe-html"
                />
              </ADescription>
            </FormGroup>
    
            <FormGroup
    
              v-slot="{ id, disabled }"
    
              :label="t('show.fields.shortDescription')"
              :is-saving="shortDescription.isSaving"
              :errors="shortDescription.errors"
              class="tw-col-span-2"
    
              edit-permissions="edit__show__short_description"
    
              <AHTMLEditor
                :id="id"
                v-model="shortDescription.value"
                :disabled="disabled"
                @blur="shortDescription.save()"
              />
    
              v-slot="{ id, disabled }"
    
              :label="t('show.fields.description')"
              :is-saving="description.isSaving"
              :errors="description.errors"
    
              edit-permissions="edit__show__description"
    
              class="tw-col-span-2"
              custom-control
            >
    
              <AHTMLEditor
                :id="id"
                v-model="description.value"
                :disabled="disabled"
                @blur="shortDescription.save()"
              />
    
            </FormGroup>
    
            <div class="tw-flex tw-gap-6 tw-flex-wrap">
              <FormGroup
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
                :label="t('show.fields.logoId')"
    
                :errors="logoId.errors"
                :is-saving="logoId.isSaving"
                class="tw-mb-0"
                custom-control
              >
                <template #default="attrs">
                  <div>
                    <ImagePicker v-model="logoId.value" v-bind="attrs" />
                  </div>
                </template>
              </FormGroup>
    
              <FormGroup
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
                :label="t('show.fields.imageId')"
    
                :errors="imageId.errors"
                :is-saving="imageId.isSaving"
                custom-control
              >
                <template #default="attrs">
                  <div>
                    <ImagePicker v-model="imageId.value" v-bind="attrs" />
                  </div>
                </template>
              </FormGroup>
            </div>
          </AFieldset>
    
          <AFieldset class="tw-bg-white" :title="t('show.section.content.title')">
            <FormGroup
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              :label="t('show.fields.categoryIds')"
    
              custom-control
              :is-saving="categories.isSaving"
    
            >
              <ComboBoxSimple v-model="categories.value" :choices="categories.choices">
                <template #selected="{ deselect }">
                  <Tag
                    v-for="category in categories.value"
                    :key="category.id"
                    removable
                    @remove="deselect(category)"
                  >
                    <span>
                      <span class="tw-block">{{ category.name }}</span>
                      <span v-if="category.subtitle.trim()" class="tw-text-xs">
                        {{ category.subtitle }}
                      </span>
                    </span>
                  </Tag>
                </template>
              </ComboBoxSimple>
            </FormGroup>
    
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              :label="t('show.fields.topicIds')"
    
              custom-control
              :is-saving="topics.isSaving"
              :errors="topics.errors"
            >
    
              <ComboBoxSimple v-model="topics.value" :choices="topics.choices" />
            </FormGroup>
    
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              :label="t('show.fields.musicFocusIds')"
    
              custom-control
              :is-saving="musicFocuses.isSaving"
              :errors="musicFocuses.errors"
            >
    
              <ComboBoxSimple v-model="musicFocuses.value" :choices="musicFocuses.choices" />
            </FormGroup>
    
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              :label="t('show.fields.languageIds')"
    
              custom-control
              :is-saving="languages.isSaving"
              :errors="languages.errors"
            >
    
              <ComboBoxSimple v-model="languages.value" :choices="languages.choices" />
            </FormGroup>
    
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
            <FormGroup
              :label="t('show.fields.typeId')"
              :errors="type.errors"
              :is-saving="type.isSaving"
            >
    
              <template #default="attrs">
                <select v-model="type.valueId" v-bind="attrs">
                  <option
                    v-for="choice in type.choices"
                    :key="choice.id"
                    :value="choice.id"
                    :label="choice.name"
                    :disabled="!choice.isActive"
                  />
                </select>
              </template>
            </FormGroup>
          </AFieldset>
    
          <AFieldset class="tw-bg-white" :title="t('show.section.contact.title')">
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
            <FormGroup
              :label="t('show.fields.email')"
              :errors="email.errors"
              :is-saving="email.isSaving"
            >
    
              <template #default="attrs">
                <input v-model="email.value" type="email" v-bind="attrs" @blur="email.save" />
              </template>
            </FormGroup>
    
            <FormGroup
              :label="t('show.fields.links')"
              :is-saving="links.isSaving"
    
              :errors="links.errors.forField('links', '')"
    
              :has-error="links.errors.length > 0"
              custom-control
            >
              <ALinkCollectionEditor
                v-model="links.value"
    
                :error-lists="links.errors.siblings('links')"
    
                allow-add
                @save="links.save()"
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              :label="t('show.fields.hostIds')"
    
              custom-control
              :is-saving="hosts.isSaving"
              :errors="hosts.errors"
            >
    
              <ComboBoxSimple v-model="hosts.value" :choices="hosts.choices" />
            </FormGroup>
    
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              :label="t('show.fields.ownerIds')"
    
              class="tw-order-last"
              :is-saving="owners.isSaving"
              :errors="owners.errors"
            >
    
              <ComboBoxSimple
                v-model="owners.value"
                :disabled="!authStore.isSuperuser"
                :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 @remove="deselect(user)" />
                  </template>
                </template>
              </ComboBoxSimple>
            </FormGroup>
          </AFieldset>
    
          <AFieldset class="tw-bg-white" :title="t('show.section.administrative.title')">
            <FormGroup
              v-slot="attrs"
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              :label="t('show.fields.fundingCategoryId')"
    
              :errors="fundingCategory.errors"
              :is-saving="fundingCategory.isSaving"
            >
              <select v-model="fundingCategory.valueId" v-bind="attrs">
                <option
                  v-for="choice in fundingCategory.choices"
                  :key="choice.id"
                  :value="choice.id"
                  :label="choice.name"
                  :disabled="!choice.isActive"
                />
              </select>
            </FormGroup>
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              :label="t('show.fields.cbaSeriesId')"
    
              :errors="cbaSeriesId.errors"
              :is-saving="cbaSeriesId.isSaving"
            >
              <template #default="attrs">
                <input
                  v-model="cbaSeriesId.value"
                  type="text"
                  inputmode="numeric"
                  pattern="[0-9]+"
                  v-bind="attrs"
                  @blur="cbaSeriesId.save"
                />
              </template>
            </FormGroup>
    
            <FormGroup
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              :label="t('show.fields.predecessorId')"
    
              :errors="predecessor.errors"
              :is-saving="predecessor.isSaving"
            >
              <template #default="attrs">
                <select v-model="predecessor.valueId" v-bind="attrs">
                  <option
                    v-for="choice in predecessor.choices"
                    :key="choice.id"
                    :value="choice.id"
                    :label="sanitizeHTML(choice.name)"
                    :disabled="!choice.isActive"
                  />
                </select>
              </template>
            </FormGroup>
    
            <template v-if="authStore.isSuperuser">
              <FormGroup
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
                :label="t('show.fields.internalNote')"
    
                :errors="internalNote.errors"
                class="md:tw-col-span-2 tw-order-last"
                :is-saving="internalNote.isSaving"
              >
                <template #default="attrs">
                  <textarea
                    ref="internalNoteEl"
                    v-model="internalNote.value"
                    class="tw-min-h-[100px]"
                    v-bind="attrs"
                    @blur="internalNote.save"
                  />
                </template>
              </FormGroup>
            </template>
          </AFieldset>
    
    
          <AFieldset :title="t('show.section.media.title')" class="tw-bg-white">
            <FormGroup :errors="playlistId.errors">
              <APlaylistEditor
                :playlist="playlist"
                :show="show"
                :use-expert-mode="true"
                class="tw-max-w-3xl"
                @create="playlistId.value = $event.id"
              />
            </FormGroup>
          </AFieldset>
    
    
          <AHousekeeping :show="show" class="tw-col-span-full" />
        </div>
    
        <p class="tw-text-sm">
          <ATimeEditInfo
            v-if="show.updatedAt"
            :edit-info="{ time: show.updatedAt, author: show.updatedBy }"
            type="modified"
          />
          <br />
          <ATimeEditInfo :edit-info="{ time: show.createdAt, author: show.createdBy }" type="created" />
        </p>
    
      </div>
    </template>
    
    <script lang="ts" setup>
    
    import { useObjectFromStore } from '@rokoli/bnb/drf'
    
    import { useTextareaAutosize } from '@vueuse/core'
    
    import { computed } from 'vue'
    
    
    import { useI18n } from '@/i18n'
    import { Show } from '@/types'
    
    import { useAPIObjectFieldCopy, useRelation, useRelationList } from '@/form'
    
    import {
      useAuthStore,
      useCategoryStore,
      useFundingCategoryStore,
      useHostStore,
      useLanguageStore,
      useMusicFocusStore,
    
      useShowStore,
      useTopicStore,
      useTypeStore,
      useUserStore,
    } from '@/stores'
    
    import { useBreadcrumbs } from '@/stores/nav'
    
    import { SteeringUser } from '@/stores/auth'
    import { sanitizeHTML } from '@/util'
    
    import PageHeader from '@/components/PageHeader.vue'
    
    import ATimeEditInfo from '@/components/generic/ATimeEditInfo.vue'
    
    import FormGroup from '@/components/generic/FormGroup.vue'
    import AHousekeeping from '@/components/shows/AHousekeeping.vue'
    
    import ADescription from '@/components/generic/ADescription.vue'
    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'
    
    const props = defineProps<{
    
      show: Show
    }>()
    
    const { t } = useI18n()
    
    const authStore = useAuthStore()
    const userStore = useUserStore()
    
    const showStore = useShowStore()
    
    const typeStore = useTypeStore()
    const categoryStore = useCategoryStore()
    const topicStore = useTopicStore()
    const musicFocusStore = useMusicFocusStore()
    const languageStore = useLanguageStore()
    const hostStore = useHostStore()
    const fundingCategoryStore = useFundingCategoryStore()
    
    const playlistStore = usePlaylistStore()
    
    
    const show = computed(() => props.show)
    
    const name = useAPIObjectFieldCopy(showStore, show, 'name', { debounce: 2 })
    const shortDescription = useAPIObjectFieldCopy(showStore, show, 'shortDescription', { debounce: 2 })
    const description = useAPIObjectFieldCopy(showStore, show, 'description', { debounce: 2 })
    
    const links = useAPIObjectFieldCopy(showStore, show, 'links', { debounce: 2 })
    
    const email = useAPIObjectFieldCopy(showStore, show, 'email', { debounce: 2 })
    const cbaSeriesId = useAPIObjectFieldCopy(showStore, show, 'cbaSeriesId', { debounce: 2 })
    const internalNote = useAPIObjectFieldCopy(showStore, show, 'internalNote', { debounce: 2 })
    const type = useRelation(showStore, show, 'typeId', typeStore)
    const fundingCategory = useRelation(showStore, show, 'fundingCategoryId', fundingCategoryStore)
    const predecessor = useRelation(showStore, show, 'predecessorId', showStore)
    const categories = useRelationList(showStore, show, 'categoryIds', categoryStore)
    const topics = useRelationList(showStore, show, 'topicIds', topicStore)
    const languages = useRelationList(showStore, show, 'languageIds', languageStore)
    const hosts = useRelationList(showStore, show, 'hostIds', hostStore)
    const musicFocuses = useRelationList(showStore, show, 'musicFocusIds', musicFocusStore)
    
    const logoId = useAPIObjectFieldCopy(showStore, show, 'logoId', { debounce: 0 })
    const imageId = useAPIObjectFieldCopy(showStore, show, 'imageId', { debounce: 0 })
    
    const owners = useRelationList(showStore, () => props.show, 'ownerIds', userStore, {
      sortBy: ['lastName', 'firstName', 'username', 'email'],
    })
    
    
    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() } } },
      t('navigation.show.basicData'),
    ])
    
    
    const { textarea: internalNoteEl } = useTextareaAutosize({
      input: computed(() => internalNote.value),
    })