Compare commits

..

No commits in common. "f539d2c3869fa3f94aad3cbfcc273d63fe151b4c" and "512e68f1ed462731f36abe611b8c5b9bda9888f4" have entirely different histories.

8 changed files with 45 additions and 93 deletions

View File

@ -1,53 +1,25 @@
<template> <template>
<q-card style="text-align: center"> <q-card class="row justify-center content-center" style="text-align: center">
<q-card-section class="row justify-center items-center content-center"> <q-card-section>
<div class="col-5"> <div class="text-h6 col-12">Dienste diesen Monat: {{ jobs }}</div>
<q-icon :name="jobs == 0 ? 'mdi-calendar-blank' : 'mdi-calendar-alert'" :size="divHeight" /> <!--TODO: Filters are deprecated! -->
</div> <!--<div class="text-h6 col-12">Nächster Dienst: {{ nextJob | date }}</div>-->
<div v-if="(jobs || 0) > 0" ref="div" class="col-7">
<div class="text-h6">Anstehende Dienste</div>
<div class="text-body1">{{ jobs }}</div>
<div class="text-h6">Nächster Dienst</div>
<div class="text-body1">{{ formatDate(nextJob) }}</div>
</div>
<div v-else ref="div" class="col-7">
<div class="text-subtitle1">Keine anstehenden Dienste</div>
</div>
</q-card-section> </q-card-section>
</q-card> </q-card>
</template> </template>
<script lang="ts"> <script lang="ts">
import { date } from 'quasar'; import { defineComponent } from 'vue';
import { computed, defineComponent, onBeforeMount, ref } from 'vue';
import { asHour, formatDateTime } from '@flaschengeist/api';
import { useEventStore } from '../store';
export default defineComponent({ export default defineComponent({
name: 'EventsWidget', name: 'EventsWidget',
setup() { setup() {
const store = useEventStore(); function randomNumber(start: number, end: number) {
return start + Math.floor(Math.random() * Math.floor(end));
const jobs = ref<number>();
const nextJob = ref<Date>();
const div = ref<HTMLElement>();
const divHeight = computed(() => `${div.value?.scrollHeight || '100'}px`);
onBeforeMount(() => {
void store.getJobs({ limit: 1, from: new Date() }).then(({ count, result }) => {
jobs.value = count;
nextJob.value = count > 0 ? result[0].start : undefined;
});
});
function formatDate(d?: Date) {
if (d === undefined) return '-';
if (date.isSameDate(d, new Date(), 'day')) return `Heute ${asHour(d)} Uhr`;
return formatDateTime(d, true, true, false, true) + ' Uhr';
} }
const jobs = randomNumber(0, 5);
return { div, divHeight, formatDate, jobs, nextJob }; const nextJob = new Date(2021, randomNumber(1, 12), randomNumber(1, 31));
return { jobs, nextJob };
}, },
}); });
</script> </script>

View File

@ -64,7 +64,7 @@
{{ timestamp.day }} {{ timestamp.day }}
<q-menu> <q-menu>
<q-list style="min-width: 100px"> <q-list style="min-width: 100px">
<q-item exact clickable @click="create(timestamp.date)"> <q-item exact :to="{ name: 'new-event', query: { date: timestamp.date } }">
<q-item-section>Neue Veranstaltung</q-item-section> <q-item-section>Neue Veranstaltung</q-item-section>
</q-item> </q-item>
</q-list> </q-list>
@ -95,7 +95,6 @@ import { date, QDate, QPopupProxy, useQuasar } from 'quasar';
import { startOfWeek } from '@flaschengeist/api'; import { startOfWeek } from '@flaschengeist/api';
import EditEvent from '../management/EditEvent.vue'; import EditEvent from '../management/EditEvent.vue';
import { QCalendarAgenda } from '@quasar/quasar-ui-qcalendar'; import { QCalendarAgenda } from '@quasar/quasar-ui-qcalendar';
import { EditableEvent, emptyEvent } from '../../store/models';
export default defineComponent({ export default defineComponent({
name: 'AgendaView', name: 'AgendaView',
@ -116,7 +115,7 @@ export default defineComponent({
calendarView.value == 'day' || quasar.screen.xs ? 1 : quasar.screen.sm ? 3 : 7 calendarView.value == 'day' || quasar.screen.xs ? 1 : quasar.screen.sm ? 3 : 7
); );
const events = ref<Agendas>({}); const events = ref<Agendas>({});
const editor = ref<EditableEvent>(); const editor = ref<FG.Event | undefined>(undefined);
interface Agendas { interface Agendas {
[index: number]: FG.Event[]; [index: number]: FG.Event[];
@ -126,9 +125,6 @@ export default defineComponent({
await loadAgendas(); await loadAgendas();
}); });
function create(ds: string) {
editor.value = emptyEvent(date.extractDate(ds, 'YYYY-MM-DD'));
}
async function edit(id: number) { async function edit(id: number) {
editor.value = await store.getEvent(id); editor.value = await store.getEvent(id);
} }
@ -160,12 +156,12 @@ export default defineComponent({
minutes: 0, minutes: 0,
hours: 0, hours: 0,
}); });
const start = calendarView.value === 'day' ? selected : startOfWeek(selected); const start = calendarRealView.value === 'day' ? selected : startOfWeek(selected);
const end = date.addToDate(start, { days: calendarDays.value }); const end = date.addToDate(start, { days: calendarDays.value });
events.value = {}; events.value = {};
const { result } = await store.getEvents({ from: start, to: end }); const list = await store.getEvents({ from: start, to: end });
result.forEach((event) => { list.forEach((event) => {
const day = event.start.getDay(); const day = event.start.getDay();
if (!events.value[day]) { if (!events.value[day]) {
@ -225,7 +221,6 @@ export default defineComponent({
calendarPrev, calendarPrev,
calendarRealView, calendarRealView,
calendarView, calendarView,
create,
edit, edit,
editor, editor,
editDone, editDone,

View File

@ -26,7 +26,7 @@
</q-item> </q-item>
<template v-for="(events, index) in agendas" :key="index"> <template v-for="(events, index) in agendas" :key="index">
<q-separator /> <q-separator />
<q-item-label overline>{{ index }}</q-item-label> <q-item-label overline>{{index}}</q-item-label>
<q-item v-for="(event, idx) in events" :key="idx" <q-item v-for="(event, idx) in events" :key="idx"
><event-slot :model-value="event" />{{ idx }}</q-item ><event-slot :model-value="event" />{{ idx }}</q-item
> >
@ -63,7 +63,7 @@ export default defineComponent({
const editor = ref<FG.Event | undefined>(undefined); const editor = ref<FG.Event | undefined>(undefined);
const events = ref<FG.Event[]>([]); const events = ref<FG.Event[]>([]);
const scrollDiv = ref<Element>(); const scrollDiv = ref<Element>()
const agendas = computed<Agendas>(() => { const agendas = computed<Agendas>(() => {
const ag = {} as Agendas; const ag = {} as Agendas;
@ -94,24 +94,21 @@ export default defineComponent({
async function load(index: number, done?: (stop: boolean) => void) { async function load(index: number, done?: (stop: boolean) => void) {
const start = new Date(); const start = new Date();
if (index < 0) { if (index < 0) {
const { result } = await store.getEvents({ to: start, limit: 5, descending: true }); events.value.unshift(...(await store.getEvents({ to: start, limit: 5, descending: true })));
events.value.unshift(...result);
if (done) done(false); if (done) done(false);
} else { } else {
const len = events.value.length; const len = events.value.length;
const { result } = await store.getEvents({ if (
from: start, len ==
offset: (index - 1) * 10, events.value.push(
limit: 10, ...(await store.getEvents({ from: start, offset: (index - 1) * 10, limit: 10 }))
}); )
if (len == events.value.push(...result)) { ) {
if (done) return done(true); if (done) return done(true);
} else if (done) done(false); } else if (done) done(false);
} }
if (index <= 1) { if (index <= 1) {
window.setTimeout(() => { window.setTimeout(() => {(<Element>scrollDiv.value).scrollTop = document.getElementById("bbb")?.scrollHeight || 0}, 150);
(<Element>scrollDiv.value).scrollTop = document.getElementById('bbb')?.scrollHeight || 0;
}, 150);
} }
} }
@ -162,8 +159,7 @@ export default defineComponent({
asYear, asYear,
asMonth, asMonth,
edit, edit,
editor, editor,scrollDiv,
scrollDiv,
editDone, editDone,
load, load,
remove, remove,

10
src/events.d.ts vendored
View File

@ -1,4 +1,4 @@
import { FG_Plugin } from '@flaschengeist/types'; import { FG_Plugin } from "@flaschengeist/types";
export interface RecurrenceRule { export interface RecurrenceRule {
frequency: string; frequency: string;
@ -13,13 +13,13 @@ interface InvitationData {
} }
interface InvitationResponseData { interface InvitationResponseData {
event: number; event: number,
job: number; job: number,
invitee: string; invitee: string
} }
export interface EventNotification extends FG_Plugin.Notification { export interface EventNotification extends FG_Plugin.Notification {
data: { data: {
type: number; type: number
} & (InvitationData | InvitationResponseData); } & (InvitationData | InvitationResponseData);
} }

View File

@ -30,10 +30,7 @@ function transpile(msg: FG_Plugin.Notification) {
message.link = { name: 'events-requests' }; message.link = { name: 'events-requests' };
} else if ((message.data.type & EventTypes._mask_) === EventTypes.invitation_response) { } else if ((message.data.type & EventTypes._mask_) === EventTypes.invitation_response) {
message.link = { message.link = {name: 'events-single-view', params: {id: (<InvitationResponseData>message.data).event}}
name: 'events-single-view',
params: { id: (<InvitationResponseData>message.data).event },
};
} }
return message; return message;
} }

View File

@ -53,7 +53,7 @@ export const privateRoutes: FG_Plugin.NamedRouteRecordRaw[] = [
name: 'events-single-view', name: 'events-single-view',
path: 'events/:id', path: 'events/:id',
component: () => import('../pages/EventPage.vue'), component: () => import('../pages/EventPage.vue'),
props: true, props: true
}, },
{ {
name: 'events-edit', name: 'events-edit',

View File

@ -107,15 +107,13 @@ export const useEventStore = defineStore({
}, },
async getEvents( async getEvents(
filter?: FG.PaginationFilter & { filter:
user?: string; | { from?: Date; to?: Date; limit?: number; offset?: number; descending?: boolean }
} | undefined = undefined
) { ) {
try { try {
const { data } = await api.get<FG.PaginationResponse<FG.Event>>('/events', { const { data } = await api.get<FG.Event[]>('/events', { params: filter });
params: <unknown>filter, data.forEach((element) => fixEvent(element));
});
data.result.forEach((element) => fixEvent(element));
return data; return data;
} catch (error) { } catch (error) {
throw error; throw error;
@ -168,15 +166,6 @@ export const useEventStore = defineStore({
.then(({ data }) => fixJob(data)); .then(({ data }) => fixJob(data));
}, },
async getJobs(filter?: FG.PaginationFilter) {
return api
.get<FG.PaginationResponse<FG.Job>>('/events/jobs', { params: <unknown>filter })
.then(({ data }) => {
data.result.forEach((j) => fixJob(j));
return data;
});
},
/** /**
* Send invite to job or transfer to other user * Send invite to job or transfer to other user
* @param job Job to invite to * @param job Job to invite to

View File

@ -16,6 +16,9 @@ export type EditableJob = Omit<Omit<FG.Job, 'type'>, 'id'> & {
export function emptyJob(startDate = new Date()): EditableJob { export function emptyJob(startDate = new Date()): EditableJob {
const start = date.adjustDate(startDate, { const start = date.adjustDate(startDate, {
hours: new Date().getHours(), hours: new Date().getHours(),
minutes: 0,
seconds: 0,
milliseconds: 0,
}); });
return { return {
start: start, start: start,
@ -26,9 +29,9 @@ export function emptyJob(startDate = new Date()): EditableJob {
}; };
} }
export function emptyEvent(startDate: Date = new Date()): EditableEvent { export function emptyEvent(startDate?: Date): EditableEvent {
return { return {
start: date.adjustDate(startDate, { hours: 0, minutes: 0, seconds: 0, milliseconds: 0 }), start: startDate === undefined ? new Date() : new Date(startDate),
jobs: [emptyJob(startDate)], jobs: [emptyJob(startDate)],
is_template: false, is_template: false,
}; };