Pull out the list of events into its own page sorted by name and show the event slots in chronological order on the schedule page, with past slots hidden by default. This makes the content underneath the schedule the most immediately useful to have in the moment, while the full list is kept separately and in a predictable order.
89 lines
2.3 KiB
Vue
89 lines
2.3 KiB
Vue
<!--
|
|
SPDX-FileCopyrightText: © 2025 Hornwitser <code@hornwitser.no>
|
|
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
-->
|
|
<template>
|
|
<main>
|
|
<h1>Events</h1>
|
|
<label v-if="accountStore.valid">
|
|
Filter:
|
|
<select
|
|
v-model="filter"
|
|
>
|
|
<option
|
|
:value="undefined"
|
|
:selected="filter === undefined"
|
|
><All events></option>
|
|
<option
|
|
value="my-schedule"
|
|
:selected='filter === "my-schedule"'
|
|
>My Schedule</option>
|
|
<option
|
|
v-if="accountStore.isCrew"
|
|
value="assigned"
|
|
:selected='filter === "assigned"'
|
|
>Assigned to Me</option>
|
|
</select>
|
|
</label>
|
|
<CardEvent
|
|
v-for="event in events"
|
|
:key="`my-${event.id}`"
|
|
:id="String(event.name)"
|
|
:event
|
|
></CardEvent>
|
|
</main>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
useHead({
|
|
title: "Schedule",
|
|
});
|
|
|
|
const stringSort = useStringSort();
|
|
const events = computed(() => {
|
|
return [...schedule.value.events.values()].filter(e => !e.deleted && [...e.slots.values()].some(eventSlotFilter.value)).sort((a, b) => stringSort(a.name, b.name));
|
|
});
|
|
|
|
const accountStore = useAccountStore();
|
|
const usersStore = useUsersStore();
|
|
await usersStore.fetch();
|
|
const schedule = await useSchedule();
|
|
|
|
const route = useRoute();
|
|
const filter = computed({
|
|
get: () => queryToString(route.query.filter),
|
|
set: (value: string | undefined) => navigateTo({
|
|
path: route.path,
|
|
query: {
|
|
...route.query,
|
|
filter: value,
|
|
},
|
|
}),
|
|
});
|
|
|
|
const eventSlotFilter = computed(() => {
|
|
if (filter.value === undefined || !accountStore.valid || schedule.value.deleted) {
|
|
return () => true;
|
|
}
|
|
const aid = accountStore.id;
|
|
if (filter.value === "my-schedule") {
|
|
const slotIds = new Set(accountStore.interestedEventSlotIds);
|
|
for (const event of schedule.value.events.values()) {
|
|
if (!event.deleted && accountStore.interestedEventIds.has(event.id)) {
|
|
for (const slot of event.slots.values()) {
|
|
slotIds.add(slot.id);
|
|
}
|
|
}
|
|
}
|
|
return (slot: ClientScheduleEventSlot) => slotIds.has(slot.id) || slot.assigned.has(aid!) || false;
|
|
}
|
|
if (filter.value === "assigned") {
|
|
return (slot: ClientScheduleEventSlot) => slot.assigned.has(aid!) || false;
|
|
}
|
|
if (filter.value.startsWith("crew-")) {
|
|
const cid = parseInt(filter.value.slice(5));
|
|
return (slot: ClientScheduleEventSlot) => slot.assigned.has(cid) || false;
|
|
}
|
|
return () => false;
|
|
});
|
|
</script>
|