Skip to content

Commit

Permalink
Merge pull request #7608 from stopfstedt/schooladmin_emails
Browse files Browse the repository at this point in the history
adds UI for managing emails in the school configuration screen.
  • Loading branch information
dartajax authored Feb 8, 2024
2 parents 51cd8eb + d074f1c commit 87c4563
Show file tree
Hide file tree
Showing 19 changed files with 556 additions and 0 deletions.
13 changes: 13 additions & 0 deletions packages/frontend/app/components/school-manager.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@
@isManaging={{@schoolManageSessionAttributes}}
@manage={{@setSchoolManageSessionAttributes}}
/>
{{#if @schoolManageEmails}}
<School::EmailsEditor
@school={{@school}}
@cancel={{fn @setSchoolManageEmails false}}
@save={{this.saveEmails}}
/>
{{else}}
<School::Emails
@canUpdate={{@canUpdateSchool}}
@manage={{@setSchoolManageEmails}}
@school={{@school}}
/>
{{/if}}
{{#if @schoolManageInstitution}}
{{#if this.institutionLoaded}}
<SchoolCurriculumInventoryInstitutionManager
Expand Down
7 changes: 7 additions & 0 deletions packages/frontend/app/components/school-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,11 @@ export default class SchoolManagerComponent extends Component {
}
await institution.save();
}

@action
async saveEmails(administratorEmail, changeAlertRecipients) {
this.args.school.changeAlertRecipients = changeAlertRecipients;
this.args.school.iliosAdministratorEmail = administratorEmail;
await this.args.school.save();
}
}
66 changes: 66 additions & 0 deletions packages/frontend/app/components/school/emails-editor.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{{#let (unique-id) as |templateId|}}
<section
class="school-emails-editor"
data-test-school-emails-editor
...attributes
{{did-insert this.load}}
{{did-update this.load}}
>
<div class="header">
<div class="title">{{t "general.emails"}}</div>
<div class="actions">
<button type="button" class="bigadd" {{on "click" (perform this.save)}} data-test-save>
<FaIcon
@icon={{if this.save.isRunning "spinner" "check"}}
@spin={{this.save.isRunning}}
/>
</button>
<button type="button" class="bigcancel" {{on "click" @cancel}} data-test-cancel>
<FaIcon @icon="arrow-rotate-left" />
</button>
</div>
</div>
<div class="content">
<div class="form">
<div class="item" data-test-administrator-email>
<label for="administrator-email-{{templateId}}">
{{t "general.administratorEmail"}}
</label>
<input
id="administrator-email-{{templateId}}"
type="text"
value={{this.administratorEmail}}
placeholder={{this.administratorEmailPlaceholder}}
{{on "input" (pick "target.value" (set this.administratorEmail))}}
{{on "keyup"
(queue
(fn this.addErrorDisplayFor "administratorEmail")
(perform this.saveOrCancel)
)
}}
>
<ValidationError @errors={{get-errors-for this.administratorEmail}} />
</div>
<div class="item" data-test-change-alert-recipients>
<label for="change-alert-recipients-{{templateId}}">
{{t "general.changeAlertRecipients"}}
</label>
<input
id="change-alert-recipients-{{templateId}}"
type="text"
value={{this.changeAlertRecipients}}
placeholder={{this.changeAlertRecipientsPlaceholder}}
{{on "input" (pick "target.value" (set this.changeAlertRecipients))}}
{{on "keyup"
(queue
(fn this.addErrorDisplayFor "changeAlertRecipients")
(perform this.saveOrCancel)
)
}}
>
<ValidationError @errors={{get-errors-for this.changeAlertRecipients}} />
</div>
</div>
</div>
</section>
{{/let}}
75 changes: 75 additions & 0 deletions packages/frontend/app/components/school/emails-editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { dropTask } from 'ember-concurrency';
import { validatable, Custom, IsEmail, Length } from 'ilios-common/decorators/validation';
import { action } from '@ember/object';
import { service } from '@ember/service';
import { isBlank, typeOf } from '@ember/utils';
import EmailValidator from 'validator/es/lib/isEmail';

@validatable
export default class SchoolEmailsEditorComponent extends Component {
@service intl;

@tracked @Length(0, 100) @IsEmail() administratorEmail;
@tracked
@Length(0, 300)
@Custom('validateChangeAlertRecipientsCallBack', 'validateChangeAlertRecipientsMessageCallBack')
changeAlertRecipients;

get changeAlertRecipientsFormatted() {
return this.changeAlertRecipients
.trim()
.split(',')
.map((email) => email.trim())
.filter((email) => !isBlank(email))
.join(', ');
}

@action
load() {
this.administratorEmail = this.args.school.iliosAdministratorEmail;
this.changeAlertRecipients = this.args.school.changeAlertRecipients;
}

@action
validateChangeAlertRecipientsCallBack() {
if ('string' !== typeOf(this.changeAlertRecipients)) {
return true;
}
const emails = this.changeAlertRecipients
.trim()
.split(',')
.map((email) => email.trim())
.filter((email) => !isBlank(email));
return emails.reduce((valid, email) => EmailValidator(email) && valid, true);
}

@action
validateChangeAlertRecipientsMessageCallBack() {
return this.intl.t('errors.invalidChangeAlertRecipients');
}

@dropTask
*save() {
this.addErrorDisplaysFor(['administratorEmail', 'changeAlertRecipients']);
const isValid = yield this.isValid();
if (!isValid) {
return false;
}

yield this.args.save(this.administratorEmail, this.changeAlertRecipientsFormatted);
this.clearErrorDisplay();
this.args.cancel();
}

@dropTask
*saveOrCancel(event) {
const keyCode = event.keyCode;
if (13 === keyCode) {
yield this.save.perform();
} else if (27 === keyCode) {
this.args.cancel();
}
}
}
30 changes: 30 additions & 0 deletions packages/frontend/app/components/school/emails.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<section
class="school-emails"
data-test-school-emails
...attributes
>
<div class="header">
<div class="title" data-test-title>{{t "general.emails"}}</div>
<div class="actions">
{{#if @canUpdate}}
<button
type="button"
{{on "click" (fn @manage true)}}
data-test-manage
>
{{t "general.manageEmails"}}
</button>
{{/if}}
</div>
</div>
<div class="content">
<div data-test-administrator-email>
<strong>{{t "general.administratorEmail"}}:</strong>
<span>{{@school.iliosAdministratorEmail}}</span>
</div>
<div data-test-change-alert-recipients>
<strong>{{t "general.changeAlertRecipients"}}:</strong>
<span>{{@school.changeAlertRecipients}}</span>
</div>
</div>
</section>
2 changes: 2 additions & 0 deletions packages/frontend/app/controllers/school.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export default class SchoolController extends Controller {
'schoolNewSessionType',
'schoolManageInstitution',
'schoolNewVocabulary',
'schoolManageEmails',
];

@tracked schoolCompetencyDetails = false;
Expand All @@ -33,4 +34,5 @@ export default class SchoolController extends Controller {
@tracked schoolManagedSessionType = null;
@tracked schoolManageInstitution = false;
@tracked schoolNewVocabulary = false;
@tracked schoolManageEmails = false;
}
2 changes: 2 additions & 0 deletions packages/frontend/app/styles/components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@
@import "components/school/session-type-visualize-vocabulary";
@import "components/school/visualizer-session-type-vocabularies";
@import "components/school/visualizer-session-type-vocabulary";
@import "components/school/emails";
@import "components/school/emails-editor";

@import "components/courses/root";
@import "components/courses/list";
Expand Down
40 changes: 40 additions & 0 deletions packages/frontend/app/styles/components/school/emails-editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
@use "../../ilios-common/colors" as c;
@use "../../ilios-common/mixins" as m;

.school-emails-editor {
@include m.detail-container(c.$orange);

.header {
@include m.detail-container-header;

.title {
@include m.detail-container-title;
}

.actions {
@include m.detail-container-actions;
}
}

.content {
@include m.detail-container-content;

.form {
@include m.ilios-form;
grid-template-columns: 1fr;
margin-top: 1em;

@include m.for-laptop-and-up {
grid-template-columns: 1fr 1fr;
}
}

.validation-error-message {
color: c.$crimson;
display: block;
@include m.font-size("small");
font-style: italic;
margin-top: 0.25rem;
}
}
}
22 changes: 22 additions & 0 deletions packages/frontend/app/styles/components/school/emails.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@use "../../ilios-common/colors" as c;
@use "../../ilios-common/mixins" as m;

.school-emails {
@include m.detail-container(c.$orange);

.header {
@include m.detail-container-header;

.title {
@include m.detail-container-title;
}

.actions {
@include m.detail-container-actions;
}
}

.content {
@include m.collapsed-container-content;
}
}
2 changes: 2 additions & 0 deletions packages/frontend/app/templates/school.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@
@setSchoolManageInstitution={{set this.schoolManageInstitution}}
@schoolNewVocabulary={{this.schoolNewVocabulary}}
@setSchoolNewVocabulary={{set this.schoolNewVocabulary}}
@schoolManageEmails={{this.schoolManageEmails}}
@setSchoolManageEmails={{set this.schoolManageEmails}}
/>
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ module('Integration | Component | school manager', function (hooks) {
@setSchoolManageInstitution={{(noop)}}
@schoolNewVocabulary={{true}}
@setSchoolNewVocabulary={{(noop)}}
@schoolManageEmails={{true}}
@setSchoolManageEmails={{(noop)}}
/>`);

assert.ok(component.schoolLeadershipExpanded.isVisible);
Expand All @@ -82,6 +84,8 @@ module('Integration | Component | school manager', function (hooks) {
assert.notOk(component.schoolSessionAttributes.collapsed.isVisible);
assert.ok(component.schoolCurriculumInventoryInstitutionManager.isVisible);
assert.notOk(component.schoolCurriculumInventoryInstitutionDetails.isVisible);
assert.ok(component.emailsEditor.isVisible);
assert.notOk(component.emails.isVisible);
});

test('it renders collapsed', async function (assert) {
Expand Down Expand Up @@ -130,6 +134,8 @@ module('Integration | Component | school manager', function (hooks) {
@setSchoolManageInstitution={{(noop)}}
@schoolNewVocabulary={{false}}
@setSchoolNewVocabulary={{(noop)}}
@schoolManageEmails={{false}}
@setSchoolManageEmails={{(noop)}}
/>`);

assert.notOk(component.schoolLeadershipExpanded.isVisible);
Expand All @@ -144,6 +150,8 @@ module('Integration | Component | school manager', function (hooks) {
assert.ok(component.schoolSessionAttributes.collapsed.isVisible);
assert.notOk(component.schoolCurriculumInventoryInstitutionManager.isVisible);
assert.ok(component.schoolCurriculumInventoryInstitutionDetails.isVisible);
assert.notOk(component.emailsEditor.isVisible);
assert.ok(component.emails.isVisible);
});

test('change title', async function (assert) {
Expand Down Expand Up @@ -195,6 +203,8 @@ module('Integration | Component | school manager', function (hooks) {
@setSchoolManageInstitution={{(noop)}}
@schoolNewVocabulary={{false}}
@setSchoolNewVocabulary={{(noop)}}
@schoolManageEmails={{false}}
@setSchoolManageEmails={{(noop)}}
/>`);

assert.strictEqual(component.title.text, 'school 0');
Expand Down Expand Up @@ -256,6 +266,8 @@ module('Integration | Component | school manager', function (hooks) {
@setSchoolManageInstitution={{(noop)}}
@schoolNewVocabulary={{false}}
@setSchoolNewVocabulary={{(noop)}}
@schoolManageEmails={{false}}
@setSchoolManageEmails={{(noop)}}
/>`);

assert.strictEqual(component.title.text, 'school 0');
Expand Down Expand Up @@ -314,6 +326,8 @@ module('Integration | Component | school manager', function (hooks) {
@setSchoolManageInstitution={{(noop)}}
@schoolNewVocabulary={{false}}
@setSchoolNewVocabulary={{(noop)}}
@schoolManageEmails={{false}}
@setSchoolManageEmails={{(noop)}}
/>`);

assert.strictEqual(component.title.text, 'school 0');
Expand Down Expand Up @@ -372,6 +386,8 @@ module('Integration | Component | school manager', function (hooks) {
@setSchoolManageInstitution={{(noop)}}
@schoolNewVocabulary={{false}}
@setSchoolNewVocabulary={{(noop)}}
@schoolManageEmails={{false}}
@setSchoolManageEmails={{(noop)}}
/>`);

assert.strictEqual(component.title.text, 'school 0');
Expand Down
Loading

0 comments on commit 87c4563

Please sign in to comment.