Refactor the existing scattered code dealing with the account state into a pinia store.
115 lines
3.4 KiB
Vue
115 lines
3.4 KiB
Vue
<template>
|
|
<main>
|
|
<h1>Schedule & Events</h1>
|
|
<p>
|
|
Study carefully, we only hold these events once a year.
|
|
</p>
|
|
<p v-if="!accountStore.valid">
|
|
<NuxtLink to="/login">Login</NuxtLink> or <NuxtLink to="/login#create-account">Create an account</NuxtLink>
|
|
to get notified about updates to the schedule.
|
|
</p>
|
|
<p v-else>
|
|
Check out your <NuxtLink to="/account/settings">Account Setting</NuxtLink> to set up notifications for changes to schedule.
|
|
</p>
|
|
<h2>Schedule</h2>
|
|
<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>
|
|
<optgroup v-if="accountStore.isCrew && accounts" label="Crew">
|
|
<option
|
|
v-for="account in accounts.filter(a => a.type === 'crew' || a.type === 'admin')"
|
|
:key="account.id"
|
|
:value="`crew-${account.id}`"
|
|
:selected="filter === `crew-${account.id}`"
|
|
>{{ account.name }}</option>
|
|
</optgroup>
|
|
</select>
|
|
</label>
|
|
<Timetable :schedule :eventSlotFilter :shiftSlotFilter />
|
|
<EventsEdit />
|
|
<h2>Events</h2>
|
|
<EventCard v-for="event in schedule.events.filter(e => e.slots.some(eventSlotFilter))" :event/>
|
|
<h2>Locations</h2>
|
|
<ul>
|
|
<li v-for="location in schedule.locations" :key="location.id">
|
|
<h3>{{ location.name }}</h3>
|
|
{{ location.description ?? "No description provided" }}
|
|
</li>
|
|
</ul>
|
|
</main>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type { ShiftSlot, TimeSlot } from '~/shared/types/schedule';
|
|
|
|
const accountStore = useAccountStore();
|
|
const { data: accounts } = await useAccounts();
|
|
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) {
|
|
return () => true;
|
|
}
|
|
const aid = accountStore.id;
|
|
if (filter.value === "my-schedule") {
|
|
const ids = new Set(accountStore.interestedIds);
|
|
for (const event of schedule.value.events) {
|
|
if (ids.has(event.id)) {
|
|
for (const slot of event.slots) {
|
|
ids.add(slot.id);
|
|
}
|
|
}
|
|
}
|
|
return (slot: TimeSlot) => ids.has(slot.id) || slot.assigned?.some(id => id === aid) || false;
|
|
}
|
|
if (filter.value === "assigned") {
|
|
return (slot: TimeSlot) => slot.assigned?.some(id => id === aid) || false;
|
|
}
|
|
if (filter.value.startsWith("crew-")) {
|
|
const cid = parseInt(filter.value.slice(5));
|
|
return (slot: TimeSlot) => slot.assigned?.some(id => id === cid) || false;
|
|
}
|
|
return () => false;
|
|
});
|
|
const shiftSlotFilter = computed(() => {
|
|
if (filter.value === undefined || !accountStore.valid) {
|
|
return () => true;
|
|
}
|
|
if (filter.value === "my-schedule" || filter.value === "assigned") {
|
|
const aid = accountStore.id;
|
|
return (slot: ShiftSlot) => slot.assigned?.some(id => id === aid) || false;
|
|
}
|
|
if (filter.value.startsWith("crew-")) {
|
|
const cid = parseInt(filter.value.slice(5));
|
|
return (slot: ShiftSlot) => slot.assigned?.some(id => id === cid) || false;
|
|
}
|
|
return () => false;
|
|
});
|
|
</script>
|