owltide/components/TableScheduleEvents.vue
Hornwitser a32a49b281
All checks were successful
/ build (push) Successful in 1m35s
/ deploy (push) Successful in 16s
Add UI for setting cancelled status
Add indications in event cards, event slot cards and the timetable for
an event or event slot being cancelled by striking it through and
dimming the text colour.  And a checkbox in the event and event slot
list to edit the cancelled status.  And a diff entry for the cancelled
status on events and event slots.
2025-09-21 23:15:10 +02:00

240 lines
5.1 KiB
Vue

<!--
SPDX-FileCopyrightText: © 2025 Hornwitser <code@hornwitser.no>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<div>
<table>
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>timetableName</th>
<th>host</th>
<th>notice</th>
<th>description</th>
<th>p</th>
<th title="cancelled">c</th>
<th>s</th>
<th v-if="edit"></th>
</tr>
</thead>
<tbody>
<template v-if="edit">
<tr
v-for="event in schedule.events.values()"
:key="event.id"
:class="{ removed: event.deleted }"
>
<td>{{ event.id }}</td>
<td>
<input
type="text"
:disabled="!canEdit(event)"
v-model="event.name"
>
</td>
<td>
<input
type="text"
:disabled="!canEdit(event)"
v-model="event.timetableName"
>
</td>
<td>
<input
type="text"
:disabled="!canEdit(event)"
v-model="event.host"
>
</td>
<td>
<textarea
rows="1"
:disabled="!canEdit(event)"
v-model="event.notice"
/>
</td>
<td>
<textarea
rows="1"
:disabled="!canEdit(event)"
v-model="event.description"
/>
</td>
<td>
<input
type="checkbox"
:disabled="!accountStore.canEditPublic"
:checked="!event.crew"
@change="event.crew = !event.crew"
>
</td>
<td>
<input
type="checkbox"
:disabled="!canEdit(event)"
v-model="event.cancelled"
>
</td>
<td>{{ event.slots.size ? event.slots.size : "" }}</td>
<td>
<button
type="button"
:disabled="!canEdit(event) || event.deleted"
@click="event.deleted = true"
>Delete</button>
<button
v-if="event.isModified()"
type="button"
@click="schedule.events.discardId(event.id)"
>Revert</button>
</td>
</tr>
<tr>
<td>{{ schedule.nextClientId }}</td>
<td>
<input
type="text"
v-model="newEventName"
>
</td>
<td>
<input
type="text"
v-model="newEventShortName"
>
</td>
<td>
<input
type="text"
v-model="newEventHost"
>
</td>
<td>
<textarea
rows="1"
v-model="newEventNotice"
/>
</td>
<td>
<textarea
rows="1"
v-model="newEventDescription"
/>
</td>
<td>
<input
type="checkbox"
:disabled="!accountStore.canEditPublic"
v-model="newEventPublic"
>
</td>
<td></td>
<td></td>
<td>
<button
v-if="eventExists(newEventName)"
disabled
>Event already exists</button>
<button
v-else
type="button"
@click="newEvent"
>Add Event</button>
</td>
</tr>
</template>
<template v-else>
<tr
v-for="event in schedule.events.values()"
:key="event.id"
>
<td>{{ event.id }}</td>
<td>{{ event.name }}</td>
<td>{{ event.timetableName }}</td>
<td>{{ event.host }}</td>
<td class="preWrap">{{ event.notice }}</td>
<td class="preWrap">{{ event.description }}</td>
<td>{{ event.crew ? "" : "Yes"}}</td>
<td>{{ event.slots.size ? event.slots.size : "" }}</td>
</tr>
</template>
</tbody>
</table>
</div>
</template>
<script lang="ts" setup>
import { Info } from '~/shared/utils/luxon';
import { toId } from '~/shared/utils/functions';
defineProps<{
edit?: boolean,
}>();
const schedule = await useSchedule();
const accountStore = useAccountStore();
function canEdit(event: ClientScheduleEvent) {
return event.crew || accountStore.canEditPublic;
}
const newEventName = ref("");
const newEventShortName = ref("");
const newEventHost = ref("");
const newEventNotice = ref("");
const newEventDescription = ref("");
const newEventPublic = ref(false);
function eventExists(name: string) {
name = toId(name);
return (
[...schedule.value.events.values()].some(e => !e.deleted && toId(e.name) === name)
);
}
function newEvent() {
if (eventExists(newEventName.value)) {
alert(`Event ${newEventName.value} already exists`);
return;
}
const zone = Info.normalizeZone(accountStore.activeTimezone);
const locale = accountStore.activeLocale;
const event = ClientScheduleEvent.create(
schedule.value,
schedule.value.nextClientId--,
newEventName.value,
newEventShortName.value,
!newEventPublic.value,
newEventHost.value,
false,
newEventNotice.value,
newEventDescription.value,
0,
new Set(),
{ zone, locale },
);
schedule.value.events.add(event);
newEventName.value = "";
newEventShortName.value = "";
newEventHost.value = "";
newEventNotice.value = "";
newEventDescription.value = "";
newEventPublic.value = false;
}
</script>
<style scoped>
table {
border-spacing: 0;
}
table th {
text-align: left;
border-bottom: 1px solid var(--foreground);
}
table :is(th, td) + :is(th, td) {
padding-inline-start: 0.4em;
}
.removed :is(td, input) {
text-decoration: line-through;
}
</style>