2025-03-15 17:06:23 +01:00
|
|
|
<template>
|
2025-06-14 19:22:53 +02:00
|
|
|
<div>
|
2025-03-15 17:06:23 +01:00
|
|
|
<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
|
2025-06-14 19:22:53 +02:00
|
|
|
v-for="shift in schedule.shifts.values()"
|
2025-03-15 17:06:23 +01:00
|
|
|
:key="shift.id"
|
2025-06-14 19:22:53 +02:00
|
|
|
:class="{ removed: shift.deleted }"
|
2025-03-15 17:06:23 +01:00
|
|
|
>
|
|
|
|
<td>{{ shift.id }}</td>
|
|
|
|
<td>
|
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
:value="shift.name"
|
|
|
|
@input="editShift(shift, { name: ($event as any).target.value })"
|
|
|
|
>
|
|
|
|
</td>
|
|
|
|
<td>
|
|
|
|
<select
|
2025-06-14 19:22:53 +02:00
|
|
|
:value="shift.role.id"
|
|
|
|
@change="editShift(shift, { role: schedule.roles.get(parseInt(($event as any).target.value, 10)) })"
|
2025-03-15 17:06:23 +01:00
|
|
|
>
|
|
|
|
<option
|
2025-06-14 19:22:53 +02:00
|
|
|
v-for="role in schedule.roles.values()"
|
2025-03-15 17:06:23 +01:00
|
|
|
:key="role.id"
|
|
|
|
:value="role.id"
|
2025-06-14 19:22:53 +02:00
|
|
|
:disabled="shift.deleted"
|
|
|
|
:selected="shift.role.id === role.id"
|
2025-03-15 17:06:23 +01:00
|
|
|
>{{ role.name }}</option>
|
|
|
|
</select>
|
|
|
|
</td>
|
2025-06-14 19:22:53 +02:00
|
|
|
<td>{{ shift.slots.size ? shift.slots.size : "" }}</td>
|
2025-03-15 17:06:23 +01:00
|
|
|
<td>
|
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
:value="shift.description"
|
|
|
|
@input="editShift(shift, { description: ($event as any).target.value })"
|
|
|
|
>
|
|
|
|
</td>
|
|
|
|
<td>
|
|
|
|
<button
|
|
|
|
type="button"
|
2025-06-14 19:22:53 +02:00
|
|
|
:disabled="shift.deleted"
|
|
|
|
@click="editShift(shift, { deleted: true })"
|
2025-03-15 17:06:23 +01:00
|
|
|
>Delete</button>
|
|
|
|
<button
|
2025-06-14 19:22:53 +02:00
|
|
|
v-if="schedule.isModifiedShift(shift.id)"
|
2025-03-15 17:06:23 +01:00
|
|
|
type="button"
|
|
|
|
@click="revertShift(shift.id)"
|
|
|
|
>Revert</button>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
2025-06-14 19:22:53 +02:00
|
|
|
<td>{{ schedule.nextClientId }}</td>
|
2025-03-15 17:06:23 +01:00
|
|
|
<td>
|
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
v-model="newShiftName"
|
|
|
|
>
|
|
|
|
</td>
|
|
|
|
<td>
|
2025-06-14 19:22:53 +02:00
|
|
|
<select v-model="newShiftRoleId">
|
2025-03-15 17:06:23 +01:00
|
|
|
<option
|
2025-06-14 19:22:53 +02:00
|
|
|
v-for="role in schedule.roles.values()"
|
2025-03-15 17:06:23 +01:00
|
|
|
:key="role.id"
|
|
|
|
:value="role.id"
|
2025-06-14 19:22:53 +02:00
|
|
|
:disabled="role.deleted"
|
|
|
|
:selected="role.id === newShiftRoleId"
|
2025-03-15 17:06:23 +01:00
|
|
|
>{{ role.name }}</option>
|
|
|
|
</select>
|
|
|
|
</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
|
2025-06-14 19:22:53 +02:00
|
|
|
v-for="shift in schedule.shifts.values()"
|
2025-03-15 17:06:23 +01:00
|
|
|
:key="shift.id"
|
|
|
|
>
|
|
|
|
<td>{{ shift.id }}</td>
|
|
|
|
<td>{{ shift.name }}</td>
|
2025-06-14 19:22:53 +02:00
|
|
|
<td>{{ shift.role.id }}</td>
|
|
|
|
<td>{{ shift.slots.size ? shift.slots.size : "" }}</td>
|
2025-03-15 17:06:23 +01:00
|
|
|
<td>{{ shift.description }}</td>
|
|
|
|
</tr>
|
|
|
|
</template>
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
2025-06-23 12:48:09 +02:00
|
|
|
import { DateTime } from '~/shared/utils/luxon';
|
2025-06-14 19:22:53 +02:00
|
|
|
import type { Id } from '~/shared/types/common';
|
2025-03-15 17:06:23 +01:00
|
|
|
import { toId } from '~/shared/utils/functions';
|
|
|
|
|
|
|
|
const props = defineProps<{
|
|
|
|
edit?: boolean,
|
2025-06-11 21:05:17 +02:00
|
|
|
roleId?: number,
|
2025-03-15 17:06:23 +01:00
|
|
|
}>();
|
|
|
|
|
|
|
|
const schedule = await useSchedule();
|
|
|
|
|
|
|
|
const newShiftName = ref("");
|
2025-06-14 19:22:53 +02:00
|
|
|
const newShiftRoleId = ref(props.roleId);
|
2025-06-11 21:05:17 +02:00
|
|
|
watch(() => props.roleId, () => {
|
2025-06-14 19:22:53 +02:00
|
|
|
newShiftRoleId.value = props.roleId;
|
2025-03-15 17:06:23 +01:00
|
|
|
});
|
|
|
|
const newShiftDescription = ref("");
|
|
|
|
function editShift(
|
2025-06-14 19:22:53 +02:00
|
|
|
shift: ClientScheduleShift,
|
|
|
|
edits: Parameters<ClientSchedule["editShift"]>[1],
|
2025-03-15 17:06:23 +01:00
|
|
|
) {
|
2025-06-14 19:22:53 +02:00
|
|
|
schedule.value.editShift(shift, edits);
|
2025-03-15 17:06:23 +01:00
|
|
|
}
|
2025-06-14 19:22:53 +02:00
|
|
|
function revertShift(id: Id) {
|
|
|
|
schedule.value.restoreShift(id);
|
2025-03-15 17:06:23 +01:00
|
|
|
}
|
|
|
|
function shiftExists(name: string) {
|
2025-06-11 21:05:17 +02:00
|
|
|
name = toId(name);
|
2025-03-15 17:06:23 +01:00
|
|
|
return (
|
2025-06-14 19:22:53 +02:00
|
|
|
[...schedule.value.shifts.values()].some(s => !s.deleted && toId(s.name) === name)
|
2025-03-15 17:06:23 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
function newShift() {
|
|
|
|
if (shiftExists(newShiftName.value)) {
|
|
|
|
alert(`Shift ${newShiftName.value} already exists`);
|
|
|
|
return;
|
|
|
|
}
|
2025-06-14 19:22:53 +02:00
|
|
|
const role = schedule.value.roles.get(newShiftRoleId.value!);
|
|
|
|
if (!role) {
|
2025-03-15 17:06:23 +01:00
|
|
|
alert(`Invalid role`);
|
|
|
|
return;
|
|
|
|
}
|
2025-06-14 19:22:53 +02:00
|
|
|
const shift = new ClientScheduleShift(
|
|
|
|
schedule.value.nextClientId--,
|
|
|
|
DateTime.now(),
|
|
|
|
false,
|
|
|
|
role,
|
|
|
|
newShiftName.value,
|
|
|
|
newShiftDescription.value,
|
|
|
|
new Map(),
|
|
|
|
);
|
|
|
|
schedule.value.setShift(shift);
|
2025-03-15 17:06:23 +01:00
|
|
|
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>
|