Skip to content
Snippets Groups Projects
nav.ts 3.86 KiB
Newer Older
import { RouteLocationNormalizedLoaded, RouteParams, RouteRecordName, useRoute } from 'vue-router'
import { useShowStore } from '@/stores/shows'
import { useI18n } from '@/i18n'
import { useTimeSlotStore } from '@/stores/timeslots'
import { parseISO } from 'date-fns'
import { ref, shallowReadonly, watch } from 'vue'
import { useSelectedShow } from '@/util'
import { Show } from '@/types'

type Route = {
  name: RouteRecordName
  params?: RouteParams
}

type MenuItem = {
  title: string
  route: Route
  requiresAdmin?: boolean
}

export type MenuItemCollection = {
  title: string
  items: MenuItem[]
}

type MenuItemCollectionGeneratorOptions = {
  route: RouteLocationNormalizedLoaded
  selectedShow: Show | null
}

type MenuItemCollectionGenerator = (
  options: MenuItemCollectionGeneratorOptions,
) => AsyncGenerator<MenuItemCollection, void, unknown>

async function* getMainNavigation() {
  const { t } = useI18n()
  yield {
    title: t('navigation'),
    items: [
      {
        title: t('navigation.shows'),
        route: { name: 'shows' },
      },
      {
        title: t('navigation.filesPlaylists'),
        route: { name: 'files' },
      },
      {
        title: t('navigation.calendar'),
        route: { name: 'calendar' },
      },
    ],
  }
}

async function* getEpisodeContextMenu({
  route,
}: MenuItemCollectionGeneratorOptions): AsyncGenerator<MenuItemCollection, void, unknown> {
  if (!route.params.episodeId) return
  const episodeId = parseInt(route.params.episodeId as string)
  const timeslotStore = useTimeSlotStore()
  const timeslot = await timeslotStore.retrieve(episodeId, { useCached: true })
  if (!timeslot) return
  const { t } = useI18n()
  const start = parseISO(timeslot.start).toLocaleString()

  yield {
    title: t('navigation.episode._title', { start }),
    items: [
      {
        title: t('navigation.episode.description'),
        route: { name: 'show-episode-description', params: route.params },
      },
      {
        title: t('navigation.episode.playlist'),
        route: { name: 'show-episode-playlist', params: route.params },
      },
    ],
  }
}

async function* getShowContextMenu({
  route,
  selectedShow,
}: MenuItemCollectionGeneratorOptions): AsyncGenerator<MenuItemCollection, void, unknown> {
  if (!route.params.showId && !selectedShow) return
  const showId = route.params.showId
    ? parseInt(route.params.showId as string)
    : (selectedShow?.id as number)
  const showStore = useShowStore()
  const show = await showStore.retrieve(showId, { useCached: true })
  if (!show) return
  const { t } = useI18n()

  yield {
    title: show.name,
    items: [
      {
        title: t('navigation.show.episodes'),
        route: { name: 'show-episodes', params: { ...route.params, showId: showId.toString() } },
      },
      {
        title: t('navigation.show.basicData'),
        route: { name: 'show-basic-data', params: { ...route.params, showId: showId.toString() } },
      },
    ],
  }
}

function useNavigationData(...menuCollectionGenerators: MenuItemCollectionGenerator[]) {
  const route = useRoute()
  const selectedShow = useSelectedShow()
  const menuItemCollections = ref<MenuItemCollection[]>([])

  watch(
    [route, () => route.params, () => route.name, selectedShow],
    async () => {
      const result: MenuItemCollection[] = []
      for (const generator of menuCollectionGenerators) {
        try {
          const collections = generator({
            route,
            selectedShow: selectedShow.value ?? null,
          })
          for await (const collection of collections) {
            result.push(collection)
          }
        } catch (e) {
          // pass
        }
      }
      menuItemCollections.value = result
    },
    { immediate: true },
  )

  return shallowReadonly(menuItemCollections)
}

export function useMainNavigationData() {
  return useNavigationData(getMainNavigation, getEpisodeContextMenu, getShowContextMenu)
}