owltide/components/TableScheduleShifts.vue
Hornwitser b0d5cdf791
All checks were successful
/ build (push) Successful in 1m36s
/ deploy (push) Successful in 16s
Refactor slot editing to use searchable selections
Instead of having to type in exactly the name of events or shifts and
then hope you remembered it right, replace these interactions with the
custom select component that gives a complete list of the available
choices and allows quickly searching for the right one.
2025-06-27 18:59:23 +02:00

169 lines
3.5 KiB
Vue

<template>
<div>
<table>
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>role</th>
<th>s</th>
<th>description</th>
<th v-if="edit"></th>
</tr>
</thead>
<tbody>
<template v-if="edit">
<tr
v-for="shift in schedule.shifts.values()"
:key="shift.id"
:class="{ removed: shift.deleted }"
>
<td>{{ shift.id }}</td>
<td>
<input
type="text"
v-model="shift.name"
>
</td>
<td>
<SelectSingleEntity
:entities="schedule.roles"
v-model="shift.roleId"
/>
</td>
<td>{{ shift.slots.size ? shift.slots.size : "" }}</td>
<td>
<input
type="text"
v-model="shift.description"
>
</td>
<td>
<button
type="button"
:disabled="shift.deleted"
@click="shift.deleted = true"
>Delete</button>
<button
v-if="shift.isModified()"
type="button"
@click="schedule.shifts.discardId(shift.id)"
>Revert</button>
</td>
</tr>
<tr>
<td>{{ schedule.nextClientId }}</td>
<td>
<input
type="text"
v-model="newShiftName"
>
</td>
<td>
<SelectSingleEntity
:entities="schedule.roles"
v-model="newShiftRoleId"
/>
</td>
<td></td>
<td>
<input
type="text"
v-model="newShiftDescription"
>
</td>
<td>
<button
v-if="shiftExists(newShiftName)"
disabled
>Shift already exists</button>
<button
v-else
type="button"
@click="newShift"
>Add Shift</button>
</td>
</tr>
</template>
<template v-else>
<tr
v-for="shift in schedule.shifts.values()"
:key="shift.id"
>
<td>{{ shift.id }}</td>
<td>{{ shift.name }}</td>
<td>{{ shift.roleId }}</td>
<td>{{ shift.slots.size ? shift.slots.size : "" }}</td>
<td>{{ shift.description }}</td>
</tr>
</template>
</tbody>
</table>
</div>
</template>
<script lang="ts" setup>
import { Info } from '~/shared/utils/luxon';
import { toId } from '~/shared/utils/functions';
const props = defineProps<{
edit?: boolean,
roleId?: number,
}>();
const schedule = await useSchedule();
const accountStore = useAccountStore();
const newShiftName = ref("");
const newShiftRoleId = ref(props.roleId);
watch(() => props.roleId, () => {
newShiftRoleId.value = props.roleId;
});
const newShiftDescription = ref("");
function shiftExists(name: string) {
name = toId(name);
return (
[...schedule.value.shifts.values()].some(s => !s.deleted && toId(s.name) === name)
);
}
function newShift() {
if (shiftExists(newShiftName.value)) {
alert(`Shift ${newShiftName.value} already exists`);
return;
}
if (newShiftRoleId.value === undefined) {
alert(`Invalid role`);
return;
}
const zone = Info.normalizeZone(accountStore.activeTimezone);
const locale = accountStore.activeLocale;
const shift = ClientScheduleShift.create(
schedule.value,
schedule.value.nextClientId--,
newShiftRoleId.value,
newShiftName.value,
newShiftDescription.value,
new Set(),
{ zone, locale },
);
schedule.value.shifts.add(shift);
newShiftName.value = "";
newShiftDescription.value = "";
}
</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>