[events] Validate jobs before adding new

This commit is contained in:
Ferdinand Thiessen 2021-04-04 21:35:14 +02:00
parent 6a35f3c669
commit 7d1993e3fa
2 changed files with 77 additions and 31 deletions

View File

@ -82,9 +82,12 @@
</q-card-section> </q-card-section>
<template v-for="(job, index) in event.jobs" :key="index"> <template v-for="(job, index) in event.jobs" :key="index">
<job <job
:ref="active === index ? 'activeRef' : undefined"
v-model="event.jobs[index]" v-model="event.jobs[index]"
:can-delete="jobDeleteDisabled" :active="active === index"
class="q-mb-xs"
@remove-job="removeJob(index)" @remove-job="removeJob(index)"
@update:active="active = index"
/> />
</template> </template>
</q-card-section> </q-card-section>
@ -117,13 +120,13 @@ export default defineComponent({
components: { IsoDateInput, Job, RecurrenceRule }, components: { IsoDateInput, Job, RecurrenceRule },
props: { props: {
modelValue: { modelValue: {
default: () => emptyEvent, default: () => emptyEvent(),
type: Object as PropType<EditableEvent>, type: Object as PropType<EditableEvent>,
}, },
date: { date: {
required: false, required: false,
default: () => new Date(), default: () => new Date(),
type: [Object, String, Number] as PropType<Date | string | number>, type: [Object, Number] as PropType<Date | number>,
}, },
}, },
emits: { emits: {
@ -131,20 +134,19 @@ export default defineComponent({
}, },
setup(props, { emit }) { setup(props, { emit }) {
const store = useScheduleStore(); const store = useScheduleStore();
const active = ref(0);
const date = computed(() => new Date(props.date)); const activeRef = ref(Job);
const event = ref<EditableEvent>(
props.modelValue.id
? props.modelValue
: Object.assign({}, props.modelValue, { start: date.value })
);
const eventtypes = computed(() => store.eventTypes); const eventtypes = computed(() => store.eventTypes);
const form = ref<QForm>(); const form = ref<QForm>();
const jobDeleteDisabled = computed(() => event.value.jobs.length < 2);
const recurrent = ref(false); const recurrent = ref(false);
const recurrenceRule = ref<FG.RecurrenceRule>({ frequency: 'daily', interval: 1 }); const recurrenceRule = ref<FG.RecurrenceRule>({ frequency: 'daily', interval: 1 });
const templates = computed(() => store.templates); const templates = computed(() => store.templates);
const template = ref<FG.Event>(); const template = ref<FG.Event>();
const event = ref<EditableEvent>(
props.modelValue.id
? props.modelValue
: Object.assign({}, props.modelValue, { start: new Date(props.date) })
);
onBeforeMount(() => { onBeforeMount(() => {
void store.getEventTypes(); void store.getEventTypes();
@ -152,25 +154,34 @@ export default defineComponent({
void store.getTemplates(); void store.getTemplates();
}); });
function addJob() { async function addJob() {
event.value.jobs.push(Object.assign({}, emptyJob)); if (event.value.jobs.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
if (!(await activeRef.value?.validate())) return;
event.value.jobs.sort((a, b) => {
if (a.end && b.end)
if (a.end < b.end) return -1;
else if (a.end > b.end) return 1;
return a.start.getTime() - b.start.getTime();
});
}
event.value.jobs.push(
emptyJob(event.value.jobs[event.value.jobs.length - 1]?.end || new Date(props.date))
);
active.value = event.value.jobs.length - 1;
} }
function removeJob(index: number) { function removeJob(index: number) {
event.value.jobs.splice(index, 1); event.value.jobs.splice(index, 1);
active.value = index == active.value ? event.value.jobs.length - 1 : index;
} }
function fromTemplate(tpl: FG.Event) { function fromTemplate(tpl: FG.Event) {
template.value = tpl; template.value = tpl;
event.value = Object.assign({}, tpl); event.value = Object.assign({}, tpl);
event.value.start = new Date( event.value.start = qdate.buildDate({ hours: 0, minutes: 0, seconds: 0 });
date.value.getUTCFullYear(),
date.value.getUTCMonth(),
date.value.getUTCDate()
);
const diff = event.value.start.getTime() - tpl.start.getTime(); const diff = event.value.start.getTime() - tpl.start.getTime();
console.log(event.value);
console.log(diff);
if (event.value.end) event.value.end = new Date(event.value.end.getTime() + diff); if (event.value.end) event.value.end = new Date(event.value.end.getTime() + diff);
event.value.jobs.forEach((job) => { event.value.jobs.forEach((job) => {
@ -231,12 +242,13 @@ export default defineComponent({
} }
function reset() { function reset() {
event.value = Object.assign({}, props.modelValue || emptyEvent); event.value = Object.assign({}, props.modelValue || emptyEvent());
template.value = undefined; template.value = undefined;
} }
return { return {
jobDeleteDisabled, active,
activeRef,
addJob, addJob,
eventtypes, eventtypes,
templates, templates,

View File

@ -1,6 +1,6 @@
<template> <template>
<q-card class="fit row justify-start content-center items-center"> <q-card class="fit row justify-start content-center items-center" @click="activate">
<q-card-section class="fit row justify-start content-center items-center"> <q-form v-if="active" ref="form" class="fit row justify-start content-center items-center">
<IsoDateInput <IsoDateInput
v-model="job.start" v-model="job.start"
class="col-xs-12 col-sm-6 q-pa-sm" class="col-xs-12 col-sm-6 q-pa-sm"
@ -40,44 +40,57 @@
<q-input <q-input
v-model="job.comment" v-model="job.comment"
class="col-12 q-pa-sm" class="col-12 q-pa-sm"
label="Beschreibung" label="Kommentar"
type="textarea" type="textarea"
filled filled
/> />
</q-form>
<q-card-section v-else class="fit row justify-start content-center items-center text-center">
<div class="text-h6 col-12">{{ formatStartEnd(job.start, job.end) }}</div>
<div class="text-subtitle1 col-12">
{{ job?.type?.name || 'Typ fehlt' }} ({{ job.required_services }})
</div>
<div class="text-body2 text-italic text-left col-12">{{ job.comment }}</div>
</q-card-section> </q-card-section>
<q-card-actions> <q-card-actions class="fit row" align="right">
<q-btn label="Schicht löschen" color="negative" :disabled="canDelete" @click="removeJob" /> <q-btn label="Schicht löschen" color="negative" @click="removeJob" />
</q-card-actions> </q-card-actions>
</q-card> </q-card>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, computed, onBeforeMount, PropType } from 'vue'; import { defineComponent, computed, onBeforeMount, PropType, ref } from 'vue';
import IsoDateInput from 'src/components/utils/IsoDateInput.vue'; import IsoDateInput from 'src/components/utils/IsoDateInput.vue';
import { notEmpty } from 'src/utils/validators'; import { notEmpty } from 'src/utils/validators';
import { useScheduleStore } from '../../store'; import { useScheduleStore } from '../../store';
import { QForm } from 'quasar';
import { asDate, asHour } from 'src/utils/datetime';
export default defineComponent({ export default defineComponent({
name: 'Job', name: 'Job',
components: { IsoDateInput }, components: { IsoDateInput },
props: { props: {
active: {
default: () => true,
type: Boolean,
},
modelValue: { modelValue: {
required: true, required: true,
type: Object as PropType<FG.Job>, type: Object as PropType<FG.Job>,
}, },
canDelete: Boolean,
}, },
emits: { emits: {
'remove-job': () => true, 'remove-job': () => true,
'update:active': (active: boolean) => typeof active === 'boolean',
'update:modelValue': (job: FG.Job) => !!job, 'update:modelValue': (job: FG.Job) => !!job,
}, },
setup(props, { emit }) { setup(props, { emit, expose }) {
const store = useScheduleStore(); const store = useScheduleStore();
onBeforeMount(() => store.getJobTypes()); onBeforeMount(() => store.getJobTypes());
const form = ref<QForm>();
const jobtypes = computed(() => store.jobTypes); const jobtypes = computed(() => store.jobTypes);
const job = new Proxy(props.modelValue, { const job = new Proxy(props.modelValue, {
get(target, prop) { get(target, prop) {
if (typeof prop === 'string') { if (typeof prop === 'string') {
@ -93,6 +106,15 @@ export default defineComponent({
}, },
}); });
function formatStartEnd(start: Date, end?: Date) {
const startDate = asDate(start);
const endDate = end ? asDate(end) : end;
return (
`${startDate}, ${asHour(start)}` +
(endDate ? ` - ${endDate !== startDate ? endDate + ', ' : ''}` + asHour(end) : '')
);
}
function removeJob() { function removeJob() {
emit('remove-job'); emit('remove-job');
} }
@ -101,7 +123,19 @@ export default defineComponent({
return props.modelValue.start < new Date(val) || 'Ende muss hinter dem Start liegen'; return props.modelValue.start < new Date(val) || 'Ende muss hinter dem Start liegen';
} }
function activate() {
emit('update:active', true);
}
function validate() {
return form.value?.validate() || new Promise((r) => r(false));
}
expose({ validate });
return { return {
activate,
form,
formatStartEnd,
job, job,
jobtypes, jobtypes,
removeJob, removeJob,