From 4a2d0a64f6886bfcf6c96b6b2d82e0397ee5ec8a Mon Sep 17 00:00:00 2001 From: Drew Regitsky Date: Wed, 9 Dec 2015 16:41:30 -0800 Subject: [PATCH] fix(quickschedule): Several UI fixes Summary: Fixes a number of smaller UI issues. Fixes T6173, T6207 Full list of changes: - Ensure time slots / days display in order - Allow time blocks of any size to be set on half hour intervals - Don't reset calendar when changing event length - Expand calendar on window resize - Change window title from "Electron" - Add delete button to cancel individual calendar events - Move event details box to the left side - Prevent addition of duplicate time slots Test Plan: manual Reviewers: bengotow Reviewed By: bengotow Maniphest Tasks: T6173, T6207 Differential Revision: https://phab.nylas.com/D2333 --- examples/N1-Quick-Schedule/calendar.html | 63 ++++++++++++++----- .../lib/availability-composer-extension.cjsx | 1 - .../lib/calendar-button.cjsx | 5 +- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/examples/N1-Quick-Schedule/calendar.html b/examples/N1-Quick-Schedule/calendar.html index f65a45716..1a4b8c779 100644 --- a/examples/N1-Quick-Schedule/calendar.html +++ b/examples/N1-Quick-Schedule/calendar.html @@ -48,8 +48,14 @@ return match && decodeURIComponent(match[1].replace(/\+/g, ' ')); } + function resizeCalendar() { + $('#calendar').fullCalendar('option', 'height', $(window).height()-55); + } + var availableTimes = []; + var eventSlots = {}; var meetingLength = 0.5; + var nextId = 0; function resetCalendar(opts,firstCall) { if(!firstCall) $('#calendar').fullCalendar("destroy"); if(!opts) opts = {}; @@ -61,7 +67,20 @@ right: 'today' }, defaultView: 'agendaWeek', - handleWindowResize: false, + handleWindowResize: true, + windowResize: function(){ + resizeCalendar(); + }, + eventRender: function(event, element) { + if(event.id === "available") { + element.append( "" ); + element.find(".closeon").click(function() { + $('#calendar').fullCalendar('removeEvents',function(e){return e===event}); + availableTimes = availableTimes.filter(function(e){return e.ext_id !== event.ext_id}); + delete eventSlots[event.start.format() + event.end.format()]; + }); + } + }, aspectRatio: 1.3, timezone: 'local', selectable: true, @@ -73,18 +92,22 @@ var new_events = []; //increment through selected time range, in blocks of size `meetingLength` while(start.isBefore(end)) { - new_events.push({ + e = { title: "Available", start: moment(start), end: moment(start).add(meetingLength, "hours"), color:"#8CA", - id: "available" - }); + id: "available", + ext_id: nextId++ + }; + if(!eventSlots[e.start.format() + e.end.format()]) + new_events.push(e); start.add(meetingLength, "hours"); } //add the events to the calendar and to `availableTimes` new_events.forEach(function(e){ availableTimes.push(e); + eventSlots[e.start.format() + e.end.format()] = true; $('#calendar').fullCalendar('renderEvent', e, true); }); $('#calendar').fullCalendar('unselect'); @@ -112,6 +135,7 @@ defaults[key] = opts[key]; } $('#calendar').fullCalendar(defaults); + resizeCalendar(); } $(document).ready(function() { @@ -125,16 +149,12 @@ $("#reset").click(function(e){ $('#calendar').fullCalendar('removeEvents', "available"); availableTimes = []; + eventSlots = {}; }); //handle meeting length dropdown $("#meeting-length").change(function(e){ meetingLength = parseFloat($(this).val()); - $('#calendar').fullCalendar('removeEvents', "available"); - availableTimes = []; - resetCalendar({ - snapDuration: {hours: meetingLength} - }); }); //handle done button click @@ -155,7 +175,7 @@ " ("+moment().tz(moment.tz.guess()).format("z")+")", //local time zone abbrev serverKey: randomId(128) //string to access this time slot on the server } - }) + }).sort(function(a,b) { return a.start - b.start }) }); window.close(); }); @@ -168,8 +188,8 @@ #calendar { position: fixed; - left: 5px; - right: 205px; + left: 205px; + right: 5px; top: 50px; bottom: 5px; } @@ -180,7 +200,7 @@ #options { position: fixed; width: 200px; - right: 0; + left: 0; top: 45px; bottom: 0; padding: 5px; @@ -208,6 +228,21 @@ height: 150px; } + .closeon { + display: none; + color: #000; + position: absolute; + right: 0; + top: 0; + z-index: 100; + cursor: pointer; + } + .fc-event:hover .closeon { + display: block; + } + .fc-event:hover .closeon:hover { + color: #800; + } @@ -241,7 +276,7 @@
- +

Use this tool to offer options for scheduling a meeting or event. Click and drag in the calendar to select time ranges when you're available. Enter event details on the left, diff --git a/examples/N1-Quick-Schedule/lib/availability-composer-extension.cjsx b/examples/N1-Quick-Schedule/lib/availability-composer-extension.cjsx index 079b0a9ca..d065bd8f6 100644 --- a/examples/N1-Quick-Schedule/lib/availability-composer-extension.cjsx +++ b/examples/N1-Quick-Schedule/lib/availability-composer-extension.cjsx @@ -17,7 +17,6 @@ class AvailabilityComposerExtension extends ComposerExtension data.attendees = [] data.attendees = participants.map (p) -> name: p.name, email: p.email, isSender: p.isMe() - console.log "Sending request!\n",JSON.stringify data serverUrl = "https://quickschedule.herokuapp.com/register-events" request.post {url: serverUrl, body: JSON.stringify(data)}, (error, resp, data) => console.log(error,resp,data) diff --git a/examples/N1-Quick-Schedule/lib/calendar-button.cjsx b/examples/N1-Quick-Schedule/lib/calendar-button.cjsx index 4c2eafb20..eb0350b8e 100644 --- a/examples/N1-Quick-Schedule/lib/calendar-button.cjsx +++ b/examples/N1-Quick-Schedule/lib/calendar-button.cjsx @@ -12,11 +12,12 @@ class CalendarButton extends React.Component _onClick: => BrowserWindow = require('remote').require('browser-window') w = new BrowserWindow + title: 'N1 QuickSchedule' nodeIntegration: false webPreferences: webSecurity:false - width: 700 - height: 600 + width: 800 + height: 650 # Here, we load an arbitrary html file into the Composer! path = require 'path'