import axios from 'axios' import { APIError, callOrReturn, handleApiError } from '../api-helper' import { getISODateString, has } from '@/utilities' import { createSteeringURL } from '@/api' import decamelize from 'decamelize' const cloneMinimalShowObject = function (show) { /* returns a new minimal object from the current show object with all properties needed for a PUT request to the /show/ endpoint */ return { name: show.name, slug: show.slug, shortDescription: show.shortDescription, fundingCategoryId: show.fundingCategoryId, typeId: show.typeId, categoryIds: Array.from(show.categoryIds), hostIds: Array.from(show.hostIds), ownerIds: Array.from(show.ownerIds), languageIds: Array.from(show.languageIds), topicIds: Array.from(show.topicIds), musicFocusIds: Array.from(show.musicFocusIds), } } const state = { shows: [], schedule: null, schedules: [], scheduleTimeslots: [], timeslots: [], types: [], fundingCategories: [], categories: [], topics: [], musicFocus: [], languages: [], hosts: [], loaded: { shows: true, timeslots: false, schedule: false, scheduleTimeslots: false, schedules: false, types: false, fundingCategories: false, categories: false, topics: false, musicFocus: false, languages: false, hosts: false, }, selected: { index: 0, // index of the currently selected show in our shows array id: 0, // actual id of the currently selected show }, } const getters = { shows: (state) => state.shows, selectedShow: (state) => state.shows[state.selected.index], schedule: (state) => state.schedule, schedules: (state) => state.schedules, scheduleTimeslots: (state) => state.scheduleTimeslots, timeslots: (state) => state.timeslots, types: (state) => state.types, fundingCategories: (state) => state.fundingCategories, categories: (state) => state.categories, topics: (state) => state.topics, musicFocus: (state) => state.musicFocus, languages: (state) => state.languages, hosts: (state) => state.hosts, getShowByDataParam: (state) => (data) => { let show if (data.id !== undefined) { show = state.shows.find((s) => s.id === data.id) if (show === undefined) { console.error('getShowByDataParam: ID not found in store!') } } else if (data.index !== undefined) { show = state.shows[data.index] } else { console.error('getShowByDataParam: no ID or index was provided') } return show }, getTimeslotById: (state) => (id) => { return state.timeslots.find((s) => s.id === id) }, } const mutations = { loading(state, item) { state.loaded[item] = false }, finishLoading(state, item) { state.loaded[item] = true }, setShows(state, shows) { state.shows = shows }, replaceShow(state, show) { const index = state.shows.findIndex(({ id }) => id === show.id) if (index !== -1) { state.shows.splice(index, 1, show) } else { state.shows.push(show) } state.shows.sort((a, b) => a.name.toLowerCase() > b.name.toLowerCase()) }, addShow(state, show) { state.shows.push(show) state.shows.sort((a, b) => a.name.toLowerCase() > b.name.toLowerCase()) }, setSchedule(state, schedule) { state.schedule = schedule }, setSchedules(state, schedules) { state.schedules = schedules }, setScheduleTimeslots(state, slots) { state.scheduleTimeslots = slots }, setTimeslots(state, slots) { state.timeslots = slots }, setTimeslot(state, slot) { const index = state.timeslots.findIndex((s) => s.id === slot.id) state.timeslots.splice(index, 1, slot) }, setName(state, data) { const index = state.shows.findIndex((s) => s.id === data.id) state.shows[index].name = data.text }, setShortDescription(state, data) { const index = state.shows.findIndex((s) => s.id === data.id) state.shows[index].shortDescription = data.text }, setDescription(state, data) { const index = state.shows.findIndex((s) => s.id === data.id) state.shows[index].description = data.text }, setActive(state, data) { const index = state.shows.findIndex((s) => s.id === data.id) state.shows[index].isActive = data.active }, setProperty(state, data) { const index = state.shows.findIndex((s) => s.id === data.id) state.shows[index][data.property] = data.value }, setMetaArray(state, data) { state[data.property] = data.value }, switchShow(state, index) { if (state.loaded.shows) { state.selected.index = index state.selected.id = state.shows[index].id } }, switchShowById(state, id) { if (state.loaded.shows) { state.selected.index = state.shows.findIndex((s) => s.id === id) state.selected.id = id } }, } const actions = { fetchSchedule(ctx, data) { ctx.commit('loading', 'schedule') const uri = createSteeringURL('shows', data.showId, 'schedules', data.scheduleId) axios .get(uri) .then((response) => { ctx.commit('setSchedule', response.data) ctx.commit('finishLoading', 'schedule') if (data && typeof data.callback === 'function') { data.callback(response) } }) .catch((error) => { handleApiError(this, error, 'could not load schedule') if (data && typeof data.callbackCancel === 'function') { data.callbackCancel() } }) }, fetchSchedules(ctx, data) { ctx.commit('loading', 'schedule') const uri = createSteeringURL('shows', data.showId, 'schedules') axios .get(uri) .then((response) => { ctx.commit('setSchedules', response.data) ctx.commit('finishLoading', 'schedule') if (data && typeof data.callback === 'function') { data.callback(response) } }) .catch((error) => { handleApiError(this, error, 'could not load schedule') if (data && typeof data.callbackCancel === 'function') { data.callbackCancel() } }) }, fetchTimeslots(ctx, data) { if (data.scheduleId !== undefined) { ctx.commit('loading', 'scheduleTimeslots') } else { ctx.commit('loading', 'timeslots') } const query = new URLSearchParams() if (data.surrounding) { const date = data.surrounding instanceof Date ? data.surrounding : new Date() query.set('surrounding', getISODateString(date)) } else { if (data?.start) query.set('startsAfter', `${data.start}T00:00:00`) if (data?.startsBefore) query.set('startsBefore', data.startsBefore) if (data?.startsAfter) query.set('startsAfter', data.startsAfter) if (data?.end) query.set('endsBefore', `${data.end}T23:59:59`) if (data?.endsBefore) query.set('endsBefore', data.endsBefore) if (data?.endsAfter) query.set('endsAfter', data.endsAfter) if (has(data, 'limit')) query.set('limit', data.limit) if (has(data, 'offset')) query.set('offset', data.offset) } const uri = data.id && data.scheduleId ? createSteeringURL('shows', data.id, 'schedules', data.scheduleId, 'timeslots', query) : data.id ? createSteeringURL('shows', data.id, 'timeslots', query) : createSteeringURL('timeslots', query) axios .get(uri) .then((response) => { if (data.scheduleId !== undefined) { ctx.commit('setScheduleTimeslots', response.data) ctx.commit('finishLoading', 'scheduleTimeslots') } else { if (data.limit) { ctx.commit('setTimeslots', response.data.results) } else { ctx.commit('setTimeslots', response.data) } ctx.commit('finishLoading', 'timeslots') } if (data && typeof data.callback === 'function') { data.callback(response) } }) .catch((error) => { handleApiError(this, error, 'could not load timeslots') if (data && typeof data.callbackCancel === 'function') { data.callbackCancel() } }) }, fetchMetaArray(ctx, data) { ctx.commit('loading', data.property) const subPath = decamelize(data.property, { separator: '-' }) let uri = createSteeringURL(subPath) if (data.onlyActive === true) { uri += '?isActive=true' } axios .get(uri) .then((response) => { ctx.commit('setMetaArray', { property: data.property, value: response.data }) ctx.commit('finishLoading', data.property) if (data && typeof data.callback === 'function') { data.callback() } }) .catch((error) => { handleApiError(this, error, 'could not load ' + data.property) if (data && typeof data.callbackCancel === 'function') { data.callbackCancel() } }) }, submitSchedule(ctx, data) { ctx.commit('loading', 'schedules') const uri = createSteeringURL('shows', data.showId, 'schedules') return axios .post(uri, data.schedule) .then((response) => { ctx.commit('finishLoading', 'schedules') return callOrReturn(response, data?.callback) }) .catch((error) => { APIError.handle(error, 'Unable to submit schedule', data, this) }) }, submitShow(ctx, data) { const uri = createSteeringURL('shows') axios .post(uri, data.show) .then((response) => { ctx.commit('addShow', response.data) if (data && typeof data.callback === 'function') { data.callback(response) } }) .catch((error) => { handleApiError(this, error, 'could not add new show') if (data && typeof data.callbackCancel === 'function') { data.callbackCancel() } }) }, updateShow(ctx, data) { const uri = createSteeringURL('shows', data.id) return axios .put(uri, data.show) .then((response) => { if (!data.callback) { // `updateProperty` does commit calls in its callback, // so we don’t commit changes, if the old callback syntax // is used as it’s not used anywhere else. ctx.commit('replaceShow', response.data) } return callOrReturn(response, data?.callback) }) .catch((error) => { APIError.handle(error, 'Unable to update show', data, this) }) }, updateProperty(ctx, data) { const show = cloneMinimalShowObject(ctx.getters.getShowByDataParam(data)) show[data.property] = data.value ctx.dispatch('updateShow', { id: data.id, show: show, callback: () => { ctx.commit('setProperty', { id: data.id, property: data.property, value: data.value, }) if (typeof data.callback === 'function') { data.callback() } }, callbackCancel: (error) => { if (typeof data.callbackCancel === 'function') { data.callbackCancel(error) } }, }) }, updateTimeslot(ctx, data) { const uri = createSteeringURL( 'shows', data.showId, 'schedules', data.scheduleId, 'timeslots', data.timeslot.id, ) axios .put(uri, data.timeslot) .then(() => { ctx.commit('setTimeslot', data.timeslot) if (data && typeof data.callback === 'function') { data.callback() } }) .catch((error) => { handleApiError(this, error, 'could not update timeslot') if (data && typeof data.callbackCancel === 'function') { data.callbackCancel() } }) }, deleteSchedule(ctx, data) { const uri = createSteeringURL('shows', data.showId, 'schedules', data.scheduleId) axios .delete(uri) .then(() => { if (data && typeof data.callback === 'function') { data.callback() } }) .catch((error) => { handleApiError(this, error, 'could not delete full schedule') if (data && typeof data.callbackCancel === 'function') { data.callbackCancel() } }) }, deleteTimeslot(ctx, data) { const uri = createSteeringURL( 'shows', data.showId, 'schedules', data.scheduleId, 'timeslots', data.timeslotId, ) axios .delete(uri) .then(() => { if (data && typeof data.callback === 'function') { data.callback() } }) .catch((error) => { handleApiError(this, error, 'could not delete single timeslot') if (data && typeof data.callbackCancel === 'function') { data.callbackCancel() } }) }, } export default { namespaced: true, state, getters, actions, mutations, }