Compare commits

..

No commits in common. "5b657f4bf046230bfb8f39a6490ebe6ae1d6c130" and "ea64568e2bfc6dd351dd7cae7fb8239e69f78828" have entirely different histories.

9 changed files with 79 additions and 103 deletions

View File

@ -78,7 +78,12 @@
<q-btn color="primary" label="Schicht hinzufügen" @click="addJob()" /> <q-btn color="primary" label="Schicht hinzufügen" @click="addJob()" />
</q-card-section> </q-card-section>
<q-card-section v-for="(job, index) in event.jobs" :key="index"> <q-card-section v-for="(job, index) in event.jobs" :key="index">
<edit-job-slot v-model="event.jobs[index]" @remove-job="removeJob(index)" /> <q-card class="q-my-auto">
<edit-job-slot
v-model="event.jobs[index]"
@remove-job="removeJob(index)"
/>
</q-card>
</q-card-section> </q-card-section>
<q-card-actions align="around"> <q-card-actions align="around">
<q-card-actions align="left"> <q-card-actions align="left">
@ -95,15 +100,11 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, PropType, ref, onBeforeMount } from 'vue';
import { date, ModifyDateOptions } from 'quasar';
import { useEventStore } from '../../store';
import { notEmpty } from '@flaschengeist/api'; import { notEmpty } from '@flaschengeist/api';
import { IsoDateInput } from '@flaschengeist/api/components'; import { IsoDateInput } from '@flaschengeist/api/components';
import { useEventStore } from '../../store';
import { emptyEvent, emptyJob, EditableEvent } from '../../store/models';
import { date, ModifyDateOptions } from 'quasar';
import { computed, defineComponent, PropType, ref, onBeforeMount } from 'vue';
import EditJobSlot from './EditJobSlot.vue'; import EditJobSlot from './EditJobSlot.vue';
import RecurrenceRule from './RecurrenceRule.vue'; import RecurrenceRule from './RecurrenceRule.vue';
@ -119,8 +120,8 @@ export default defineComponent({
date: { date: {
required: false, required: false,
default: undefined, default: undefined,
type: String as PropType<string | undefined>, type: String as PropType<string|undefined>
}, }
}, },
emits: { emits: {
done: (val: boolean) => typeof val === 'boolean', done: (val: boolean) => typeof val === 'boolean',
@ -128,19 +129,33 @@ export default defineComponent({
setup(props, { emit }) { setup(props, { emit }) {
const store = useEventStore(); const store = useEventStore();
const startDate = computed(() => { const startDate = computed(() => {
const d = date.buildDate({ milliseconds: 0, seconds: 0, minutes: 0, hours: 0 }); const d = date.buildDate({milliseconds: 0, seconds: 0, minutes: 0, hours: 0})
if (!props.date || !date.isValid(props.date)) return d; if (!props.date || !date.isValid(props.date)) return d
const split = props.date.split('-'); const split = props.date.split('-');
return date.adjustDate(d, { return date.adjustDate(d, {year: parseInt(split[0]), month: parseInt(split[1]), date: parseInt(split[2])})
year: parseInt(split[0]), })
month: parseInt(split[1]),
date: parseInt(split[2]),
}); const emptyJob = () => ({
id: NaN,
start: date.adjustDate(startDate.value, {hours: (new Date()).getHours()}, true),
end: date.addToDate(date.adjustDate(startDate.value, {hours: (new Date()).getHours()}, true), {hours: 1}),
services: [],
required_services: 2,
type: store.jobTypes[0],
});
const emptyEvent = () => ({
id: NaN,
start: new Date(startDate.value),
jobs: [emptyJob()],
type: store.eventTypes[0],
is_template: false,
}); });
const templates = computed(() => store.templates); const templates = computed(() => store.templates);
const template = ref<FG.Event | undefined>(undefined); const template = ref<FG.Event | undefined>(undefined);
const event = ref<EditableEvent>(props.modelValue || emptyEvent(startDate.value)); const event = ref<FG.Event>(props.modelValue || emptyEvent());
const eventtypes = computed(() => store.eventTypes); const eventtypes = computed(() => store.eventTypes);
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 });
@ -169,7 +184,7 @@ export default defineComponent({
event.value.is_template = template; event.value.is_template = template;
try { try {
if (event.value?.id !== undefined) { if (!isNaN(event.value.id)) {
//fix //fix
} }
await store.addEvent(event.value); await store.addEvent(event.value);
@ -224,8 +239,7 @@ export default defineComponent({
template.value = undefined; template.value = undefined;
} }
const afterStart = (d: Date) => const afterStart = (d: Date) => !d || (event.value.start <= d || 'Das Veranstaltungsende muss vor dem Beginn liegen')
!d || event.value.start <= d || 'Das Veranstaltungsende muss vor dem Beginn liegen';
return { return {
addJob, addJob,

View File

@ -1,5 +1,5 @@
<template> <template>
<q-card class="fit row justify-start content-center items-center"> <q-card-section class="fit row justify-start content-center items-center">
<q-card-section class="fit row justify-start content-center items-center"> <q-card-section class="fit row justify-start content-center items-center">
<IsoDateInput <IsoDateInput
v-model="job.start" v-model="job.start"
@ -45,10 +45,8 @@
filled filled
/> />
</q-card-section> </q-card-section>
<q-card-actions> <q-btn label="Schicht löschen" color="negative" :disabled="jobCanDelete" @click="removeJob" />
<q-btn label="Schicht löschen" color="negative" :disabled="canDelete" @click="removeJob" /> </q-card-section>
</q-card-actions>
</q-card>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -65,10 +63,10 @@ export default defineComponent({
required: true, required: true,
type: Object as PropType<FG.Job>, type: Object as PropType<FG.Job>,
}, },
canDelete: { jobCanDelete: {
type: Boolean, type: Boolean,
default: false, default: false,
}, }
}, },
emits: { emits: {
'remove-job': () => true, 'remove-job': () => true,
@ -84,7 +82,7 @@ export default defineComponent({
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') {
return (props.modelValue as unknown as Record<string, unknown>)[prop]; return ((props.modelValue as unknown) as Record<string, unknown>)[prop];
} }
}, },
set(obj, prop, value) { set(obj, prop, value) {

View File

@ -1,5 +1,5 @@
<template> <template>
<q-page padding class="fit row justify-center content-start items-start q-gutter-sm"> <div>
<q-tabs v-if="$q.screen.gt.sm" v-model="tab"> <q-tabs v-if="$q.screen.gt.sm" v-model="tab">
<q-tab <q-tab
v-for="(tabindex, index) in tabs" v-for="(tabindex, index) in tabs"
@ -24,23 +24,25 @@
</q-item> </q-item>
</q-list> </q-list>
</q-drawer> </q-drawer>
<q-tab-panels <q-page padding class="fit row justify-center content-start items-start q-gutter-sm">
v-model="tab" <q-tab-panels
style="background-color: transparent" v-model="tab"
class="q-ma-none q-pa-none fit row justify-center content-start items-start" style="background-color: transparent"
animated class="q-ma-none q-pa-none fit row justify-center content-start items-start"
> animated
<q-tab-panel name="create"> >
<EditEvent :date="date" /> <q-tab-panel name="create">
</q-tab-panel> <EditEvent :date="date" />
<q-tab-panel name="eventtypes"> </q-tab-panel>
<ManageTypes title="Veranstaltungstyp" type="EventType" /> <q-tab-panel name="eventtypes">
</q-tab-panel> <ManageTypes title="Veranstaltungstyp" type="EventType" />
<q-tab-panel name="jobtypes"> </q-tab-panel>
<ManageTypes title="Dienstart" type="JobType" /> <q-tab-panel name="jobtypes">
</q-tab-panel> <ManageTypes title="Dienstart" type="JobType" />
</q-tab-panels> </q-tab-panel>
</q-page> </q-tab-panels>
</q-page>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -58,16 +60,14 @@ export default defineComponent({
date: { date: {
type: String, type: String,
required: false, required: false,
default: undefined, default: undefined
}, }
}, },
setup() { setup() {
const tabs = computed(() => [ const tabs = computed(() => [
{ name: 'create', label: 'Veranstaltungen' }, { name: 'create', label: 'Veranstaltungen' },
...(hasPermission(PERMISSIONS.JOB_TYPE) ? [{ name: 'jobtypes', label: 'Dienstarten' }] : []), ...(hasPermission(PERMISSIONS.JOB_TYPE) ? [{ name: 'jobtypes', label: 'Dienstarten' }] : []),
...(hasPermission(PERMISSIONS.EVENT_TYPE) ...(hasPermission(PERMISSIONS.EVENT_TYPE) ? [{ name: 'eventtypes', label: 'Veranstaltungsarten' }] : [])
? [{ name: 'eventtypes', label: 'Veranstaltungsarten' }]
: []),
]); ]);
const drawer = ref<boolean>(false); const drawer = ref<boolean>(false);
@ -82,6 +82,7 @@ export default defineComponent({
}, },
}); });
return { return {
showDrawer, showDrawer,
tab, tab,

View File

@ -19,7 +19,7 @@ export const innerRoutes: FG_Plugin.MenuRoute[] = [
route: { route: {
path: 'schedule-overview', path: 'schedule-overview',
name: 'schedule-overview', name: 'schedule-overview',
component: () => import('../pages/EventOverview.vue'), component: () => import('../pages/Overview.vue'),
}, },
}, },
{ {
@ -30,7 +30,7 @@ export const innerRoutes: FG_Plugin.MenuRoute[] = [
route: { route: {
path: 'schedule-management', path: 'schedule-management',
name: 'schedule-management', name: 'schedule-management',
component: () => import('../pages/EventManagement.vue'), component: () => import('../pages/Management.vue'),
props: (route) => ({date: route.query.date}), props: (route) => ({date: route.query.date}),
}, },
}, },
@ -41,7 +41,7 @@ export const innerRoutes: FG_Plugin.MenuRoute[] = [
route: { route: {
path: 'schedule-requests', path: 'schedule-requests',
name: 'schedule-requests', name: 'schedule-requests',
component: () => import('../pages/EventRequests.vue'), component: () => import('../pages/Requests.vue'),
}, },
}, },
], ],
@ -57,6 +57,6 @@ export const privateRoutes: FG_Plugin.NamedRouteRecordRaw[] = [
{ {
name: 'events-edit', name: 'events-edit',
path: 'schedule/:id/edit', path: 'schedule/:id/edit',
component: () => import('../pages/EventPage.vue'), component: () => import('../pages/Event.vue'),
}, },
]; ];

View File

@ -1,6 +1,9 @@
import { api, isAxiosError } from '@flaschengeist/api'; import { api, isAxiosError } from '@flaschengeist/api';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { EditableEvent } from './models';
interface UserService {
user: FG.Service;
}
function fixJob(job: FG.Job) { function fixJob(job: FG.Job) {
job.start = new Date(job.start); job.start = new Date(job.start);
@ -139,8 +142,8 @@ export const useEventStore = defineStore({
return api.post<FG.Job>(`/events/jobs/${jobId}/assign`, service); return api.post<FG.Job>(`/events/jobs/${jobId}/assign`, service);
}, },
async addEvent(event: EditableEvent) { async addEvent(event: FG.Event) {
if (event?.id === undefined) { if (isNaN(event.id)) {
const { data } = await api.post<FG.Event>('/events', event); const { data } = await api.post<FG.Event>('/events', event);
if (data.is_template) this.templates.push(data); if (data.is_template) this.templates.push(data);
return data; return data;
@ -153,12 +156,10 @@ export const useEventStore = defineStore({
} }
}, },
async sendInvite(job: FG.Job, invitees: FG.User[], isInvite = true) { async sendInvite(job: FG.Job, invitees: FG.User[], transfer = false) {
return api.post<FG.Event>('/events/transfer', { await Promise.resolve()
job: job.id, console.log(job, invitees, transfer)
receiver: invitees, return Promise.resolve()
is_invite: isInvite
});
} }
}, },
}); });

View File

@ -1,38 +0,0 @@
import { date } from 'quasar';
/** An new event does not contain an id and the type might be unset */
export type EditableEvent = Omit<Omit<Omit<FG.Event, 'jobs'>, 'type'>, 'id'> & {
type?: FG.EventType | number;
id?: number;
jobs: EditableJob[];
};
/** A new job does not have an id or type assigned */
export type EditableJob = Omit<Omit<FG.Job, 'type'>, 'id'> & {
type?: FG.EventType | number;
id?: number;
};
export function emptyJob(startDate = new Date()): EditableJob {
const start = date.adjustDate(startDate, {
hours: new Date().getHours(),
minutes: 0,
seconds: 0,
milliseconds: 0,
});
return {
start: start,
end: date.addToDate(start, { hours: 1 }),
services: [],
locked: false,
required_services: 2,
};
}
export function emptyEvent(startDate?: Date): EditableEvent {
return {
start: startDate === undefined ? new Date() : new Date(startDate),
jobs: [emptyJob(startDate)],
is_template: false,
};
}