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

feat(meeting-creation): only allow bestuursorganen active at planned start date #765

Merged
Merged
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
8 changes: 8 additions & 0 deletions .changeset/chatty-lemons-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'frontend-gelinkt-notuleren': minor
---

- Adjust logic of meeting creation modal:
* Only allow the selection of 'bestuursorganen' which are active on the selected 'planned start' date
* When modifying the 'planned start' date, clear the 'bestuursorgaan' if necessary.
- Modernize `administrative-body-select` component
2 changes: 1 addition & 1 deletion app/components/administrative-body-select.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PowerSelect
@placeholder={{t 'manage-zittings-data.select-placeholder'}}
@selected={{@selected}}
@options={{this.administrativeBodyOptions}}
@options={{this.administrativeBodyOptions.value}}
@onChange={{@onChange}}
@triggerId={{@id}}
as |administrativeBody|
Expand Down
72 changes: 29 additions & 43 deletions app/components/administrative-body-select.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { service } from '@ember/service';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { task } from 'ember-concurrency';
import sub from 'date-fns/sub';
import isAfter from 'date-fns/isAfter';
import { trackedFunction } from 'reactiveweb/function';

const VALID_ADMINISTRATIVE_BODY_CLASSIFICATIONS = [
'http://data.vlaanderen.be/id/concept/BestuursorgaanClassificatieCode/5ab0e9b8a3b2ca7c5e000005', // "Gemeenteraad"
Expand All @@ -30,56 +27,45 @@ const VALID_ADMINISTRATIVE_BODY_CLASSIFICATIONS = [
* @property {BestuursOrgaan} selected which governing body is currently selected
* @property {(administrativeBody: BestuursOrgaan) => void} onChange change handler called when a body is selected
* @property {boolean} error whether there is a form value error and we should render as such
* @property {Date|undefined} referenceDate the reference date to use when determining the currently active bodies
*/

/** @extends {Component<Args>} */
export default class AdministrativeBodySelectComponent extends Component {
@service currentSession;
@service store;
@tracked administrativeBodyOptions = [];

constructor() {
super(...arguments);

this.fetchAdministrativeBodies.perform();
get referenceDate() {
return this.args.referenceDate || new Date();
}

/**
* Fetch bodies which are of the right classification, and whose
* end date is not older than 2 months before the current date
*/
fetchAdministrativeBodies = task(async () => {
administrativeBodyOptions = trackedFunction(this, async () => {
let currentAdministrativeUnitId = this.currentSession.group.id;

let administrativeBodiesInTime = await this.store.query('bestuursorgaan', {
'filter[is-tijdsspecialisatie-van][bestuurseenheid][id]':
currentAdministrativeUnitId,
include: [
'is-tijdsspecialisatie-van.bestuurseenheid',
'is-tijdsspecialisatie-van.classificatie',
].join(),
sort: '-binding-start',
});

this.administrativeBodyOptions = administrativeBodiesInTime.filter(
(administrativeBodyInTime) => {
const classificationUrl = administrativeBodyInTime.get(
'isTijdsspecialisatieVan.classificatie.uri',
);
const bodyIsValid =
VALID_ADMINISTRATIVE_BODY_CLASSIFICATIONS.includes(classificationUrl);
// shortcutting to avoid work
if (!bodyIsValid) {
return false;
}

const endDate = administrativeBodyInTime.bindingEinde;
if (!endDate) {
return true;
}
const twoMonthsAgo = sub(new Date(), { months: 2 });
return isAfter(endDate, twoMonthsAgo);
const referenceDate = this.referenceDate;
let administrativeBodiesInTime = await this.store.countAndFetchAll(
'bestuursorgaan',
{
'filter[is-tijdsspecialisatie-van][bestuurseenheid][id]':
currentAdministrativeUnitId,
include: [
'is-tijdsspecialisatie-van.bestuurseenheid',
'is-tijdsspecialisatie-van.classificatie',
].join(),
sort: '-binding-start',
},
);

return administrativeBodiesInTime.filter((administrativeBodyInTime) => {
const classificationUrl = administrativeBodyInTime.get(
'isTijdsspecialisatieVan.classificatie.uri',
);
const bodyIsValid =
VALID_ADMINISTRATIVE_BODY_CLASSIFICATIONS.includes(classificationUrl);
// shortcutting to avoid work
if (!bodyIsValid) {
return false;
}
return administrativeBodyInTime.isActive(referenceDate);
});
});
}
9 changes: 9 additions & 0 deletions app/controllers/inbox/meetings/new.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ export default class InboxMeetingsNewController extends Controller {
this.meeting.opLocatie = event.target.value;
}

@action
async updatePlannedStart(date) {
this.meeting.geplandeStart = new Date(date.getTime());
const bestuursorgaan = await this.meeting.bestuursorgaan;
if (!bestuursorgaan?.isActive(date)) {
this.meeting.bestuursorgaan = null;
}
}

get title() {
return this.intl.t('inbox.meetings.new.common-meeting.title');
}
Expand Down
13 changes: 13 additions & 0 deletions app/models/bestuursorgaan.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import Model, { attr, belongsTo, hasMany } from '@ember-data/model';
import isAfter from 'date-fns/isAfter';
import isBefore from 'date-fns/isBefore';

export default class BestuursorgaanModel extends Model {
@attr uri;
Expand Down Expand Up @@ -47,4 +49,15 @@ export default class BestuursorgaanModel extends Model {
'http://data.vlaanderen.be/ns/mandaat#isTijdspecialisatieVan',
bevat: 'http://www.w3.org/ns/org#hasPost',
};

/**
* @param {Date} referenceDate
*/
isActive(referenceDate) {
const startDateIsValid =
!this.bindingStart || isBefore(this.bindingStart, referenceDate);
const endDateIsValid =
!this.bindingEinde || isAfter(this.bindingEinde, referenceDate);
return startDateIsValid && endDateIsValid;
}
}
3 changes: 2 additions & 1 deletion app/templates/inbox/meetings/new.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
@id={{id}}
@selected={{this.meeting.bestuursorgaan}}
@onChange={{this.updateAdministrativeBody}}
@referenceDate={{this.meeting.geplandeStart}}
@error={{if errors true false}}
/>
{{#each errors as |error|}}
Expand Down Expand Up @@ -52,7 +53,7 @@
}}</AuLabel>
<DateTimePicker
@alignment='top'
@onChange={{fn (mut this.meeting.geplandeStart)}}
@onChange={{this.updatePlannedStart}}
@value={{this.meeting.geplandeStart}}
/>
</div>
Expand Down