Skip to content

Commit

Permalink
Feature/agenda improvements (#204)
Browse files Browse the repository at this point in the history
* agenda today and goto buttons

* link to agenda from closings admin view
  • Loading branch information
bbonf authored Apr 25, 2024
1 parent 7be3234 commit 80960b0
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 37 deletions.
19 changes: 11 additions & 8 deletions babex-vue/src/components/DateTimePicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@

<script lang="ts" setup>
import {defineEmits, defineProps } from 'vue';
import {formatDateTime} from '../util';
import {formatDate, formatDateTime} from '../util';

function parseDate(dateStr: string) : Date {
// unfortunately, the Intl date api doesn't provide a parsing function,
// so this is manually written to parse nl-NL date strings
const parts = dateStr.split(' ');
const datePart = parts[0];
const timePart = parts[1];
const timePart = props.time ? parts[1] : '00:00';
return new Date(
datePart.split('-').reverse().join('-') + 'T' + timePart
);
Expand All @@ -25,18 +25,21 @@
}
}

defineProps<{
const props = withDefaults(defineProps<{
modelValue: Date,
readonly?: boolean
}>();
readonly?: boolean,
time?: boolean
}>(), {
time: true
});

const emits = defineEmits(['update:modelValue']);
</script>

<template>
<div>
<input :readonly="readonly" class="form-control" type="text" :value="formatDateTime(modelValue)" @change="onChange">
</div>
<div>
<input :readonly="readonly" class="form-control" type="text" :value="props.time ? formatDateTime(modelValue): formatDate(modelValue)" @change="onChange">
</div>
</template>

<style scoped>
Expand Down
79 changes: 62 additions & 17 deletions babex-vue/src/components/agenda/AgendaCalendar.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
<script lang="ts" setup>
import '@fullcalendar/core/vdom';
import { _ } from '@/util';
import FullCalendar from '@fullcalendar/vue3';
import dayGridPlugin from '@fullcalendar/daygrid';
import timeGridPlugin from '@fullcalendar/timegrid';
import interactionPlugin from '@fullcalendar/interaction';
import type {EventInput, EventContentArg, CalendarOptions, EventSourceApi} from '@fullcalendar/core';
import {defineEmits, defineExpose, defineProps, ref} from 'vue';
import type { EventInput, EventContentArg, CalendarOptions, EventSourceApi } from '@fullcalendar/core';
import { defineEmits, defineExpose, defineProps, ref } from 'vue';
import {urls} from '../../urls';
import DateTimePicker from '../DateTimePicker.vue';
import { urls } from '../../urls';
const props = defineProps<{
// optional starting date of valid selection range (iso format)
Expand All @@ -18,7 +20,7 @@
scheduling?: boolean,
}>();
function formatAppointment(event: EventInput) : EventInput {
function formatAppointment(event: EventInput): EventInput {
return {
id: event.id,
start: event.start,
Expand All @@ -35,7 +37,7 @@
};
}
function formatClosing(event: EventInput) : EventInput {
function formatClosing(event: EventInput): EventInput {
return {
original: event,
id: event.id,
Expand All @@ -49,16 +51,33 @@
};
}
function showGoToDate() {
goToModal.value = true;
}
function goToDate() {
calendar.value?.calendar.gotoDate(date.value);
goToModal.value = false;
}
const emit = defineEmits(['select', 'eventClick']);
const calendar = ref<typeof FullCalendar|null>(null);
const calendar = ref<typeof FullCalendar | null>(null);
const goToModal = ref<boolean>(false);
const date = ref<Date>(new Date());
const calendarOptions: CalendarOptions = {
plugins: [ dayGridPlugin, timeGridPlugin, interactionPlugin ],
plugins: [dayGridPlugin, timeGridPlugin, interactionPlugin],
initialView: 'dayGridMonth',
customButtons: {
goto: {
text: _('go to'),
click: showGoToDate
}
},
headerToolbar: {
end: 'dayGridMonth timeGridWeek today prev,next',
end: 'dayGridMonth timeGridWeek prev,today,next goto',
},
allDaySlot: false,
slotMinTime: "07:00:00",
Expand Down Expand Up @@ -101,10 +120,10 @@
return {
html: `<div class="fc-event-main-frame ${className}"><div class="fc-event-time">${arg.timeText}</div>
<div class="fc-event-title-container">
<div class="fc-event-title fc-sticky">${arg.event.title}</div>
</div></div>
<div>${arg.event.extendedProps.extra ?? ''}</div>`
<div class="fc-event-title-container">
<div class="fc-event-title fc-sticky">${arg.event.title}</div>
</div></div>
<div>${arg.event.extendedProps.extra ?? ''}</div>`
}
}
Expand All @@ -113,11 +132,33 @@
calendarApi.getEventSources().forEach((src: EventSourceApi) => src.refetch());
}
defineExpose({calendar, refresh});
defineExpose({ calendar, refresh });
</script>

<template>
<FullCalendar ref="calendar" :options="calendarOptions" />
<FullCalendar ref="calendar" :options="calendarOptions" />

<Teleport to="body">
<div v-if="goToModal">
<div id="modal-backdrop" class="modal-backdrop fade show" style="display:block;"></div>
<div id="modal" class="modal fade show" tabindex="-1" style="display:block;">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-body">
<form @submit="goToDate()">
<DateTimePicker :time="false" v-model="date"/>
</form>
</div>
<div class="modal-footer">
<button @click="goToDate()" type="button" class="btn btn-primary">{{ _('Confirm') }}</button>
<button @click="goToModal = false" type="button" class="btn btn-secondary">{{ _('Cancel')}}</button>
</div>
</div>
</div>
</div>
</div>
</Teleport>

</template>

<style>
Expand All @@ -139,11 +180,14 @@
background: unset;
}
table tbody tr.no-background:hover, table tbody tr.no-background {
table tbody tr.no-background:hover,
table tbody tr.no-background {
background: unset;
}
table tbody td, table thead th, table tfoot th {
table tbody td,
table thead th,
table tfoot th {
padding: unset;
}
Expand All @@ -156,7 +200,8 @@
border-color: #8ac4fd;
}
.event-canceled div, .event-canceled + div {
.event-canceled div,
.event-canceled+div {
text-decoration: line-through;
}
</style>
28 changes: 16 additions & 12 deletions lab/agenda/models.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
from django.db import models
from django.utils.timezone import localdate
from django.utils.translation import gettext_lazy as _

from rest_framework import serializers

from experiments.models import Location


class Closing(models.Model):
start = models.DateTimeField(_('agenda:closing:attribute:start'), db_index=True)
end = models.DateTimeField(_('agenda:closing:attribute:end'), db_index=True)
start = models.DateTimeField(_("agenda:closing:attribute:start"), db_index=True)
end = models.DateTimeField(_("agenda:closing:attribute:end"), db_index=True)

# SET_NULL will let us keep closings history if for some reason a location is removed
location = models.ForeignKey(Location, on_delete=models.SET_NULL, null=True,
verbose_name=_('agenda:closing:attribute:location'))
location = models.ForeignKey(
Location, on_delete=models.SET_NULL, null=True, verbose_name=_("agenda:closing:attribute:location")
)

# used to indicate entire lab is closed
is_global = models.BooleanField(_('agenda:cosing:attribute:is_global'))
is_global = models.BooleanField(_("agenda:cosing:attribute:is_global"))

comment = models.TextField(_("agenda:cosing:attribute:comment"), null=True)

comment = models.TextField(_('agenda:cosing:attribute:comment'), null=True)
@property
def start_localdate(self):
"""returns only the date part of self.start, but in the local timezone"""
return localdate(self.start)


class ClosingSerializer(serializers.ModelSerializer):
class Meta:
model = Closing
fields = ['id', 'start', 'end', 'is_global', 'comment', 'location',
'location_name']
fields = ["id", "start", "end", "is_global", "comment", "location", "location_name"]

location_name = serializers.StringRelatedField(source='location') # type: ignore
location = serializers.PrimaryKeyRelatedField(queryset=Location.objects.all(),
allow_null=True)
location_name = serializers.StringRelatedField(source="location") # type: ignore
location = serializers.PrimaryKeyRelatedField(queryset=Location.objects.all(), allow_null=True)
5 changes: 5 additions & 0 deletions lab/agenda/templates/agenda/closings_admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ <h1 class="h2">
<th>
{% get_verbose_field_name "agenda" "Closing" "comment" %}
</th>
<th>
</th>
</tr>
</thead>

Expand All @@ -66,6 +68,9 @@ <h1 class="h2">
<td>
{{ closing.comment|default_if_none:'' }}
</td>
<td>
<a href="{% url 'agenda:agenda.date' closing.start_localdate %}">agenda</a>
</td>
</tr>
{% endfor %}
</tbody>
Expand Down

0 comments on commit 80960b0

Please sign in to comment.