import { StorageSerializers, useStorage } from '@vueuse/core' import { APICreate, APIListPaginated, APIListUnpaginated, APIRemove, APIRetrieve, APIUpdate, createExtendableAPI, ExtendableAPI, } from '@rokoli/bnb/drf' import { defineStore } from 'pinia' import { computed, Ref, watch } from 'vue' import { useStore } from 'vuex' import { useRoute, useRouter } from 'vue-router' import { createSteeringURL } from '@/api' import { components } from '@/steering-types' import { steeringAuthInit, useAuthStore, useOnAuthBehaviour } from '@/stores/auth' import { KeysFrom, Show } from '@/types' type ReadonlyAttrs = KeysFrom<Show, 'id' | 'createdAt' | 'createdBy' | 'updatedAt' | 'updatedBy'> type ShowCreateData = Omit<Show, ReadonlyAttrs> type ShowUpdateData = ShowCreateData type ShowPartialUpdateData = components['schemas']['PatchedShow'] export type NewShow = ShowCreateData export function newShow(): NewShow { return { name: '', slug: '', description: '', shortDescription: '', email: '', internalNote: '', typeId: -1, fundingCategoryId: -1, isActive: true, isPublic: true, predecessorId: null, defaultPlaylistId: null, cbaSeriesId: null, imageId: null, logoId: null, links: [], topicIds: [], categoryIds: [], musicFocusIds: [], ownerIds: [], hostIds: [], languageIds: [], } } function useSelectedShowBehaviour(api: ExtendableAPI<Show>) { const authStore = useAuthStore() const { retrieve } = APIRetrieve(api) const selectedShowId = useStorage<number | null>('aura:selected-show', null, undefined, { serializer: StorageSerializers.number, }) const selectedShow = computed(() => selectedShowId.value !== null ? api.itemMap.value.get(selectedShowId.value) ?? null : null, ) // Ensure that we always have the currently selected show in the store watch( [selectedShowId, () => authStore.currentUser], ([showId, user]) => { if (showId && user) void retrieve(showId, { useCached: true }) }, { immediate: true }, ) return { selectedShowId, selectedShow } } function useLegacyVuexStoreSyncBehaviour( shows: Ref<Show[]>, selectedShowId: Ref<Show['id'] | null>, selectedShow: Ref<Show | null>, ) { const authStore = useAuthStore() const store = useStore() watch(shows, (newShows) => { store.commit('shows/setShows', newShows) }) // updated selected show in legacy vuex store when changed in pinia story watch(selectedShowId, (newShowId) => { store.commit('shows/switchShowById', newShowId) }) // updated selected show in pinia store when changed in legacy vuex store watch( () => store.state.shows.selected.id, (newId) => { if (newId !== selectedShowId.value) { selectedShowId.value = newId } }, ) // fetch playlists when a show is selected watch( [() => selectedShow.value?.slug, () => authStore.currentUser], ([showSlug, user], [oldShowSlug]) => { if (showSlug && user && showSlug !== oldShowSlug) { void store.dispatch('playlists/fetch', { showSlug }) } }, { immediate: true }, ) } function useRouteSyncBehaviour( selectedShowId: Ref<Show['id'] | null>, selectedShow: Ref<Show | null>, ) { const route = useRoute() const router = useRouter() // watch changes to the selected show and apply them to the current route // so that fast context switches between multiple shows on show editor pages are possible watch(selectedShow, (show, oldShow) => { if (!oldShow) return const newShowId = show?.id ?? null const oldShowId = oldShow?.id ?? null if (newShowId === oldShowId) return if (show && route.name && route.params.showId) { void router.replace({ name: route.name, params: { ...route.params, showId: newShowId } }) } }) // Change the selected show if the user accessed a route for a particular show. // This is made so the show selector and the current route don’t have mismatching shows, which may cause confusion. watch( () => route.params.showId, (showId) => { if (showId) { selectedShowId.value = parseInt(showId as string) } }, { immediate: true }, ) } export const useShowStore = defineStore('shows', () => { const endpoint = createSteeringURL.prefix('shows') const { api, base } = createExtendableAPI<Show>(endpoint, steeringAuthInit) const { selectedShow, selectedShowId } = useSelectedShowBehaviour(api) useRouteSyncBehaviour(selectedShowId, selectedShow) // TODO: remove once we get rid of the Vuex stores useLegacyVuexStoreSyncBehaviour(base.items, selectedShowId, selectedShow) // Make sure the store contains a list of all shows, which are // required on a number of pages and in the show selector. useOnAuthBehaviour(() => void APIListUnpaginated(api).list()) return { ...base, ...APIListPaginated(api), ...APIRetrieve(api), ...APICreate<Show, ShowCreateData>(api), ...APIUpdate<Show, ShowUpdateData, ShowPartialUpdateData>(api), ...APIRemove(api), selectedShowId, selectedShow, } })