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 All @@ -10,6 +11,7 @@ import InstitutionModel from 'ember-osf-web/models/institution';
import InstitutionDepartmentsModel from 'ember-osf-web/models/institution-department';
import Analytics from 'ember-osf-web/services/analytics';
import { RelationshipWithLinks } from 'osf-api';
import {MessageTypeChoices} from 'ember-osf-web/models/user-message';

interface Column {
key: string;
Expand All @@ -27,6 +29,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 +41,12 @@ export default class InstitutionalUsersList extends Component<InstitutionalUsers
@tracked sort = 'user_name';
@tracked selectedDepartments: string[] = [];
@tracked filteredUsers = [];
@tracked messageModalShown = false;
@tracked messageText = '';
@tracked bcc_sender = false;
@tracked replyTo = false;
@tracked selectedUserId = null;
@service toast!: Toast;

@tracked columns: Column[] = [
{
Expand Down Expand Up @@ -262,4 +272,54 @@ 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.bcc_sender = false;
this.replyTo = false;
this.selectedUserId = null;
}

@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: MessageTypeChoices.InstitutionalRequest,
bcc_sender: this.bcc_sender,
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,50 @@
{{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.bcc_sender}} />
{{t 'institutions.dashboard.send_message_modal.cc_label'}}
</label>
<label local-class='checkbox-item'>
<Input @type='checkbox' @checked={{this.replyTo}} />
{{t 'institutions.dashboard.send_message_modal.reply_to_label'}}
</label>
</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))}}

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

export enum MessageTypeChoices {
InstitutionalRequest = 'institutional_request',
}


export default class UserMessageModel extends Model {
futa-ikeda marked this conversation as resolved.
Show resolved Hide resolved
@attr('string') messageText;
@attr('string') messageType: MessageTypeChoices;
@attr('boolean') bcc_sender;
@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