Skip to content
Snippets Groups Projects
Commit 1201a518 authored by Konrad Mohrfeldt's avatar Konrad Mohrfeldt :koala:
Browse files

feat: implement on-air and next-up visualizations for timeslots

refs #206
parent 38c3a959
No related branches found
No related tags found
No related merge requests found
Pipeline #7220 failed
...@@ -16,11 +16,18 @@ ...@@ -16,11 +16,18 @@
<th>{{ t('emissionTable.start') }}</th> <th>{{ t('emissionTable.start') }}</th>
<th>{{ t('emissionTable.duration') }}</th> <th>{{ t('emissionTable.duration') }}</th>
<th>{{ t('emissionTable.playlist') }}</th> <th>{{ t('emissionTable.playlist') }}</th>
<th class="tw-p-0" />
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<template v-for="timeslot in result.items" :key="timeslot.id"> <template v-for="timeslot in result.items" :key="timeslot.id">
<TimeSlotRow class="tw-transition hover:tw-bg-gray-50" :timeslot="timeslot" /> <TimeSlotRow
class="tw-transition hover:tw-bg-gray-50"
:timeslot="timeslot"
:is-next-up="nextBroadcastedTimeslot?.id === timeslot.id"
:is-on-air="onAirTimeslot?.id === timeslot.id"
/>
</template> </template>
<template v-if="!hasTimeslots"> <template v-if="!hasTimeslots">
<tr> <tr>
...@@ -110,6 +117,25 @@ const { result } = usePaginatedList(timeslotStore.listIsolated, page, limit, { ...@@ -110,6 +117,25 @@ const { result } = usePaginatedList(timeslotStore.listIsolated, page, limit, {
})), })),
}) })
const hasTimeslots = computed(() => result.value.count > 0) const hasTimeslots = computed(() => result.value.count > 0)
const onAirTimeslot = computed(() => {
const _now = formatISO(now.value)
return result.value.items.find((t) => t.start <= _now && _now < t.end) ?? null
})
const currentResultTime = ref(new Date())
const { result: currentResult } = usePaginatedList(timeslotStore.listIsolated, 1, 1, {
events: timeslotStore.events,
query: useQuery(() => ({
showIds: props.show.id,
startsAfter: formatISO(currentResultTime.value),
order: 'start',
})),
})
const nextBroadcastedTimeslot = computed(() => currentResult.value.items[0] ?? null)
watch([onAirTimeslot, useNow({ interval: 15 * 60_000 })], () => {
// reload from usePaginatedList doesn’t cut it, because we actually need to change the query
currentResultTime.value = new Date()
})
watchEffect(() => { watchEffect(() => {
if (page.value !== 1) { if (page.value !== 1) {
......
...@@ -54,6 +54,18 @@ ...@@ -54,6 +54,18 @@
{{ t(`playlist.state.${playlistState.state}.title`) }} {{ t(`playlist.state.${playlistState.state}.title`) }}
</AStatus> </AStatus>
</td> </td>
<td class="tw-relative tw-p-0" :class="{ 'tw-w-6': isOnAir || isNextUp }">
<div
v-if="isNextUp || isOnAir"
class="tw-absolute tw-right-0 tw-inset-y-0 tw-w-6 tw-leading-0 tw-px-[2px] tw-select-none tw-text-white tw-flex tw-items-center tw-text-sm tw-font-bold tw-whitespace-nowrap tw-pointer-events-none"
:class="{ 'tw-bg-green-400': isNextUp, 'tw-bg-indigo-400': isOnAir }"
>
<span style="writing-mode: vertical-lr">
<template v-if="isOnAir">On Air</template>
<template v-else-if="isNextUp">Next Up</template>
</span>
</div>
</td>
</tr> </tr>
</template> </template>
...@@ -61,6 +73,7 @@ ...@@ -61,6 +73,7 @@
import { useObjectFromStore } from '@rokoli/bnb/drf' import { useObjectFromStore } from '@rokoli/bnb/drf'
import { parseISO } from 'date-fns' import { parseISO } from 'date-fns'
import { computed, useAttrs } from 'vue' import { computed, useAttrs } from 'vue'
import { useI18n } from '@/i18n' import { useI18n } from '@/i18n'
import { TimeSlot } from '@/types' import { TimeSlot } from '@/types'
import { useNoteStore } from '@/stores/notes' import { useNoteStore } from '@/stores/notes'
...@@ -79,6 +92,8 @@ defineOptions({ ...@@ -79,6 +92,8 @@ defineOptions({
const props = defineProps<{ const props = defineProps<{
timeslot: TimeSlot timeslot: TimeSlot
isNextUp?: boolean
isOnAir?: boolean
}>() }>()
const attrs = useAttrs() const attrs = useAttrs()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment