Skip to content
Snippets Groups Projects
nav.ts 3.22 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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'
    
    type Route = {
      name: RouteRecordName
      params?: RouteParams
    }
    
    type MenuItem = {
      title: string
      route: Route
      requiresAdmin?: boolean
    }
    
    export type MenuItemCollection = {
      title: string
      items: MenuItem[]
    }
    
    type MenuItemCollectionGenerator = (
      route: RouteLocationNormalizedLoaded,
    ) => 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: RouteLocationNormalizedLoaded) {
      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: RouteLocationNormalizedLoaded) {
      if (!route.params.showId) return
      const showId = parseInt(route.params.showId as string)
      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 },
          },
          {
            title: t('navigation.show.basicData'),
            route: { name: 'show-basic-data', params: route.params },
          },
        ],
      }
    }
    
    function useNavigationData(...menuCollectionGenerators: MenuItemCollectionGenerator[]) {
      const route = useRoute()
      const menuItemCollections = ref<MenuItemCollection[]>([])
    
      watch(
        [route, () => route.params, () => route.name],
        async () => {
          const result: MenuItemCollection[] = []
          for (const generator of menuCollectionGenerators) {
            try {
              for await (const collection of generator(route)) {
                result.push(collection)
              }
            } catch (e) {
              // pass
            }
          }
          menuItemCollections.value = result
        },
        { immediate: true },
      )
    
      return shallowReadonly(menuItemCollections)
    }
    
    export function useMainNavigationData() {
      return useNavigationData(getMainNavigation, getEpisodeContextMenu, getShowContextMenu)
    }