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

Implementing a button for Presence in the 2de kamer #891

Open
wants to merge 5 commits into
base: staging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 15 additions & 0 deletions app/abilities/study-room-presence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Ability } from 'ember-can';

export default class StudyRoomPresence extends Ability {
get canShow() {
return this.session.hasPermission('study-room-presence.read');

Check warning on line 5 in app/abilities/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/abilities/study-room-presence.js#L5

Added line #L5 was not covered by tests
}

get canCreate() {
return this.session.hasPermission('study-room-presence.create');

Check warning on line 9 in app/abilities/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/abilities/study-room-presence.js#L9

Added line #L9 was not covered by tests
}

get canDestroy() {
return this.session.hasPermission('study-room-presence.destroy');

Check warning on line 13 in app/abilities/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/abilities/study-room-presence.js#L13

Added line #L13 was not covered by tests
}
}
1 change: 1 addition & 0 deletions app/components/index/authenticated.hbs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<EmberWormhole @to='navbar-wormhole'>
<PageActionsButtons @pageActions={{pageActions}}>
<Tools::StudyRoomPresence />
<Tools::BoardRoomPresence />
</PageActionsButtons>
</EmberWormhole>
Expand Down
2 changes: 1 addition & 1 deletion app/components/tools/board-room-presence.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class='board-room-presence-dropdown page-action'>
<div class='room-presence-dropdown page-action'>
<BsButton @type='primary'>
<FaIcon @icon='mug-saucer' />
<span class='d-none d-md-inline'>Bestuurskamer</span>
Expand Down
135 changes: 135 additions & 0 deletions app/components/tools/study-room-presence.hbs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please also write this template in octane style. Some quick rules (without regard for whether you followed these or not):

  • use angle bracket syntax for inserting components
  • refer to controller properties/functions with this. i.e. this.property or this.someFunction
  • refer to arguments passed to this component using @. So, if the parent component has passed an argument called someArgument, then we can refer to it in this template with @someArgument.
  • do not use the action helper anymore. see Refactor: {{action}} helper usage #635 and Refactor: {{action}} helper usage, the sequel #896 for examples of what to write instead.

please thoroughly familiarize yourself with #429 and the tutorials/guides/resources mentioned there.

Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<div class='room-presence-dropdown page-action'>
<BsButton @type='primary'>
<FaIcon @icon='book' />
<span class='d-none d-md-inline'>2de kamer</span>
<span class='status-dot label-{{overallStatus}}'></span>

<BsPopover
{{!-- @triggerEvents='focus' --}}
@placement='bottom'
@title='Aanwezig in de 2de Kamer'
@renderInPlace="{{true}}"
>
{{#each sortedPresences as |presence|}}
<div class='py-1'>
<div class='d-block'>
<LinkTo @route='users.user' @model={{presence.user.id}}>
<small><b>{{presence.user.fullNameWithNickname}}</b></small>
</LinkTo>
</div>
<span class='presence-label label-{{presence.status}}'>
{{t (concat 'component.tools.studyRoomPresence.' presence.status)}}
van
{{moment-format presence.startTime 'HH:mm'}}
tot
{{moment-format presence.endTime 'HH:mm'}}
</span>
</div>
{{else}}
<div>Er is niemand aanwezig</div>
{{/each}}

{{#if (can 'create study-room-presences')}}
<span class='d-flex'>
<button
class='btn btn-secondary mb-2 mt-3 update-presence-button'
{{action 'setPresenceModalState' 'open'}}
type='button'
>
Aanwezigheid updaten
</button>
</span>
{{/if}}
</BsPopover>
</BsButton>
</div>

{{#if presenceModalIsOpen}}
<EmberWormhole @to='ember-wormhole-destination'>
<BasicModal
@title='2de kamer beschikbaarheid opgeven'
@closeModal={{action 'setPresenceModalState' 'closed'}}
@onSubmit={{action 'save'}}
@submitText='Beschikbaarheid opslaan'
@submitDisabled={{saveButtonDisabled}}
>
{{#if sortedPresences}}
<table class='table edit-presence'>
<thead>
<tr>
<th>Persoon</th>
<th>Status</th>
<th>Tot</th>
<th></th>
</tr>
</thead>
<tbody>
{{#each sortedPresences as |presence|}}
<tr class="edit-presence-row">
<td>{{presence.user.fullNameWithNickname}}</td>
<td>
{{t
(concat 'component.tools.studyRoomPresence.' presence.status)
}}
</td>
<td> {{moment-format presence.endTime 'HH:mm'}} </td>
<td>
{{#if (can 'destroy study-room-presences')}}
<button
class='btn btn-danger delete-presence-button float-end'
aria-hidden='true'
{{action 'deletePresence'}}
type='button'
>
<FaIcon @icon='trash' @size="xs" />
</button>
{{/if}}
</td>
</tr>
{{/each}}
</tbody>
</table>
{{else}}
<div class='alert alert-info'>Er zijn geen alphanen aanwezig</div>
{{/if}}

{{#if currentUserPresence}}
<label for="new-user-presence-status">Status</label>
<Input::SelectInput
@class='form-control col-xs-12 presence-select'
@required={{true}}
@options={{statusOptions}}
@placeholder={{Status}}
@value={{currentUserPresence.status}}
@id="new-user-presence-status"
/>
<label for="new-user-presence-starttime" class="mt-2">Van</label>
<Input::TimeInput
@dateValue={{currentUserPresence.startTime}}
@class='col-xs-12 presence-time-input'
@inputClass='form-control'
@placeholder={{currentUserPresence.startTime}}
@required={{true}}
@id="new-user-presence-starttime"
/>
<label for="new-user-presence-endtime" class="mt-2">Tot</label>
<Input::TimeInput
@dateValue={{currentUserPresence.endTime}}
@class='col-xs-12 presence-time-input'
@inputClass='form-control'
@placeholder={{currentUserPresence.endTime}}
@required={{true}}
@id="new-user-presence-endtime"
/>
{{else}}
<button
class='btn btn-secondary'
{{action 'newPresence'}}
type='button'
>
Nieuw
</button>
{{/if}}
</BasicModal>
</EmberWormhole>
{{/if}}
122 changes: 122 additions & 0 deletions app/components/tools/study-room-presence.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this component is written in the old style, please follow the new octane component style. There are a lot of examples that use glimmer components already

specifically, you can take example from https://github.com/csvalpha/amber-ui/pull/635/files#diff-b264f9e9a3db1a61c4d3c4c38a3c454a93a33286c5d2b1e820513bc9d4986084 where I've rewritten the board-room-presence component

Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { task, timeout } from 'ember-concurrency';
import Component from '@ember/component';
import Ember from 'ember';
import { computed } from '@ember/object';
import { equal } from '@ember/object/computed';
import moment from 'moment';
import { inject as service } from '@ember/service';

const StudyRoomPresence = Component.extend({
session: service(),
store: service(),
abilities: service(),
presenceModalIsOpen: false,
model: [],

statusOptions: [
{
value: 'chilling',
label: 'Chillen',
},
{
value: 'studying',
label: 'Studeren',
},
{
value: 'banaan',
label: 'Banaan',
},
],

// Periodically poll for new studyroom data
poll: task(function* () {
while (!Ember.testing) {
this.fetchData.perform();
yield timeout(1000 * 30); // Wait 30 seconds
}
})

Check warning on line 37 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L35-L37

Added lines #L35 - L37 were not covered by tests
.drop()
.on('didInsertElement'),

// Fetch task is separate from polling task, so we can call it individually.
fetchData: task(function* () {
/* eslint-disable camelcase */
const model = yield this.store.query('study-room-presence', {
filter: { current_and_future: true },
});

Check warning on line 46 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L46

Added line #L46 was not covered by tests
/* eslint-enable camelcase */

this.set('model', model);
}).restartable(),

Check warning on line 51 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L51

Added line #L51 was not covered by tests
currentUserPresence: computed('model.[]', function () {
return (
this.model.filter((presence) => presence.get('user.isCurrentUser'))[0] ||
null
);

Check warning on line 56 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L55-L56

Added lines #L55 - L56 were not covered by tests
}),

sortedPresences: computed('model.[]', function () {
return this.model.sortBy('endTime');
}),

Check warning on line 62 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L62

Added line #L62 was not covered by tests
overallStatus: computed('model.[]', function () {
const currentStatusses = this.model
.filter((presence) => {
return moment().isBetween(

Check warning on line 66 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L66

Added line #L66 was not covered by tests
moment(presence.get('startTime')),
moment(presence.get('endTime')),

Check warning on line 68 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L68

Added line #L68 was not covered by tests
'minute',
'[)'
);
})
.mapBy('status');

if (currentStatusses.includes('chilling')) {
return 'Chillen';
} else if (currentStatusses.includes('studeren')) {
return 'Studying';
}

Check warning on line 80 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L77-L80

Added lines #L77 - L80 were not covered by tests
return 'banaan';
}),

Check warning on line 83 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L83

Added line #L83 was not covered by tests
saveButtonDisabled: equal('currentUserPresence', null),

actions: {
setPresenceModalState(state) {
this.set('presenceModalIsOpen', state === 'open');
},

Check warning on line 90 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L90

Added line #L90 was not covered by tests
deletePresence() {
this.currentUserPresence.destroyRecord().then(() => {
this.set('currentUserPresence', null);
});
},

Check warning on line 95 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L94-L95

Added lines #L94 - L95 were not covered by tests

newPresence() {
if (this.abilities.can('create study-room-presences')) {
const newPresenceObject = this.store.createRecord(
'study-room-presence',
{

Check warning on line 101 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L100-L101

Added lines #L100 - L101 were not covered by tests
startTime: moment().startOf('minute').toDate(),
endTime: moment().startOf('minute').add(1, 'hours').toDate(),
status: 'Studying',
user: this.session.currentUser,
}
);
this.set('currentUserPresence', newPresenceObject);
}
},

Check warning on line 110 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L110

Added line #L110 was not covered by tests

save() {
const presence = this.currentUserPresence;
const fetch = this.fetchData;

presence.save().then(() => fetch.perform());

Check warning on line 116 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L115-L116

Added lines #L115 - L116 were not covered by tests
this.set('presenceModalIsOpen', false);
},
},

Check warning on line 119 in app/components/tools/study-room-presence.js

View check run for this annotation

Codecov / codecov/patch

app/components/tools/study-room-presence.js#L118-L119

Added lines #L118 - L119 were not covered by tests
});

export default StudyRoomPresence;
11 changes: 11 additions & 0 deletions app/models/study-room-presence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Model, { belongsTo, attr } from '@ember-data/model';

export default class StudyRoomPresence extends Model {
// Properties
@attr startTime;
@attr endTime;
@attr status;

// Relations
@belongsTo user;
}
2 changes: 1 addition & 1 deletion app/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
@import 'components/quickpost';
@import 'components/sidebar';
@import 'components/social-media-buttons';
@import 'components/tools/board-room-presence';
@import 'components/tools/room-presence';
@import 'components/tools/upcoming-birthdays';
@import 'components/tools/upcoming-activities';
@import 'components/tools/forum-tool';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
font-weight: bold;
}

.board-room-presence-dropdown {
.room-presence-dropdown {
color: $white;
}

Expand All @@ -26,6 +26,18 @@
background-color: $brand-danger;
}

.label-chilling {
background-color: $brand-success;
}

.label-studying {
background-color: $brand-warning;
}

.label-banaan {
background-color: $brand-success;
}

.edit-presence {
.edit-presence-row {
margin: 5px;
Expand Down
1 change: 1 addition & 0 deletions mirage/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default function () {
this.resource('groups');
this.resource('quickpost_messages');
this.resource('board_room_presences');
this.resource('study_room_presences');
this.resource('photo_albums');
this.resource('photo_comments');
this.resource('photo_tags');
Expand Down
1 change: 1 addition & 0 deletions mirage/scenarios/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default function (server) {
'article',
'article_comment',
'board_room_presence',
'study_room_presence',
'group',
'membership',
'photo_album',
Expand Down
4 changes: 4 additions & 0 deletions translations/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,10 @@ component:
present: Present
busy: Busy
absent: Absent
studyRoomPresence:
chilling: Chilling
studying: Studying
banaan: Banaan
userComment:
anonymous: Anonymous user
mixin:
Expand Down
4 changes: 4 additions & 0 deletions translations/nl.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ component:
present: Aanwezig
busy: Bezig
absent: Afwezig
studyRoomPresence:
chilling: Chillen
studying: Studeren
banaan: Banaan
userComment:
anonymous: Anonieme gebruiker
mixin:
Expand Down
Loading