Use a single mutable location, event, slot, etc, for each unique resource that keeps track of the local editable client copy and the server copy of the data contained in it. This makes it much simpler to update these data structures as I can take advantage of the v-model bindings in Vue.js and work with the system instead of against it.
170 lines
4.1 KiB
Vue
170 lines
4.1 KiB
Vue
<template>
|
|
<main>
|
|
<h1>Edit</h1>
|
|
<label>
|
|
Crew Filter:
|
|
<select
|
|
v-model="crewFilter"
|
|
>
|
|
<option
|
|
:value="undefined"
|
|
:selected="crewFilter === undefined"
|
|
><All Crew></option>
|
|
<option
|
|
v-for="user in [...usersStore.users.values()].filter(a => a.type === 'crew' || a.type === 'admin')"
|
|
:key="user.id"
|
|
:value="String(user.id)"
|
|
:selected="crewFilter === String(user.id)"
|
|
>{{ user.name }}</option>
|
|
</select>
|
|
</label>
|
|
<Timetable :schedule :eventSlotFilter :shiftSlotFilter />
|
|
<Tabs
|
|
:tabs
|
|
default="locations"
|
|
>
|
|
<template #locations>
|
|
<TableScheduleLocations :edit="accountStore.canEditPublic" />
|
|
</template>
|
|
<template #events>
|
|
<TableScheduleEvents :edit="true" />
|
|
</template>
|
|
<template #eventSlots>
|
|
<label>
|
|
Location Filter:
|
|
<select
|
|
v-model="locationFilter"
|
|
>
|
|
<option
|
|
:value="undefined"
|
|
:selected="locationFilter === undefined"
|
|
><All locations></option>
|
|
<option
|
|
v-for="location in schedule.locations.values()"
|
|
:key="location.id"
|
|
:value="location.id"
|
|
:disabled="location.deleted"
|
|
:selected="locationFilter === location.id"
|
|
>{{ location.name }}</option>
|
|
</select>
|
|
</label>
|
|
<TableScheduleEventSlots :edit="true" :locationId="locationFilter" :eventSlotFilter />
|
|
</template>
|
|
<template #roles>
|
|
<TableScheduleRoles :edit="true" />
|
|
</template>
|
|
<template #shifts>
|
|
<TableScheduleShifts :edit="true" :roleId="roleFilter" />
|
|
</template>
|
|
<template #shiftSlots>
|
|
<label>
|
|
Role Filter:
|
|
<select
|
|
v-model="roleFilter"
|
|
>
|
|
<option
|
|
:value="undefined"
|
|
:selected="roleFilter === undefined"
|
|
><All roles></option>
|
|
<option
|
|
v-for="role in schedule.roles.values()"
|
|
:key="role.id"
|
|
:value="role.id"
|
|
:disabled="role.deleted"
|
|
:selected="roleFilter === role.id"
|
|
>{{ role.name }}</option>
|
|
</select>
|
|
</label>
|
|
<TableScheduleShiftSlots :edit="true" :roleId="roleFilter" :shiftSlotFilter />
|
|
</template>
|
|
</Tabs>
|
|
<p v-if="schedule.isModified()">
|
|
Changes are not saved yet.
|
|
<button
|
|
type="button"
|
|
@click="saveChanges"
|
|
>Save Changes</button>
|
|
</p>
|
|
</main>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
definePageMeta({
|
|
middleware: ["authenticated"],
|
|
allowedAccountTypes: ["crew", "admin"],
|
|
});
|
|
|
|
const tabs = [
|
|
{ id: "locations", title: "Locations" },
|
|
{ id: "events", title: "Events" },
|
|
{ id: "eventSlots", title: "Event Slots" },
|
|
{ id: "roles", title: "Roles" },
|
|
{ id: "shifts", title: "Shifts" },
|
|
{ id: "shiftSlots", title: "Shifts Slots" },
|
|
];
|
|
|
|
const schedule = await useSchedule();
|
|
const usersStore = useUsersStore();
|
|
await usersStore.fetch();
|
|
const accountStore = useAccountStore();
|
|
|
|
const route = useRoute();
|
|
const crewFilter = computed({
|
|
get: () => queryToString(route.query.crew),
|
|
set: (value: string | undefined) => navigateTo({
|
|
path: route.path,
|
|
query: {
|
|
...route.query,
|
|
crew: value,
|
|
},
|
|
}),
|
|
});
|
|
const eventSlotFilter = computed(() => {
|
|
if (crewFilter.value === undefined || !accountStore.valid) {
|
|
return () => true;
|
|
}
|
|
const cid = parseInt(crewFilter.value);
|
|
return (slot: ClientScheduleEventSlot) => slot.assigned.has(cid);
|
|
});
|
|
const shiftSlotFilter = computed(() => {
|
|
if (crewFilter.value === undefined || !accountStore.valid) {
|
|
return () => true;
|
|
}
|
|
const cid = parseInt(crewFilter.value);
|
|
return (slot: ClientScheduleShiftSlot) => slot.assigned.has(cid);
|
|
});
|
|
|
|
const locationFilter = computed({
|
|
get: () => queryToNumber(route.query.location),
|
|
set: (value: number | undefined) => navigateTo({
|
|
path: route.path,
|
|
query: {
|
|
...route.query,
|
|
location: value !== undefined ? String(value) : undefined,
|
|
},
|
|
}),
|
|
});
|
|
|
|
const roleFilter = computed({
|
|
get: () => queryToNumber(route.query.role),
|
|
set: (value: string | undefined) => navigateTo({
|
|
path: route.path,
|
|
query: {
|
|
...route.query,
|
|
role: value,
|
|
},
|
|
}),
|
|
});
|
|
|
|
async function saveChanges() {
|
|
try {
|
|
await $fetch("/api/schedule", {
|
|
method: "PATCH",
|
|
body: schedule.value.toApi(true),
|
|
});
|
|
} catch (err: any) {
|
|
console.error(err);
|
|
alert(err?.data?.message ?? err.message);
|
|
}
|
|
}
|
|
</script>
|