Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add driver slot interface #61

Merged
merged 53 commits into from
Jan 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
b40a719
Add preliminary calendar implementation
backspace Dec 5, 2017
83cef49
Merge branch 'primary' into slots
backspace Dec 9, 2017
cfc02ba
Add preliminary display of commitments
backspace Dec 10, 2017
7bef97c
Add ability to delete commitments
backspace Dec 10, 2017
8b3f7b2
Add ability to commit to a slot
backspace Dec 10, 2017
766aee4
Merge branch 'primary' into slots
backspace Dec 20, 2017
570b3bb
Add step toward token requirement
backspace Dec 20, 2017
9614b4d
Merge branch 'primary' into slots
backspace Dec 20, 2017
1a34e20
Correct commitment-creation with token
backspace Dec 21, 2017
aef544b
Add progress toward magic token exchange
backspace Dec 21, 2017
c91f975
Merge branch 'primary' into slots
backspace Dec 21, 2017
23ef370
Update slot assertions
backspace Dec 21, 2017
e3bf69f
Update Ember Power Calendar
backspace Dec 21, 2017
4f718e8
Remove Ember Simple Auth for person tokens
backspace Dec 21, 2017
82c1d5f
Add token encoding and proper header
backspace Dec 21, 2017
2cb3cac
Add tokens to Mirage person model
backspace Dec 21, 2017
9db53ca
Add display of person token’s email address
backspace Dec 22, 2017
a1b5492
Add handling for magic token exchange failure
backspace Dec 24, 2017
6d2be05
Add handling for a missing magic token
backspace Dec 24, 2017
d8bfad6
Add handling for person-fetch failure
backspace Dec 24, 2017
4b225a3
Add handling for commitment-deletion failure
backspace Dec 24, 2017
4f68620
Add preliminary calendar styling
backspace Dec 24, 2017
4ba0bcc
Add handling for commitment creation failure
backspace Dec 24, 2017
a7359be
Restore storage of person token
backspace Dec 24, 2017
503e26f
Remove count from calendar
backspace Dec 24, 2017
b3985b0
Add person to commitment creation
backspace Dec 24, 2017
5e5829f
Add full slot detection/commitment-blocking
backspace Dec 25, 2017
6544700
Remove unused property
backspace Dec 25, 2017
b3a43ef
Add missing whitespace
backspace Dec 25, 2017
daaccf0
Change commitment-deletion to be properly scoped
backspace Dec 25, 2017
0ff8a40
Add assertion on calendar month
backspace Dec 29, 2017
0722ce5
Add month to calendar path
backspace Dec 29, 2017
5f4bd7b
Add checkbox for slot commitment indicator
backspace Dec 30, 2017
d671fb7
Add ember-cli-poll
backspace Jan 2, 2018
ffb3420
Merge branch 'primary' into slots
backspace Jan 2, 2018
3de52db
Add ESLint workaround
backspace Jan 2, 2018
e490b46
Merge branch 'primary' into slots
backspace Jan 2, 2018
6b7b990
Update dependencies
backspace Jan 2, 2018
b50a1f7
Update lockfile
backspace Jan 2, 2018
4921fed
Add simple polling for slots
backspace Jan 2, 2018
2a549ce
Add progress toward admin calendar
backspace Jan 3, 2018
06eb2ba
Add guard against polling in testing
backspace Jan 3, 2018
8905cb2
Correct admin calendar test
backspace Jan 3, 2018
f3293b9
Add admin ability to move between months
backspace Jan 3, 2018
91e06f2
Hide checkbox on admin calendar
backspace Jan 3, 2018
1bbe3cf
Update appearance of slot count
backspace Jan 3, 2018
29d4831
Add title for currently-viewed slot
backspace Jan 3, 2018
48f113a
Move viewed slot to second column
backspace Jan 3, 2018
b4c4891
Add link to admin calendar
backspace Jan 3, 2018
2b0e303
Remove unused method
backspace Jan 5, 2018
725d27b
Move viewing action into template
backspace Jan 5, 2018
48ebcfa
Remove fake slots
backspace Jan 5, 2018
70f066c
Update appearance of calendar session
backspace Jan 5, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions app/adapters/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,14 @@ export default DS.JSONAPIAdapter.extend(DataAdapterMixin, {
default:
return this._super(...arguments);
}
},

urlForQueryRecord(query) {
if (query.me) {
delete query.me;
return `${this._super(...arguments)}/me`;
}

return this._super(...arguments);
}
});
11 changes: 11 additions & 0 deletions app/adapters/commitment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import ApplicationAdapter from './application';
import { computed } from '@ember/object';

export default ApplicationAdapter.extend({
headers: computed(function() {
const personToken = localStorage.getItem('person-token');
return {
'Authorization': `Person Bearer ${personToken}`
};
}).volatile()
});
11 changes: 11 additions & 0 deletions app/components/calendar-day.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Component from '@ember/component';
import { computed } from '@ember/object';

export default Component.extend({
daySlots: computed('day.id', '[email protected]', function() {
const dayDateString = this.get('day.date').toDateString();
const slots = this.get('slots');

return slots.filter(slot => dayDateString === slot.get('start').toDateString()).sortBy('start');
})
});
3 changes: 3 additions & 0 deletions app/components/calendar-days.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Days from 'ember-power-calendar/components/power-calendar/days';

export default Days;
44 changes: 44 additions & 0 deletions app/components/calendar-slot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import { reads } from '@ember/object/computed';
import { inject as service } from '@ember/service';
import config from 'prison-rideshare-ui/config/environment';

export default Component.extend({
paperToaster: service(),
store: service(),

isCommittedTo: reads('commitment'),

commitment: computed('[email protected]', 'person', function() {
const personId = this.get('person.id');

return this.get('slot.commitments').find(slot => slot.belongsTo('person').id() == personId);
}),

actions: {
toggle() {
if (this.get('isCommittedTo')) {
this.get('commitment').destroyRecord().catch(() => {
this.get('paperToaster').show('Couldn’t save your change', {
duration: config.toastDuration,
position: 'top right'
});
});
} else if (this.get('slot.isNotFull')) {
const newRecord = this.get('store').createRecord('commitment', {
slot: this.get('slot'),
person: this.get('person')
});

newRecord.save().catch(() => {
this.get('paperToaster').show('Couldn’t save your change', {
duration: config.toastDuration,
position: 'top right'
});
newRecord.destroyRecord();
});
}
}
}
});
13 changes: 13 additions & 0 deletions app/components/person-badge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Component from '@ember/component';

export default Component.extend({
classNames: ['person-badge'],

showContact: false,

actions: {
toggleContact() {
this.toggleProperty('showContact');
}
}
});
4 changes: 0 additions & 4 deletions app/components/ride-person.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ export default Component.extend({
const ride = this.get('ride');
ride.set(this.get('property'), null);
return ride.save();
},

toggleContact() {
this.toggleProperty('showContact');
}
}
});
3 changes: 3 additions & 0 deletions app/controllers/admin-calendar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import CalendarController from './calendar';

export default CalendarController.extend();
9 changes: 9 additions & 0 deletions app/controllers/calendar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Controller from '@ember/controller';

import { alias } from '@ember/object/computed';

export default Controller.extend({
month: alias('model.month'),
slots: alias('model.slots'),
person: alias('model.person')
});
6 changes: 6 additions & 0 deletions app/models/commitment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import DS from 'ember-data';

export default DS.Model.extend({
slot: DS.belongsTo({ async: false }),
person: DS.belongsTo()
});
17 changes: 17 additions & 0 deletions app/models/slot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import DS from 'ember-data';
import { computed } from '@ember/object';

export default DS.Model.extend({
start: DS.attr('date'),
end: DS.attr('date'),
count: DS.attr('number'),

commitments: DS.hasMany({ async: false }),

isNotFull: computed('commitments.length', 'count', function() {
const count = this.get('count');
const commitmentCount = this.get('commitments.length');

return count === 0 || commitmentCount < count;
})
});
3 changes: 3 additions & 0 deletions app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ Router.map(function() {

this.route('login');
this.route('register');

this.route('admin-calendar', { path: '/admin-calendar/:month' });
this.route('calendar', { path: '/calendar/:month' });
});

export default Router;
11 changes: 11 additions & 0 deletions app/routes/admin-calendar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Route from '@ember/routing/route';
import RSVP from 'rsvp';

export default Route.extend({
model({ month }) {
return RSVP.hash({
slots: this.store.findAll('slot'),
month
});
}
});
12 changes: 12 additions & 0 deletions app/routes/application.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
import Ember from 'ember';

import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';

Expand All @@ -8,11 +9,22 @@ export default Route.extend(ApplicationRouteMixin, {
account: service(),
userSocket: service(),
flashMessages: service(),
poll: service(),

beforeModel() {
return this._loadCurrentUser();
},

afterModel() {
this._super(...arguments);
if (!Ember.testing) {
this.get('poll').start({
idle_timeout: 10000,
interval: 10000
});
}
},

title(tokens) {
return `${tokens.join(' · ')} · Prison Rideshare`;
},
Expand Down
65 changes: 65 additions & 0 deletions app/routes/calendar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import Route from '@ember/routing/route';
import RSVP from 'rsvp';
import { inject as service } from '@ember/service';
import { isEmpty } from '@ember/utils';
import Ember from 'ember';
import fetch from 'fetch';
import config from '../config/environment';

export default Route.extend({
poll: service(),

// FIXME is it possible to get the token from elsewhere than the transition object?
model({ month }, { queryParams }) {
const token = queryParams.token;
const personTokenEndpoint = `${(Ember.testing ? '' : config.DS.host)}/${config.DS.namespace}/people/token`;

if (isEmpty(token)) {
throw new Error('We were unable to log you in without a token.');
}

return fetch(personTokenEndpoint, {
method: 'POST',
body: `grant_type=magic&token=${encodeURIComponent(token)}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(response => {
if (response.ok) {
return response.json();
}

throw new Error('We were unable to log you in with that token.');
}).then(({ access_token }) => {
localStorage.setItem('person-token', access_token);
return this.store.queryRecord('person', { me: true, token: access_token })
}).catch(() => {
throw new Error('We were unable to log you in with that token.');
}).then(person => {
return RSVP.hash({
slots: this.store.findAll('slot'),
person,
month
});
});
},

afterModel() {
const url = this.store.adapterFor('application').buildURL('slot');

if (!Ember.testing) {
this.get('poll').setup({
name: 'slotsPoll',
resource_name: 'slots',
url
});
}
},

actions: {
willTransition(transition) {
this._super(transition);
this.get('poll').removePoll('slotsPoll');
}
}
});
2 changes: 1 addition & 1 deletion app/services/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default Service.extend({

if (!isEmpty(token)) {
fetch(`${(Ember.testing ? '' : config.DS.host)}/${config.DS.namespace.length > 0 ? `${config.DS.namespace}/` : ''}users/current`, {
type: 'GET',
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
Expand Down
5 changes: 4 additions & 1 deletion app/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ $primary: 'indigo';

@import 'ember-paper';
@import 'paper-data-table';
@import 'ember-power-calendar';

@import 'loading';

@import 'calendar';

body {
max-width: 100%;
max-height: 100%;
Expand Down Expand Up @@ -220,7 +223,7 @@ md-table-container.debts .person .name {
}
}

.ride-person {
.person-badge {
display: inline-block;
background-color: #e0e0e0;
color: #424242;
Expand Down
22 changes: 22 additions & 0 deletions app/styles/calendar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.ember-power-calendar {
@include ember-power-calendar(100px);

.count {
display: inline-block;
width: 1rem;
height: 1rem;

font-size: 75%;
text-align: center;

border-radius: 5rem;
background-color: $dark-contrast-color;
color: white;

cursor: pointer;
}
}

.admin-calendar {
display: flex;
}
24 changes: 24 additions & 0 deletions app/templates/admin-calendar.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<div class='admin-calendar'>
{{#power-calendar center=month daysComponent='calendar-days' onCenterChange=(action (mut month) value="date") as |calendar|}}
<nav class="ember-power-calendar-nav">
<button type="button" class="ember-power-calendar-nav-control previous-month" onclick={{action calendar.actions.moveCenter -1 'month'}}>‹</button>
<div class="ember-power-calendar-nav-title">
{{moment-format calendar.center 'MMMM YYYY'}}
</div>
<button class="ember-power-calendar-nav-control next-month" onclick={{action calendar.actions.moveCenter 1 'month'}}>›</button>
</nav>

{{#calendar.days showDaysAround=false as |day|}}
{{calendar-day day=day slots=slots count=true setViewingSlot=(action (mut viewingSlot))}}
{{/calendar.days}}
{{/power-calendar}}

{{#if viewingSlot.commitments}}
<div class='viewing-slot'>
<h3 class='hours'>{{moment-format viewingSlot.start 'dddd, MMMM D, hA'}}–{{moment-format viewingSlot.end 'hA'}}</h3>
{{#each viewingSlot.commitments as |commitment|}}
{{person-badge person=commitment.person}}
{{/each}}
</div>
{{/if}}
</div>
3 changes: 3 additions & 0 deletions app/templates/application.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
{{#paper-item}}
{{#link-to 'institutions'}}<span>Institutions</span>{{/link-to}}
{{/paper-item}}
{{#paper-item}}
{{#link-to 'admin-calendar' (moment-format (now) 'YYYY-MM')}}<span>Calendar</span>{{/link-to}}
{{/paper-item}}
{{/if}}
{{#paper-item}}
{{#link-to 'reports.new'}}<span>Report</span>{{/link-to}}
Expand Down
1 change: 1 addition & 0 deletions app/templates/calendar-error.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div class='error'>{{model.message}}</div>
13 changes: 13 additions & 0 deletions app/templates/calendar.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{{#power-calendar center=month daysComponent='calendar-days' as |calendar|}}
{{#paper-card as |card|}}
{{#card.content}}
<div class='person-session'>You are logged in as {{person.email}}</div>
{{/card.content}}
{{/paper-card}}

{{calendar.nav}}

{{#calendar.days showDaysAround=false as |day|}}
{{calendar-day day=day slots=slots person=person}}
{{/calendar.days}}
{{/power-calendar}}
5 changes: 5 additions & 0 deletions app/templates/components/calendar-day.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{{day.number}}

{{#each daySlots as |slot|}}
{{calendar-slot slot=slot person=person count=count setViewingSlot=setViewingSlot}}
{{/each}}
Loading