Allow a shift to have no role associated with it in order to simplify conflict resolution around situations like a shift being created while the role it was assoiated with was deleted. This also allows for shifts that are freestanding to be created in case having a role doesn't make sense for it.
165 lines
3.5 KiB
Vue
165 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;
|
|
}
|
|
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>
|