diff --git a/packages/frontend/.lint-todo b/packages/frontend/.lint-todo index d72ccbd208..e589a5fbd0 100644 --- a/packages/frontend/.lint-todo +++ b/packages/frontend/.lint-todo @@ -1,8 +1,4 @@ add|ember-template-lint|no-at-ember-render-modifiers|2|61|2|61|23cd787c79c34a628dadb6e96dd4004d42eebb79|1731542400000|1762646400000|1793750400000|app/components/new-directory-user.hbs -add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1731542400000|1762646400000|1793750400000|app/components/user-profile-bio.hbs -add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|f53982efe02d2bef9e7f12b5b862288c594579c2|1731542400000|1762646400000|1793750400000|app/components/user-profile-bio.hbs -add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1731542400000|1762646400000|1793750400000|app/components/user-profile-roles.hbs -add|ember-template-lint|no-at-ember-render-modifiers|6|2|6|2|e5120f87b74c5ae8e4c76b9089e0b4a4504c6e3c|1731542400000|1762646400000|1793750400000|app/components/user-profile-roles.hbs add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|1fb0566922ce4f066916e5e2931f650f69d7cfba|1731542400000|1762646400000|1793750400000|app/components/visualizer-program-year-objectives.hbs add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|38e65b45b56fdfd4160d3b0884114b6643e3a036|1731542400000|1762646400000|1793750400000|app/components/visualizer-program-year-objectives.hbs add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|cb6d7acb9879902b89ad1575846d290a564ffbae|1731542400000|1762646400000|1793750400000|app/components/learner-group/instructor-manager.hbs diff --git a/packages/frontend/app/components/user-profile-bio-details.hbs b/packages/frontend/app/components/user-profile-bio-details.hbs new file mode 100644 index 0000000000..5ba2fcea34 --- /dev/null +++ b/packages/frontend/app/components/user-profile-bio-details.hbs @@ -0,0 +1,135 @@ +{{#let (unique-id) as |templateId|}} +
+
+ + + {{@user.firstName}} + +
+
+ + + {{@user.middleName}} + +
+
+ + + {{@user.lastName}} + +
+
+ + + {{@user.campusId}} + +
+
+ + + {{@user.otherId}} + +
+
+ + + {{@user.email}} + +
+
+ + + {{@user.displayName}} + +
+
+ + + {{@user.pronouns}} + +
+
+ + + {{@user.preferredEmail}} + +
+
+ + + {{@user.phone}} + +
+
+ + + {{this.userAuthentication.username}} + +
+ {{#if this.canEditUsernameAndPassword}} +
+ + + {{#if this.userAuthentication.username}} + ********* + {{/if}} + +
+ {{/if}} +
+{{/let}} \ No newline at end of file diff --git a/packages/frontend/app/components/user-profile-bio-details.js b/packages/frontend/app/components/user-profile-bio-details.js new file mode 100644 index 0000000000..6590ef33df --- /dev/null +++ b/packages/frontend/app/components/user-profile-bio-details.js @@ -0,0 +1,35 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +// import { action } from '@ember/object'; +// import { service } from '@ember/service'; +// import { TrackedAsyncData } from 'ember-async-data'; + +export default class UserProfileBioDetailsComponent extends Component { + @tracked firstName; + @tracked middleName; + @tracked lastName; + @tracked campusId; + @tracked otherId; + @tracked email; + @tracked displayName; + @tracked pronouns; + @tracked preferredEmail; + @tracked phone; + @tracked username; + @tracked password; + + constructor() { + super(...arguments); + + this.firstName = this.args.user.firstName; + this.middleName = this.args.user.middleName; + this.lastName = this.args.user.lastName; + this.campusId = this.args.user.campusId; + this.otherId = this.args.user.otherId; + this.email = this.args.user.email; + this.displayName = this.args.user.displayName; + this.pronouns = this.args.user.pronouns; + this.preferredEmail = this.args.user.preferredEmail; + this.phone = this.args.user.phone; + } +} diff --git a/packages/frontend/app/components/user-profile-bio-manager.hbs b/packages/frontend/app/components/user-profile-bio-manager.hbs new file mode 100644 index 0000000000..c6da654af0 --- /dev/null +++ b/packages/frontend/app/components/user-profile-bio-manager.hbs @@ -0,0 +1,289 @@ +{{#let (unique-id) as |templateId|}} +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ +
+ + {{#unless this.canEditUsernameAndPassword}} + + {{/unless}} + +
+ {{#if this.showSyncErrorMessage}} + + {{t "general.unableToSyncUser"}} + + {{/if}} +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + + {{#if this.showUsernameTakenErrorMessage}} + + {{t "errors.duplicateUsername"}} + + {{/if}} +
+ {{#if this.canEditUsernameAndPassword}} +
+ + {{#if this.changeUserPassword}} + + {{#if this.hasErrorForPassword}} + + {{else if (gt this.password.length 0)}} + + {{#if (eq this.passwordStrengthScore 0)}} + {{t "general.tryHarder"}} + {{else if (eq this.passwordStrengthScore 1)}} + {{t "general.bad"}} + {{else if (eq this.passwordStrengthScore 2)}} + {{t "general.weak"}} + {{else if (eq this.passwordStrengthScore 3)}} + {{t "general.good"}} + {{else if (eq this.passwordStrengthScore 4)}} + {{t "general.strong"}} + {{/if}} + + + {{/if}} + + {{else}} + + {{/if}} +
+ {{/if}} +
+{{/let}} \ No newline at end of file diff --git a/packages/frontend/app/components/user-profile-bio-manager.js b/packages/frontend/app/components/user-profile-bio-manager.js new file mode 100644 index 0000000000..e6a403e80d --- /dev/null +++ b/packages/frontend/app/components/user-profile-bio-manager.js @@ -0,0 +1,36 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +// import { action } from '@ember/object'; +// import { service } from '@ember/service'; +// import { TrackedAsyncData } from 'ember-async-data'; +import { ValidateIf } from 'class-validator'; +import { validatable, IsEmail, NotBlank, Length } from 'ilios-common/decorators/validation'; + +@validatable +export default class UserProfileBioManagerComponent extends Component { + @tracked @Length(1, 50) @NotBlank() firstName; + @tracked @Length(0, 20) middleName; + @tracked @Length(1, 50) @NotBlank() lastName; + @tracked @Length(0, 16) campusId; + @tracked @Length(0, 16) otherId; + @tracked @IsEmail() @Length(1, 100) @NotBlank() email; + @tracked @Length(0, 200) displayName; + @tracked @Length(0, 50) pronouns; + @tracked @IsEmail() @Length(0, 100) preferredEmail; + @tracked @Length(0, 20) phone; + @tracked + @Length(1, 100) + @NotBlank() + username; + @tracked + @ValidateIf((o) => o.canEditUsernameAndPassword && o.changeUserPassword) + @Length(5) + @NotBlank() + password; + + @tracked showSyncErrorMessage = false; + @tracked showUsernameTakenErrorMessage = false; + @tracked changeUserPassword = false; + @tracked updatedFieldsFromSync = []; + @tracked passwordStrengthScore = 0; +} diff --git a/packages/frontend/app/components/user-profile-bio.hbs b/packages/frontend/app/components/user-profile-bio.hbs index 233376b908..dd85934e68 100644 --- a/packages/frontend/app/components/user-profile-bio.hbs +++ b/packages/frontend/app/components/user-profile-bio.hbs @@ -1,14 +1,10 @@
{{#let (unique-id) as |templateId|}} - {{#if this.load.isRunning}} - - {{else}} + {{#if this.userAuthenticationData.isResolved}}
{{#if @isManaging}} {{/if}}
- {{#unless @user.authentication.username}} + {{#unless this.userAuthentication.username}}
{{t "general.missingRequiredUsername"}}
@@ -350,7 +344,7 @@ {{/if}} {{else}} - {{@user.authentication.username}} + {{this.userAuthentication.username}} {{/if}}
@@ -415,7 +409,7 @@ {{/if}} {{else}} - {{#if @user.authentication.username}} + {{#if this.userAuthentication.username}} ********* {{/if}} @@ -423,6 +417,8 @@ {{/if}} + {{else}} + {{/if}} {{/let}} \ No newline at end of file diff --git a/packages/frontend/app/components/user-profile-bio.js b/packages/frontend/app/components/user-profile-bio.js index d417d8b7ae..4c981c515c 100644 --- a/packages/frontend/app/components/user-profile-bio.js +++ b/packages/frontend/app/components/user-profile-bio.js @@ -44,6 +44,32 @@ export default class UserProfileBioComponent extends Component { userSearchTypeConfig = new TrackedAsyncData(this.iliosConfig.getUserSearchType()); + constructor() { + super(...arguments); + + this.firstName = this.args.user.firstName; + this.middleName = this.args.user.middleName; + this.lastName = this.args.user.lastName; + this.campusId = this.args.user.campusId; + this.otherId = this.args.user.otherId; + this.email = this.args.user.email; + this.displayName = this.args.user.displayName; + this.pronouns = this.args.user.pronouns; + this.preferredEmail = this.args.user.preferredEmail; + this.phone = this.args.user.phone; + + this.load.perform(); + } + + @cached + get userAuthenticationData() { + return new TrackedAsyncData(this.args.user.authentication); + } + + get userAuthentication() { + return this.userAuthenticationData.isResolved ? this.userAuthenticationData.value : null; + } + @cached get hasErrorForPasswordData() { return new TrackedAsyncData(this.hasErrorFor('password')); @@ -108,17 +134,6 @@ export default class UserProfileBioComponent extends Component { @action cancel() { - this.firstName = null; - this.lastName = null; - this.middleName = null; - this.campusId = null; - this.otherId = null; - this.email = null; - this.displayName = null; - this.pronouns = null; - this.preferredEmail = null; - this.phone = null; - this.username = null; this.password = null; this.passwordStrengthScore = 0; this.changeUserPassword = false; @@ -134,16 +149,6 @@ export default class UserProfileBioComponent extends Component { } load = restartableTask(async () => { - this.firstName = this.args.user.firstName; - this.middleName = this.args.user.middleName; - this.lastName = this.args.user.lastName; - this.campusId = this.args.user.campusId; - this.otherId = this.args.user.otherId; - this.email = this.args.user.email; - this.displayName = this.args.user.displayName; - this.pronouns = this.args.user.pronouns; - this.preferredEmail = this.args.user.preferredEmail; - this.phone = this.args.user.phone; const auth = await this.args.user.authentication; if (auth) { this.username = auth.username; diff --git a/packages/frontend/app/components/user-profile-roles.hbs b/packages/frontend/app/components/user-profile-roles.hbs index 3f93d7e974..d385d8250d 100644 --- a/packages/frontend/app/components/user-profile-roles.hbs +++ b/packages/frontend/app/components/user-profile-roles.hbs @@ -2,8 +2,6 @@ class="user-profile-roles small-component last {{if this.hasSavedRecently 'has-saved' 'has-not-saved'}}" data-test-user-profile-roles - {{did-insert (perform this.load)}} - {{did-update (perform this.load) @user.roles}} ...attributes >
diff --git a/packages/frontend/app/components/user-profile-roles.js b/packages/frontend/app/components/user-profile-roles.js index 0f36924339..2a2dd1e32b 100644 --- a/packages/frontend/app/components/user-profile-roles.js +++ b/packages/frontend/app/components/user-profile-roles.js @@ -1,9 +1,10 @@ import Component from '@glimmer/component'; import { service } from '@ember/service'; -import { dropTask, restartableTask, timeout } from 'ember-concurrency'; -import { tracked } from '@glimmer/tracking'; +import { dropTask, timeout } from 'ember-concurrency'; +import { tracked, cached } from '@glimmer/tracking'; import { action } from '@ember/object'; import { findBy } from 'ilios-common/utils/array-helpers'; +import { TrackedAsyncData } from 'ember-async-data'; export default class UserProfileRolesComponent extends Component { @service store; @@ -13,12 +14,17 @@ export default class UserProfileRolesComponent extends Component { @tracked isFormerStudentFlipped = false; @tracked isStudentFlipped = false; @tracked isUserSyncIgnoredFlipped = false; - @tracked roleTitles = []; - load = restartableTask(async () => { - const roles = await this.args.user.roles; - this.roleTitles = roles.map((role) => role.title.toLowerCase()); - }); + @cached + get roleTitlesData() { + return new TrackedAsyncData(this.args.user.roles); + } + + get roleTitles() { + return this.roleTitlesData.isResolved + ? this.roleTitlesData.value.map((role) => role.title.toLowerCase()) + : []; + } get isStudent() { const originallyYes = this.roleTitles.includes('student');