mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-01-30 20:07:48 +08:00
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
This commit is contained in:
parent
2dc43d141b
commit
a3e986d94a
3 changed files with 52 additions and 17 deletions
|
@ -48,8 +48,14 @@
|
||||||
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
|
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resizeCalendar() {
|
||||||
|
$('#calendar').fullCalendar('option', 'height', $(window).height()-55);
|
||||||
|
}
|
||||||
|
|
||||||
var availableTimes = [];
|
var availableTimes = [];
|
||||||
|
var eventSlots = {};
|
||||||
var meetingLength = 0.5;
|
var meetingLength = 0.5;
|
||||||
|
var nextId = 0;
|
||||||
function resetCalendar(opts,firstCall) {
|
function resetCalendar(opts,firstCall) {
|
||||||
if(!firstCall) $('#calendar').fullCalendar("destroy");
|
if(!firstCall) $('#calendar').fullCalendar("destroy");
|
||||||
if(!opts) opts = {};
|
if(!opts) opts = {};
|
||||||
|
@ -61,7 +67,20 @@
|
||||||
right: 'today'
|
right: 'today'
|
||||||
},
|
},
|
||||||
defaultView: 'agendaWeek',
|
defaultView: 'agendaWeek',
|
||||||
handleWindowResize: false,
|
handleWindowResize: true,
|
||||||
|
windowResize: function(){
|
||||||
|
resizeCalendar();
|
||||||
|
},
|
||||||
|
eventRender: function(event, element) {
|
||||||
|
if(event.id === "available") {
|
||||||
|
element.append( "<span class='closeon'>✕</span>" );
|
||||||
|
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,
|
aspectRatio: 1.3,
|
||||||
timezone: 'local',
|
timezone: 'local',
|
||||||
selectable: true,
|
selectable: true,
|
||||||
|
@ -73,18 +92,22 @@
|
||||||
var new_events = [];
|
var new_events = [];
|
||||||
//increment through selected time range, in blocks of size `meetingLength`
|
//increment through selected time range, in blocks of size `meetingLength`
|
||||||
while(start.isBefore(end)) {
|
while(start.isBefore(end)) {
|
||||||
new_events.push({
|
e = {
|
||||||
title: "Available",
|
title: "Available",
|
||||||
start: moment(start),
|
start: moment(start),
|
||||||
end: moment(start).add(meetingLength, "hours"),
|
end: moment(start).add(meetingLength, "hours"),
|
||||||
color:"#8CA",
|
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");
|
start.add(meetingLength, "hours");
|
||||||
}
|
}
|
||||||
//add the events to the calendar and to `availableTimes`
|
//add the events to the calendar and to `availableTimes`
|
||||||
new_events.forEach(function(e){
|
new_events.forEach(function(e){
|
||||||
availableTimes.push(e);
|
availableTimes.push(e);
|
||||||
|
eventSlots[e.start.format() + e.end.format()] = true;
|
||||||
$('#calendar').fullCalendar('renderEvent', e, true);
|
$('#calendar').fullCalendar('renderEvent', e, true);
|
||||||
});
|
});
|
||||||
$('#calendar').fullCalendar('unselect');
|
$('#calendar').fullCalendar('unselect');
|
||||||
|
@ -112,6 +135,7 @@
|
||||||
defaults[key] = opts[key];
|
defaults[key] = opts[key];
|
||||||
}
|
}
|
||||||
$('#calendar').fullCalendar(defaults);
|
$('#calendar').fullCalendar(defaults);
|
||||||
|
resizeCalendar();
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
@ -125,16 +149,12 @@
|
||||||
$("#reset").click(function(e){
|
$("#reset").click(function(e){
|
||||||
$('#calendar').fullCalendar('removeEvents', "available");
|
$('#calendar').fullCalendar('removeEvents', "available");
|
||||||
availableTimes = [];
|
availableTimes = [];
|
||||||
|
eventSlots = {};
|
||||||
});
|
});
|
||||||
|
|
||||||
//handle meeting length dropdown
|
//handle meeting length dropdown
|
||||||
$("#meeting-length").change(function(e){
|
$("#meeting-length").change(function(e){
|
||||||
meetingLength = parseFloat($(this).val());
|
meetingLength = parseFloat($(this).val());
|
||||||
$('#calendar').fullCalendar('removeEvents', "available");
|
|
||||||
availableTimes = [];
|
|
||||||
resetCalendar({
|
|
||||||
snapDuration: {hours: meetingLength}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//handle done button click
|
//handle done button click
|
||||||
|
@ -155,7 +175,7 @@
|
||||||
" ("+moment().tz(moment.tz.guess()).format("z")+")", //local time zone abbrev
|
" ("+moment().tz(moment.tz.guess()).format("z")+")", //local time zone abbrev
|
||||||
serverKey: randomId(128) //string to access this time slot on the server
|
serverKey: randomId(128) //string to access this time slot on the server
|
||||||
}
|
}
|
||||||
})
|
}).sort(function(a,b) { return a.start - b.start })
|
||||||
});
|
});
|
||||||
window.close();
|
window.close();
|
||||||
});
|
});
|
||||||
|
@ -168,8 +188,8 @@
|
||||||
|
|
||||||
#calendar {
|
#calendar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 5px;
|
left: 205px;
|
||||||
right: 205px;
|
right: 5px;
|
||||||
top: 50px;
|
top: 50px;
|
||||||
bottom: 5px;
|
bottom: 5px;
|
||||||
}
|
}
|
||||||
|
@ -180,7 +200,7 @@
|
||||||
#options {
|
#options {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
right: 0;
|
left: 0;
|
||||||
top: 45px;
|
top: 45px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
@ -208,6 +228,21 @@
|
||||||
height: 150px;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
@ -241,7 +276,7 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button class="btn btn-default" id="reset">Reset</button>
|
<button class="btn btn-default" id="reset">Reset</button>
|
||||||
<button class="btn btn-default" id="done">Done</button>
|
<button class="btn btn-primary" id="done">Done</button>
|
||||||
</div>
|
</div>
|
||||||
<p> Use this tool to offer options for scheduling a meeting or event. Click and drag in the
|
<p> 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,
|
calendar to select time ranges when you're available. Enter event details on the left,
|
||||||
|
|
|
@ -17,7 +17,6 @@ class AvailabilityComposerExtension extends ComposerExtension
|
||||||
data.attendees = []
|
data.attendees = []
|
||||||
data.attendees = participants.map (p) ->
|
data.attendees = participants.map (p) ->
|
||||||
name: p.name, email: p.email, isSender: p.isMe()
|
name: p.name, email: p.email, isSender: p.isMe()
|
||||||
console.log "Sending request!\n",JSON.stringify data
|
|
||||||
serverUrl = "https://quickschedule.herokuapp.com/register-events"
|
serverUrl = "https://quickschedule.herokuapp.com/register-events"
|
||||||
request.post {url: serverUrl, body: JSON.stringify(data)}, (error, resp, data) =>
|
request.post {url: serverUrl, body: JSON.stringify(data)}, (error, resp, data) =>
|
||||||
console.log(error,resp,data)
|
console.log(error,resp,data)
|
||||||
|
|
|
@ -12,11 +12,12 @@ class CalendarButton extends React.Component
|
||||||
_onClick: =>
|
_onClick: =>
|
||||||
BrowserWindow = require('remote').require('browser-window')
|
BrowserWindow = require('remote').require('browser-window')
|
||||||
w = new BrowserWindow
|
w = new BrowserWindow
|
||||||
|
title: 'N1 QuickSchedule'
|
||||||
nodeIntegration: false
|
nodeIntegration: false
|
||||||
webPreferences:
|
webPreferences:
|
||||||
webSecurity:false
|
webSecurity:false
|
||||||
width: 700
|
width: 800
|
||||||
height: 600
|
height: 650
|
||||||
|
|
||||||
# Here, we load an arbitrary html file into the Composer!
|
# Here, we load an arbitrary html file into the Composer!
|
||||||
path = require 'path'
|
path = require 'path'
|
||||||
|
|
Loading…
Reference in a new issue