Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main'
Browse files Browse the repository at this point in the history
Signed-off-by: Jason Sherman <[email protected]>

# Conflicts:
#	app/package-lock.json
#	app/package.json
  • Loading branch information
usingtechnology committed Sep 23, 2024
2 parents 2bee361 + 267c9d6 commit 2126e56
Show file tree
Hide file tree
Showing 30 changed files with 950 additions and 10,568 deletions.
8 changes: 4 additions & 4 deletions app/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ defineExpose({
<span
v-if="
submission.status === 'SUBMITTED' &&
(submission.status === 'SUBMITTED' ||
submission.status === 'COMPLETED') &&
isCopyFromExistingSubmissionEnabled === true
"
>
Expand Down
154 changes: 137 additions & 17 deletions app/frontend/src/components/forms/submission/StatusPanel.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup>
import { storeToRefs } from 'pinia';
import { computed, ref } from 'vue';
import { computed, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import StatusTable from '~/components/forms/submission/StatusTable.vue';
Expand Down Expand Up @@ -35,13 +35,17 @@ const loading = ref(true);
const note = ref('');
const emailComment = ref('');
const submissionUserEmail = ref('');
const formSubmitters = ref([]);
const selectAllSubmitters = ref(false);
const selectedSubmissionUsers = ref([]);
const statusHistory = ref({});
const statusFields = ref(false);
const statusPanelForm = ref(null);
const statusToSet = ref('');
const valid = ref(false);
const showSendConfirmEmail = ref(false);
const showStatusContent = ref(false);
const emailRecipients = ref([]);
const formStore = useFormStore();
const notificationStore = useNotificationStore();
Expand Down Expand Up @@ -86,6 +90,45 @@ const statusAction = computed(() => {
return actionStatus;
});
async function getEmailRecipients() {
try {
const response = await formService.getEmailRecipients(
properties.submissionId
);
if (response.data) {
emailRecipients.value = response.data.emailRecipients;
} else {
emailRecipients.value = [submissionUserEmail.value];
}
} catch (error) {
notificationStore.addNotification({
text: t('trans.statusPanel.fetchSubmissionUsersErr'),
consoleError: t('trans.statusPanel.fetchSubmissionUsersErr', {
error: error.message,
}),
});
}
}
watch(selectAllSubmitters, (newValue) => {
if (newValue) {
selectedSubmissionUsers.value = formSubmitters.value.map(
(user) => user.value
);
} else {
// selectAllSubmitters is false, disable the checkbox if the array contains all the submitters
if (selectedSubmissionUsers.value.length === formSubmitters.value.length) {
selectAllSubmitters.value = true;
}
}
});
watch(selectedSubmissionUsers, (newValue) => {
if (newValue.length !== formSubmitters.value.length) {
selectAllSubmitters.value = false;
}
});
getStatus();
async function onStatusChange(status) {
Expand All @@ -95,6 +138,18 @@ async function onStatusChange(status) {
try {
await formStore.fetchSubmissionUsers(properties.submissionId);
// add all the submission users emails to the formSubmitters array
formSubmitters.value = submissionUsers.value.data.map((data) => {
const username = data.user.idpCode
? `${data.user.username} (${data.user.idpCode})`
: data.user.username;
return {
value: data.user.email,
title: `${data.user.fullName} (${data.user.email})`,
subtitle: `${username}`,
};
});
const submitterData = submissionUsers.value.data.find((data) => {
const username = data.user.idpCode
? `${data.user.username}@${data.user.idpCode}`
Expand All @@ -106,7 +161,14 @@ async function onStatusChange(status) {
submissionUserEmail.value = submitterData.user
? submitterData.user.email
: undefined;
showSendConfirmEmail.value = status === 'COMPLETED';
// add the submissionUserEmail to the selectedSubmissionUsers array
selectedSubmissionUsers.value = [submissionUserEmail.value];
if (status === 'COMPLETED') {
showSendConfirmEmail.value = true;
await getEmailRecipients();
}
}
} catch (error) {
notificationStore.addNotification({
Expand Down Expand Up @@ -136,6 +198,13 @@ function autoCompleteFilter(_itemTitle, queryText, item) {
);
}
function revisingFilter(_itemTitle, queryText, item) {
return (
item.value.toLocaleLowerCase().includes(queryText.toLocaleLowerCase()) ||
item.title.toLocaleLowerCase().includes(queryText.toLocaleLowerCase())
);
}
async function getStatus() {
loading.value = true;
try {
Expand Down Expand Up @@ -193,8 +262,12 @@ function resetForm() {
statusFields.value = false;
statusPanelForm.value.resetValidation();
submissionUserEmail.value = '';
selectAllSubmitters.value = false;
formReviewers.value = [];
selectedSubmissionUsers.value = [];
statusToSet.value = '';
note.value = '';
emailRecipients.value = [];
}
async function updateStatus() {
Expand All @@ -206,7 +279,10 @@ async function updateStatus() {
const statusBody = {
code: statusToSet.value,
submissionUserEmail: submissionUserEmail.value,
submissionUserEmails:
statusToSet.value === 'COMPLETED'
? emailRecipients.value
: selectedSubmissionUsers.value,
revisionNotificationEmailContent: emailComment.value,
};
if (showAssignee.value) {
Expand All @@ -215,6 +291,7 @@ async function updateStatus() {
statusBody.assignmentNotificationEmail = assignee.value.email;
}
}
const statusResponse = await formService.updateSubmissionStatus(
properties.submissionId,
statusBody
Expand All @@ -223,15 +300,22 @@ async function updateStatus() {
throw new Error(t('trans.statusPanel.updtSubmissionsStatusErr'));
}
if (statusToSet.value === 'REVISING') {
await formService.addEmailRecipients(properties.submissionId, {
emailRecipients: selectedSubmissionUsers.value,
});
}
if (emailComment.value) {
let formattedComment;
if (statusToSet.value === 'ASSIGNED') {
formattedComment = `Email to ${assignee.value.email}: ${emailComment.value}`;
} else if (
statusToSet.value === 'REVISING' ||
statusToSet.value === 'COMPLETED'
) {
formattedComment = `Email to ${submissionUserEmail.value}: ${emailComment.value}`;
} else if (statusToSet.value === 'REVISING') {
const emailList = selectedSubmissionUsers.value.join(', ');
formattedComment = `Email to ${emailList}: ${emailComment.value}`;
} else if (statusToSet.value === 'COMPLETED') {
const emailList = emailRecipients.value.join(', ');
formattedComment = `Email to ${emailList}: ${emailComment.value}`;
}
const submissionStatusId = statusResponse.data[0].submissionStatusId;
Expand All @@ -252,6 +336,7 @@ async function updateStatus() {
// Update the parent if the note was updated
emit('note-updated');
}
resetForm();
await getStatus();
}
Expand All @@ -269,6 +354,7 @@ defineExpose({
addComment,
assignee,
autoCompleteFilter,
revisingFilter,
emailComment,
formReviewers,
getStatus,
Expand All @@ -281,7 +367,10 @@ defineExpose({
statusFields,
statusToSet,
submissionUserEmail,
formSubmitters,
selectAllSubmitters,
updateStatus,
getEmailRecipients,
});
</script>

Expand Down Expand Up @@ -428,14 +517,46 @@ defineExpose({
</div>
</div>
<div v-show="statusFields" v-if="showRevising">
<v-text-field
v-model="submissionUserEmail"
:label="$t('trans.statusPanel.recipientEmail')"
variant="outlined"
density="compact"
<span :lang="locale">{{
$t('trans.statusPanel.recipientEmail')
}}</span>
<v-autocomplete
v-model="selectedSubmissionUsers"
:class="{ 'dir-rtl': isRTL }"
:lang="locale"
autocomplete="autocomplete_off"
data-test="showRecipientEmail"
clearable
multiple
:custom-filter="revisingFilter"
:items="formSubmitters"
item-value="value"
item-title="display"
:loading="loading"
:no-data-text="$t('trans.statusPanel.noDataText')"
variant="outlined"
:rules="[
(v) =>
!!v.length || $t('trans.statusPanel.recipientIsRequired'),
]"
:lang="locale"
>
<!-- selected user -->
<template #chip="{ props, item }">
<v-chip v-bind="props" :text="item?.raw?.value" />
</template>
<!-- users found in dropdown -->
<template #item="{ props, item }">
<v-list-item
v-bind="props"
:title="`${item?.raw?.title}`"
:subtitle="`${item?.raw?.subtitle}`"
>
</v-list-item>
</template>
</v-autocomplete>
<v-checkbox
v-model="selectAllSubmitters"
label="Notify all submitters"
/>
</div>
Expand Down Expand Up @@ -553,13 +674,12 @@ defineExpose({
margin: 0;
}
@media (max-width: 959px) {
@media (max-width: 1279px) {
.hide-on-narrow {
display: none;
}
}
@media (min-width: 960px) {
@media (min-width: 1280px) {
.hide-on-wide {
display: none;
}
Expand Down
26 changes: 26 additions & 0 deletions app/frontend/src/services/formService.js
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,32 @@ export default {
);
},

/**
* @function getEmailRecipients
* Get the email recipients for the submission
* @param {string} submissionId The form submission identifier
* @returns {Promise} An axios response
*/
getEmailRecipients(submissionId) {
return appAxios().get(
`${ApiRoutes.SUBMISSION}/${submissionId}/emailRecipients`
);
},

/**
* @function addEmailRecipients
* Add a new email recipients to the submission
* @param {string} submissionId The form submission identifier
* @param {Object} data The request body
* @returns {Promise} An axios response
*/
addEmailRecipients(submissionId, data) {
return appAxios().post(
`${ApiRoutes.SUBMISSION}/${submissionId}/emailRecipients`,
data
);
},

//
// Email
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ const BCEIDBASIC = {
param: 'username',
exact: true,
required: 2,
caseSensitive: false,
},
{
name: 'filterFullName',
Expand All @@ -104,6 +105,7 @@ const BCEIDBASIC = {
exact: true,
param: 'email',
required: 2,
caseSensitive: false,
},
{
name: 'filterSearch',
Expand Down Expand Up @@ -164,6 +166,7 @@ const BCEIDBUSINESS = {
param: 'username',
exact: true,
required: 2,
caseSensitive: false,
},
{
name: 'filterFullName',
Expand All @@ -185,6 +188,7 @@ const BCEIDBUSINESS = {
exact: true,
param: 'email',
required: 2,
caseSensitive: false,
},
{
name: 'filterSearch',
Expand Down
Loading

0 comments on commit 2126e56

Please sign in to comment.