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

[ENG-6665] Add user messaging modal to user's tab on institutional dashboard #2421

13 changes: 13 additions & 0 deletions app/adapters/user-message.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// app/adapters/user-message.js
import { inject as service } from '@ember/service';
import config from 'ember-osf-web/config/environment';
const { OSF: { apiUrl } } = config;
import OsfAdapter from './osf-adapter';

export default class UserMessageAdapter extends OsfAdapter {
@service session;
urlForCreateRecord(modelName, snapshot) {
const userId = snapshot.record.user;
return `${apiUrl}/v2/users/${userId}/messages/`;
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { task } from 'ember-concurrency';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
Expand Down Expand Up @@ -27,6 +28,8 @@ interface InstitutionalUsersListArgs {
export default class InstitutionalUsersList extends Component<InstitutionalUsersListArgs> {
@service analytics!: Analytics;
@service intl!: Intl;
@service store;
@service currentUser!: CurrentUser;

institution?: InstitutionModel;

Expand All @@ -37,6 +40,10 @@ export default class InstitutionalUsersList extends Component<InstitutionalUsers
@tracked sort = 'user_name';
@tracked selectedDepartments: string[] = [];
@tracked filteredUsers = [];
@tracked messageModalShown = false;
@tracked messageText = '';
@tracked selectedUserId = null;
@service toast!: Toast;

@tracked columns: Column[] = [
{
Expand Down Expand Up @@ -262,4 +269,69 @@ export default class InstitutionalUsersList extends Component<InstitutionalUsers
clickToggleOrcidFilter(hasOrcid: boolean) {
this.hasOrcid = !hasOrcid;
}

@action
openMessageModal(userId: string) {
this.selectedUserId = userId;
this.messageModalShown = true;
}

@action
toggleMessageModal(userId: string | null = null) {
this.messageModalShown = !this.messageModalShown;
this.selectedUserId = userId;
if (!this.messageModalShown) {
this.resetModalFields();
}
}

@action
resetModalFields() {
this.messageText = '';
this.cc = false;
this.replyTo = false;
Johnetordoff marked this conversation as resolved.
Show resolved Hide resolved
this.selectedUserId = null;
}

@action
updateMessageText(event: Event) {
this.messageText = (event.target as HTMLTextAreaElement).value;
}
Johnetordoff marked this conversation as resolved.
Show resolved Hide resolved

@action
toggleCc() {
this.cc = !this.cc;
}

@action
toggleReplyTo() {
this.replyTo = !this.replyTo;
}
Johnetordoff marked this conversation as resolved.
Show resolved Hide resolved

@task
@waitFor
async sendMessage() {
if (!this.messageText.trim()) {
this.toast.error(this.intl.t('error.empty_message'));
return;
}

try {
const userMessage = this.store.createRecord('user-message', {
messageText: this.messageText.trim(),
messageType: 'institutional_request',
Johnetordoff marked this conversation as resolved.
Show resolved Hide resolved
cc: this.cc,
replyTo: this.replyTo,
institution: this.args.institution,
user: this.selectedUserId,
});

await userMessage.save();
this.toast.success(this.intl.t('institutions.dashboard.send_message_modal.message_sent_success'));
} catch (error) {
this.toast.error(this.intl.t('institutions.dashboard.send_message_modal.message_sent_failed'));
} finally {
this.messageModalShown = false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,41 @@ input:checked + .slider::before {
justify-content: flex-end;
margin-right: 15px;
}


.icon-message {
opacity: 0;
color: $color-text-blue-dark;
/* !important used to override ember Button border scripting */
background-color: inherit !important;
border: 0 !important;
box-shadow: 0 !important;
}

.icon-message:hover {
opacity: 1;
background-color: inherit !important;
}

.message-textarea {
min-width: 450px;
min-height: 280px;
}

.message-label {
display: block;
}

.checkbox-container {
display: flex;
flex-direction: column;
gap: 10px;
padding: 10px;
}

.checkbox-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,14 @@
<OsfLink @href={{concat '/' institutionalUser.userGuid '/'}}>
{{institutionalUser.userName}}
</OsfLink>
<Button
local-class='icon-message'
aria-label={{t 'institutions.dashboard.send_message_modal.open_aira_label'}}

{{on 'click' (fn this.openMessageModal institutionalUser.userGuid)}}
>
<FaIcon @icon='comment' />
</Button>
{{else if (eq column.type 'osf_link')}}
<OsfLink @href={{concat '/' institutionalUser.userGuid '/'}}>
{{institutionalUser.userGuid}}
Expand Down Expand Up @@ -204,4 +212,51 @@
{{t 'institutions.dashboard.users_list.empty'}}
</list.empty>
</PaginatedList::HasMany>
<OsfDialog @isOpen={{this.messageModalShown}} @onClose={{this.toggleMessageModal}} as |dialog|>
<dialog.heading>
{{t 'institutions.dashboard.send_message_modal.title'}}
</dialog.heading>
<dialog.main>
<div>
<label for='message-text' local-class='message-label'>
{{t 'institutions.dashboard.send_message_modal.opening_message_label'}}
</label>
<Textarea
id='message-text'
local-class='message-textarea'
@value={{this.messageText}}
/>
<div>
{{t 'institutions.dashboard.send_message_modal.closing_message_label' adminName=this.currentUser.user.fullName htmlSafe=true}}
</div>
<div local-class='checkbox-container'>
<label local-class='checkbox-item'>
<input type='checkbox' checked={{this.cc}} {{on 'change' this.toggleCc}} />
{{t 'institutions.dashboard.send_message_modal.cc_label'}}
</label>
<label local-class='checkbox-item'>
<input type='checkbox' checked={{this.replyTo}} {{on 'change' this.toggleReplyTo}} />
{{t 'institutions.dashboard.send_message_modal.reply_to_label'}}
</label>
Johnetordoff marked this conversation as resolved.
Show resolved Hide resolved
</div>
</div>
</dialog.main>
<dialog.footer>
<Button
@type='secondary'
{{on 'click' this.toggleMessageModal}}
>
{{t 'general.cancel'}}
</Button>
<Button
@type='primary'
@disabled={{not this.messageText.trim}}
{{on 'click' (queue (perform this.sendMessage))}}
{{on 'click' this.toggleMessageModal}}
Johnetordoff marked this conversation as resolved.
Show resolved Hide resolved

>
{{t 'institutions.dashboard.send_message_modal.send'}}
</Button>
</dialog.footer>
</OsfDialog>
{{/if}}
10 changes: 10 additions & 0 deletions app/models/user-message.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// app/models/user-message.js
import Model, { attr, belongsTo } from '@ember-data/model';

export default class UserMessageModel extends Model {
futa-ikeda marked this conversation as resolved.
Show resolved Hide resolved
@attr('string') messageText;
@attr('string') messageType;
Johnetordoff marked this conversation as resolved.
Show resolved Hide resolved
@attr('boolean') cc;
@attr('boolean') replyTo;
@belongsTo('institution') institution;
}
12 changes: 12 additions & 0 deletions translations/en-us.yml
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,18 @@ institutions:
search_placeholder: 'Search institutions'
load_more: 'Load more institutions'
dashboard:
send_message_modal:
open_aira_label: 'Open User Message Modal Button'
close_aira_label: 'Close User Message Modal Button'
send_aira_label: 'Send User Message Button'
title: 'Send Email'
opening_message_label: 'Comments:'
closing_message_label: 'Sincerely Yours,<br> {adminName}'
message_sent_success: 'Message has been sent'
message_sent_failed: 'Message has failed to send. If the issue persists contact your administrator'
send: 'Send'
cc_label: 'CC sender'
reply_to_label: 'Allow reply to sender address'
tabs:
summary: Summary
users: Users
Expand Down
Loading