Skip to content
This repository has been archived by the owner on Sep 5, 2019. It is now read-only.

Commit

Permalink
Adds basic side-bar interaction to reservation calendar
Browse files Browse the repository at this point in the history
  • Loading branch information
Denis Krienbühl committed Apr 19, 2016
1 parent 8547e2a commit 5de3178
Show file tree
Hide file tree
Showing 10 changed files with 253 additions and 67 deletions.
4 changes: 3 additions & 1 deletion onegov/town/assets/js/locale.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
var locales = {
de: {
"Reservations": "Reservationen",
"Select allocations on the right to reserve them": "Wählen Sie die gewünschten Daten rechts aus"
"Select allocations on the left to reserve them": "Wählen Sie die gewünschten Daten links aus",
"Reserve": "Reservieren",
"Remove": "Entfernen"
}
};

Expand Down
75 changes: 65 additions & 10 deletions onegov/town/assets/js/reservationcalendar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ var defaultOptions = {
*/
feed: null,

/*
Returns the reservations for the current resource.
*/
reservations: null,

/*
The type of the calendar. Either 'room' or 'daypass'
*/
Expand Down Expand Up @@ -58,6 +63,11 @@ var defaultOptions = {
highlights: []
};

rc.events = [
'rc-reservation-error',
'rc-reservations-changed'
];

rc.getFullcalendarOptions = function(options) {
var rcOptions = $.extend(true, defaultOptions, options);

Expand All @@ -73,7 +83,8 @@ rc.getFullcalendarOptions = function(options) {
highlights: rcOptions.highlights,
afterSetup: [],
viewRenderers: [],
eventRenderers: []
eventRenderers: [],
reservations: rcOptions.reservations
};

// the reservation calendar type definition
Expand All @@ -83,16 +94,17 @@ rc.getFullcalendarOptions = function(options) {
case 'daypass':
views = ['month'];
fcOptions.header = {
left: 'title',
right: 'today prev, next'
left: 'title today prev,next',
center: '',
right: ''
};
break;
case 'room':
views = ['month', 'agendaWeek', 'agendaDay'];
fcOptions.header = {
left: views.join(','),
center: 'title',
right: 'today prev,next'
left: 'title today prev,next',
center: '',
right: views.join(',')
};
break;
default:
Expand Down Expand Up @@ -220,21 +232,31 @@ rc.spawnPopup = function(event, element) {
'type': 'tooltip',
'onopen': function() {
var popup = $(this);
var links = popup.find('a');

// hookup all links with intercool
Intercooler.processNodes(links);

// hookup the confirmation dialog
var confirm_links = popup.find('a.confirm');

Intercooler.processNodes(confirm_links);
confirm_links.confirmation();

$(confirm_links).on('success.ic', function() {
$('.calendar').fullCalendar('refetchEvents');
});

// any link clicked will close the popup
popup.find('a').click(function() {
links.click(function() {
popup.popup('hide');
});

// pass all reservationcalendar links to the window
_.each(rc.events, function(eventName) {
links.on(eventName, _.debounce(function(data) {
$(window).trigger(eventName, data);
}));
});

},
'onclose': function() {
$(element).removeClass('has-popup');
Expand Down Expand Up @@ -276,6 +298,10 @@ rc.setupHistory = function(fcOptions) {

fcOptions.afterSetup.push(function(calendar) {
window.onpopstate = function(event) {
if (event.state === null) {
return;
}

isPopping = true;
calendar.fullCalendar('changeView', event.state.view);
calendar.fullCalendar('gotoDate', event.state.date);
Expand Down Expand Up @@ -306,6 +332,18 @@ rc.setupReservationSelect = function(fcOptions) {
fcOptions.viewRenderers.push(function() {
rc.resizeReservationSelection(selection);
});

$(window).on('rc-reservation-error', function() {
console.log('error');
});

$(window).on('rc-reservations-changed', function() {
$.getJSON(fcOptions.reservations, function(reservations) {
rc.renderReservationSelection(selection.get(0), reservations);
});
});

$(window).trigger('rc-reservations-changed');
};

// renders the occupied partitions on an event
Expand Down Expand Up @@ -456,8 +494,25 @@ ReservationSelection = React.createClass({
<h3>{locale("Reservations")}</h3>
{
this.props.reservations.length === 0 &&
<p>{locale("Select allocations on the right to reserve them")}</p>
<p>{locale("Select allocations on the left to reserve them")}</p>
}
{
this.props.reservations.length > 0 &&
<ul>{
_.map(this.props.reservations, function(r, ix) {
return (
<li key={ix} className={r.className + " reservation"}>
<span className="reservation-date">{r.date}</span>
<span className="reservation-time">{r.time}</span>
<a href="#">{locale('Remove')}</a>
</li>
);
})
}</ul>
}
<a href="#" className={this.props.reservations.length === 0 && 'disabled button secondary' || 'button secondary'}>
{locale("Reserve")}
</a>
</div>
);
}
Expand Down
3 changes: 2 additions & 1 deletion onegov/town/assets/js/reservationcalendar_custom.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ var setupReservationCalendar = function(calendar) {
editUrl: calendar.data('edit-url'),
view: calendar.data('view'),
date: calendar.data('date'),
highlights: calendar.data('highlights')
highlights: calendar.data('highlights'),
reservations: calendar.data('reservations')
});
};

Expand Down
3 changes: 3 additions & 0 deletions onegov/town/elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ def __call__(self, request, extra_classes=None):
if self.request_method == 'GET':
a.attrib['href'] = self.url

if self.request_method == 'POST':
a.attrib['ic-post-to'] = self.url

if self.request_method == 'DELETE':
url = URL(self.url).query_param(
'csrf-token', request.new_csrf_token())
Expand Down
1 change: 1 addition & 0 deletions onegov/town/templates/resource.pt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

<div class="calendar"
data-feed="${feed}"
data-reservations="${request.link(resource, name='reservations')}"
data-type="${resource.type}"
data-editable="${request.is_logged_in and 'true' or 'false'}"
data-select-url="${request.link(resource, name='neue-einteilung')}"
Expand Down
65 changes: 52 additions & 13 deletions onegov/town/theme/styles/town.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1793,6 +1793,23 @@ button {

.fc-toolbar {
margin-bottom: 0;
width: 80%;

h2 {
clear: both;
display: block;
float: none;
margin-bottom: 1rem;
text-align: left;
}

.fc-left {
float: none;

button {
margin-left: 0;
}
}
}

.calendar-occupied {
Expand Down Expand Up @@ -2470,25 +2487,47 @@ ul.search-results {
Reservation calendar
*/
.reservation-selection {
border: 1px solid $gainsboro;
border-right: 0;
float: left;
float: right;
padding: 0 0 0 20px;
width: 20%;

h3 {
background-color: $white-smoke;
border-bottom: 1px solid $gainsboro;
p {
font-size: .875rem;
font-weight: bold;
line-height: 18px;
padding: 1ex;
}

ul {
font-size: .8rem;
list-style: none;
margin: 0;
text-align: center;
}

p {
font-size: .875rem;
padding: 1ex;
text-align: center;
li {
display: block;
margin: 10px 0;
}

.button {
border-radius: 3px;
display: block;
margin: 0;
}

.reservation-date {
display: block;
font-weight: bold;

&::before {
content: '\f274';
font-family: 'FontAwesome';
margin-right: 1ex;
}
}

a,
.reservation-time {
display: block;
margin-left: 1.4rem;
}
}

Expand Down
54 changes: 45 additions & 9 deletions onegov/town/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
from datetime import datetime, time
from functools import lru_cache
from isodate import parse_date, parse_datetime
from itertools import groupby
from libres.modules import errors as libres_errors
from lxml.html import fragments_fromstring, tostring
from onegov.ticket import TicketCollection
from onegov.town import _
from onegov.town.elements import DeleteLink, Link
from operator import attrgetter
from uuid import uuid4


def add_class_to_node(node, classname):
Expand Down Expand Up @@ -112,6 +115,28 @@ def __init__(self, allocation, availability, request):
self.request = request
self.translate = request.translate

@classmethod
def from_allocations(cls, request, scheduler, allocations):
events = []

for key, group in groupby(allocations, key=attrgetter('_start')):
grouped = tuple(group)
availability = scheduler.queries.availability_by_allocations(
grouped
)

for allocation in grouped:
if allocation.is_master:
events.append(
cls(
allocation,
availability,
request
)
)

return events

@property
def event_start(self):
return self.allocation.display_start().isoformat()
Expand Down Expand Up @@ -185,9 +210,10 @@ def event_actions(self):
)
else:
yield Link(
_("Reserve"),
self.request.link(self.allocation, name='reservieren'),
classes=('new-reservation', )
_("Select"),
self.request.link(self.allocation, name='reserve'),
request_method='POST',
classes=('new-reservation', ),
)

if self.request.is_logged_in:
Expand Down Expand Up @@ -299,17 +325,20 @@ def as_dict(self):
}


def get_libres_error(e, request):
assert type(e) in libres_error_messages, (
"Unknown libres error {}".format(type(e))
)

return request.translate(libres_error_messages.get(type(e)))


def show_libres_error(e, request):
""" Shows a human readable error message for the given libres exception,
using request.alert.
"""

assert type(e) in libres_error_messages, (
"Unknown libres error {}".format(type(e))
)

request.alert(request.translate(libres_error_messages.get(type(e))))
request.alert(get_libres_error(e, request))


def djb2_hash(text, size):
Expand Down Expand Up @@ -352,3 +381,10 @@ def get_user_color(username):
int(round(g * 255)),
int(round(b * 255))
)


def get_libres_session_id(request):
if not request.browser_session.has('libres_session_id'):
request.browser_session.libres_session_id = uuid4()

return request.browser_session.libres_session_id
Loading

0 comments on commit 5de3178

Please sign in to comment.