Skip to content

Commit 4bbc2c7

Browse files
committed
Handle external recipients when viewing feedback.
1 parent f2f7cef commit 4bbc2c7

File tree

3 files changed

+56
-19
lines changed

3 files changed

+56
-19
lines changed

web-ui/src/api/feedbackanswer.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ export const getQuestionsAndAnswers = async (feedbackRequests, cookie) => {
6161
return {
6262
answer: {
6363
...obj.answer,
64-
responder: obj.request.recipientId
64+
responder: obj.request.recipientId ?? obj.request.externalRecipientId,
65+
external: !!!obj.request.recipientId
6566
},
6667
...obj.question
6768
};
@@ -85,7 +86,8 @@ export const getQuestionsAndAnswers = async (feedbackRequests, cookie) => {
8586
answer: val.answer.answer,
8687
requestId: val.answer.requestId,
8788
sentiment: val.answer.sentiment,
88-
responder: val.answer.responder
89+
responder: val.answer.responder,
90+
external: val.answer.external,
8991
};
9092
});
9193

web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import { styled } from '@mui/material/styles';
33
import { Autocomplete, Avatar, Button, Checkbox, Chip, TextField, Typography, Box } from '@mui/material';
44
import FeedbackResponseCard from './feedback_response_card/FeedbackResponseCard';
55
import { getQuestionsAndAnswers } from '../../api/feedbackanswer';
6-
import { getFeedbackRequestById } from '../../api/feedback';
6+
import {
7+
getFeedbackRequestById,
8+
getExternalRecipients
9+
} from '../../api/feedback';
710
import queryString from 'query-string';
811
import { useLocation } from 'react-router-dom';
912
import { AppContext } from '../../context/AppContext';
@@ -74,11 +77,24 @@ const ViewFeedbackResponses = () => {
7477
const [selectedResponders, setSelectedResponders] = useState([]);
7578
const [filteredQuestionsAndAnswers, setFilteredQuestionsAndAnswers] = useState([]);
7679
const [isLoading, setIsLoading] = useState(true);
80+
const [externalRecipients, setExternalRecipients] = useState([]);
7781

7882
useEffect(() => {
7983
setQuery(queryString.parse(location?.search));
8084
}, [location.search]);
8185

86+
useEffect(() => {
87+
async function fetchExternalRecipients() {
88+
const res = await getExternalRecipients();
89+
setExternalRecipients(
90+
res.payload && res.payload.data &&
91+
res.payload.status === 200 && !res.error
92+
? res.payload.data
93+
: null);
94+
}
95+
fetchExternalRecipients();
96+
}, []);
97+
8298
useEffect(() => {
8399
async function retrieveQuestionsAndAnswers(requests, cookie) {
84100
requests = requests
@@ -196,6 +212,24 @@ const ViewFeedbackResponses = () => {
196212
};
197213

198214

215+
const getResponder = (responder, external) => {
216+
let name = "";
217+
let workEmail = "";
218+
const info = selectProfile(state, responder);
219+
if (external || !info) {
220+
const current = externalRecipients.filter((e) => e.id === responder);
221+
if (current.length > 0) {
222+
const first = current[0];
223+
name = `${first.firstName} ${first.lastName}`;
224+
workEmail = first.email;
225+
}
226+
} else if (info) {
227+
name = info.name;
228+
workEmail = info.workEmail;
229+
}
230+
return {name, workEmail};
231+
};
232+
199233
return selectCanViewFeedbackAnswerPermission(state) ? (
200234

201235
<Root className="view-feedback-responses-page">
@@ -230,7 +264,7 @@ const ViewFeedbackResponses = () => {
230264
disableCloseOnSelect
231265
options={responderOptions}
232266
getOptionLabel={option => {
233-
return selectProfile(state, option)?.name;
267+
return getResponder(option)?.name;
234268
}}
235269
value={selectedResponders}
236270
onChange={(event, value) => setSelectedResponders(value)}
@@ -242,7 +276,7 @@ const ViewFeedbackResponses = () => {
242276
style={{ marginRight: 8 }}
243277
checked={selected}
244278
/>
245-
{selectProfile(state, option)?.name}
279+
{getResponder(option)?.name}
246280
</li>
247281
)}
248282
renderInput={params => (
@@ -259,7 +293,7 @@ const ViewFeedbackResponses = () => {
259293
)}
260294
renderTags={(values, getTagProps) =>
261295
values.map((responderId, index) => {
262-
const profile = selectProfile(state, responderId);
296+
const profile = getResponder(responderId);
263297
return (
264298
<Chip
265299
key={`${responderId}-chip`}
@@ -313,15 +347,17 @@ const ViewFeedbackResponses = () => {
313347

314348
{/* If the question has no answers or inputType is "NONE" */}
315349
{!hasResponses || question.inputType === 'NONE' ? null : (
316-
question.answers.map(answer => (
317-
<FeedbackResponseCard
350+
question.answers.map(answer => {
351+
const { workEmail, name } = getResponder(answer.responder, answer.external);
352+
return <FeedbackResponseCard
318353
key={answer.id || answer.responder}
319-
responderId={answer.responder}
320-
answer={isEmptyOrWhitespace(answer.answer) ? ' ⚠️ No response submitted' : String(answer.answer)}
354+
responderName={name}
355+
responderEmail={workEmail}
356+
answer={String(answer.answer)}
321357
inputType={question.inputType}
322358
sentiment={answer.sentiment}
323-
/>
324-
))
359+
/>;
360+
})
325361
)}
326362
</div>
327363
);
@@ -332,4 +368,4 @@ const ViewFeedbackResponses = () => {
332368
);
333369
};
334370

335-
export default ViewFeedbackResponses;
371+
export default ViewFeedbackResponses;

web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,20 @@ import CardContent from '@mui/material/CardContent';
55
import { Typography } from '@mui/material';
66
import './FeedbackResponseCard.css';
77
import { AppContext } from '../../../context/AppContext';
8-
import { selectProfile } from '../../../context/selectors';
98
import Avatar from '@mui/material/Avatar';
109
import { getAvatarURL } from '../../../api/api.js';
1110
import FeedbackAnswerInput from '../../feedback_answer_input/FeedbackAnswerInput';
1211

1312
const propTypes = {
14-
responderId: PropTypes.string.isRequired,
13+
responderName: PropTypes.string.isRequired,
14+
responderEmail: PropTypes.string.isRequired,
1515
answer: PropTypes.string, // Allow answer to be null or undefined
1616
inputType: PropTypes.string.isRequired,
1717
sentiment: PropTypes.number
1818
};
1919

2020
const FeedbackResponseCard = props => {
2121
const { state } = useContext(AppContext);
22-
const userInfo = selectProfile(state, props.responderId);
2322

2423
const getFormattedAnswer = () => {
2524
if (props.inputType === 'NONE') {
@@ -40,9 +39,9 @@ const FeedbackResponseCard = props => {
4039
<div className="response-card-recipient-info">
4140
<Avatar
4241
className="avatar-photo"
43-
src={getAvatarURL(userInfo?.workEmail)}
42+
src={getAvatarURL(props.responderEmail)}
4443
/>
45-
<Typography className="responder-name">{userInfo?.name}</Typography>
44+
<Typography className="responder-name">{props.responderName}</Typography>
4645
</div>
4746
{props.inputType !== 'NONE' && (
4847
<FeedbackAnswerInput
@@ -58,4 +57,4 @@ const FeedbackResponseCard = props => {
5857

5958
FeedbackResponseCard.propTypes = propTypes;
6059

61-
export default FeedbackResponseCard;
60+
export default FeedbackResponseCard;

0 commit comments

Comments
 (0)