[events] Validate jobs before adding new
This commit is contained in:
		
							parent
							
								
									6a35f3c669
								
							
						
					
					
						commit
						7d1993e3fa
					
				| 
						 | 
					@ -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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue