<template> <q-card bordered> <q-dialog :model-value="dialog"> <q-card style="min-width: 320px"> <q-card-section class="row items-center q-pb-none"> <div class="text-h6"> {{ userDisplay(service.userid) }} {{ asDate(modelValue.start) }} </div> <q-space /> <q-btn icon="mdi-close" flat round dense @click="dialog = false" /> </q-card-section> <q-card-section> {{ modelValue.type.name }} {{ asHour(modelValue.start) }}{{ modelValue.end ? ` - ${asHour(modelValue.end)}` : '' }} Uhr </q-card-section> <q-card-actions align="around"> <q-btn style="width: 47.5%" color="primary" label="Eintragen" @click="enroll()" /> <q-toggle v-model="service.is_backup" style="width: 47.5%" color="primary" label="Als Backup" /> </q-card-actions> <q-card-actions v-if="!enrolled(service.userid)" align="around"> <q-btn v-if="isEnrolled" style="width: 47.5%" color="negative" label="Übertragen" @click="enroll(true)" /> <q-btn v-if="!iam(service.userid)" style="width: 47.5%" color="secondary" label="Einladen" @click="enroll(false, true)" /> </q-card-actions> </q-card> </q-dialog> <div class="text-weight-medium q-px-xs"> {{ asHour(modelValue.start) }} <template v-if="modelValue.end">- {{ asHour(modelValue.end) }}</template> </div> <div class="q-px-xs"> {{ modelValue.type.name }} </div> <div class="col-auto q-px-xs" style="font-size: 10px"> {{ modelValue.comment }} </div> <div> <q-select :model-value="modelValue.services" :options="options" :option-label="(v) => userDisplay(v.userid)" filled multiple stack-label label="Dienste" class="col-auto q-px-xs" style="font-size: 6px" counter :max-values="modelValue.required_services" @add="enrollDialog" > <template #selected-item="scope"> <q-chip :removable="canEdit(scope.opt.userid)" dense :tabindex="scope.tabindex" color="white" :text-color="scope.opt.is_backup ? 'primary' : 'secondary'" class="q-ma-none" @remove="remove(scope.opt, scope.removeAtIndex, scope.index)" > <q-avatar :color="scope.opt.is_backup ? 'primary' : 'secondary'" text-color="white"> <img :src="userAvatar(scope.opt.userid)" onerror="this.src=' data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';" /> </q-avatar> {{ userDisplay(scope.opt.userid) }} </q-chip> </template> </q-select> </div> </q-card> </template> <script lang="ts"> import { defineComponent, onBeforeMount, computed, ref, PropType } from 'vue'; import { Notify } from 'quasar'; import { asHour, asDate } from 'src/utils/datetime'; import { useUserStore } from 'src/plugins/user/store'; import { useMainStore } from 'src/stores'; import { useScheduleStore } from 'src/plugins/events/store'; import { PERMISSIONS } from 'src/plugins/events/permissions'; import { hasPermission } from 'src/utils/permission'; export default defineComponent({ name: 'JobSlot', props: { modelValue: { required: true, type: Object as PropType<FG.Job>, }, eventId: { required: true, type: Number, }, }, emits: { 'update:modelValue': (v: FG.Job) => !!v }, setup(props, { emit }) { const store = useScheduleStore(); const mainStore = useMainStore(); const userStore = useUserStore(); const availableUsers = null; const dialog = ref(false); const service = ref<FG.Service>(); onBeforeMount(async () => userStore.getUsers()); function userDisplay(uid: string) { return userStore.findUser(uid)?.display_name || uid; } function userAvatar(uid: string) { return userStore.findUser(uid)?.avatar_url; } function enrollDialog(details: { index: number; value: FG.User }) { service.value = { userid: details.value.userid, is_backup: false, value: 1, }; dialog.value = true; } function iam(uid: string) { return uid === mainStore.currentUser.userid; } async function enroll(transfer = false, invite = false) { try { dialog.value = false; if (transfer) service.value = Object.assign({}, service.value, { replace: mainStore.currentUser.userid, }); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access else if (invite) delete (<any>service.value).value; const job = await store.updateJob(props.eventId, props.modelValue.id, { user: <FG.Service>service.value, }); emit('update:modelValue', job); } catch (error) { console.warn(error); Notify.create({ group: false, type: 'negative', message: 'Fehler beim Eintragen als Dienst', timeout: 10000, progress: true, actions: [{ icon: 'mdi-close', color: 'white' }], }); } } async function remove(service: FG.Service, rem: (i: number) => void, index: number) { if ( service.userid === mainStore.currentUser.userid || hasPermission(PERMISSIONS.ASSIGN_OTHER) ) { rem(index); try { const job = await store.updateJob(props.eventId, props.modelValue.id, { user: Object.assign({}, service, { value: -service.value }), }); emit('update:modelValue', job); } catch (error) { console.warn(error); Notify.create({ group: false, type: 'negative', message: 'Fehler beim Austragen als Dienst', timeout: 10000, progress: true, actions: [{ icon: 'mdi-close', color: 'white' }], }); } } } const options = computed(() => hasPermission(PERMISSIONS.ASSIGN_OTHER) ? userStore.users.filter((v) => !enrolled(v.userid)) : !isEnrolled.value ? [mainStore.currentUser] : [] ); function canEdit(uid: string) { return uid === mainStore.currentUser.userid || hasPermission(PERMISSIONS.ASSIGN_OTHER); } function enrolled(userid: string) { return props.modelValue.services.findIndex((service) => service.userid == userid) !== -1; } const isEnrolled = computed(() => enrolled(mainStore.currentUser.userid)); const canEnroll = computed(() => { const is = isEnrolled.value; let sum = 0; props.modelValue.services.forEach((s) => (sum += s.value)); return sum < props.modelValue.required_services && !is; }); return { enroll, availableUsers, canEdit, isEnrolled, enrolled, enrollDialog, canEnroll, remove, userAvatar, userDisplay, options, iam, dialog, service, asHour, asDate, }; }, }); </script> <style scoped></style>