Skip to content

Commit 1d20228

Browse files
committed
Added Feedback Request 'Deny' option
1 parent 6a1ce4e commit 1d20228

File tree

4 files changed

+167
-225
lines changed

4 files changed

+167
-225
lines changed

web-ui/src/components/received_request_card/ReceivedRequestCard.jsx

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import PropTypes from 'prop-types';
77
import { selectProfile } from '../../context/selectors';
88
import DateFnsUtils from '@date-io/date-fns';
99
import { AppContext } from '../../context/AppContext';
10-
import { Edit as EditIcon } from '@mui/icons-material';
10+
import { Edit as EditIcon, Close as CloseIcon } from '@mui/icons-material';
1111
import './ReceivedRequestCard.css';
1212

1313
const dateFns = new DateFnsUtils();
@@ -21,12 +21,16 @@ const classes = {
2121
};
2222

2323
const propTypes = {
24-
request: PropTypes.object.isRequired
24+
request: PropTypes.object.isRequired,
25+
handleDenyClick: PropTypes.func.isRequired // handle deny function as a prop
2526
};
2627

27-
const ReceivedRequestCard = ({ request }) => {
28-
let { submitDate, dueDate, sendDate } = request;
28+
const ReceivedRequestCard = ({ request, handleDenyClick }) => {
29+
console.log("Rendering ReceivedRequestCard for request:", request.id);
30+
2931
const { state } = useContext(AppContext);
32+
33+
let { submitDate, dueDate, sendDate } = request;
3034
const requestCreator = selectProfile(state, request?.creatorId);
3135
const requestee = selectProfile(state, request?.requesteeId);
3236
submitDate = submitDate
@@ -67,20 +71,15 @@ const ReceivedRequestCard = ({ request }) => {
6771
};
6872

6973
return (
70-
<div
71-
className="card-content-grid"
72-
style={{ paddingLeft: '16px', paddingRight: '16px' }}
73-
>
74+
<div className="card-content-grid" style={{ paddingLeft: '16px', paddingRight: '16px' }}>
7475
<div className="request-members-container">
7576
<div className="member-chip">
7677
<Avatar
7778
style={{ width: '40px', height: '40px', marginRight: '0.5em' }}
7879
src={getAvatarURL(requestCreator?.workEmail)}
7980
/>
8081
<div>
81-
<Typography className="person-name">
82-
{requestCreator?.name}
83-
</Typography>
82+
<Typography className="person-name">{requestCreator?.name}</Typography>
8483
<Typography className="position-text" style={{ fontSize: '14px' }}>
8584
{requestCreator?.title}
8685
</Typography>
@@ -119,22 +118,30 @@ const ReceivedRequestCard = ({ request }) => {
119118
!request.submitDate &&
120119
request.id &&
121120
request.status !== 'canceled' ? (
122-
<Link
123-
to={`/feedback/submit?request=${request.id}`}
124-
style={{ textDecoration: 'none' }}
125-
>
126-
<Tooltip title="Give feedback" arrow>
127-
<IconButton size="large">
128-
<EditIcon />
121+
<>
122+
<Link to={`/feedback/submit?request=${request.id}`} style={{ textDecoration: 'none' }}>
123+
<Tooltip title="Give feedback" arrow>
124+
<IconButton size="large">
125+
<EditIcon />
126+
</IconButton>
127+
</Tooltip>
128+
</Link>
129+
<Tooltip title="Deny feedback request" arrow>
130+
<IconButton size="large" onClick={() => {
131+
console.log("X icon clicked for request ID:", request.id);
132+
handleDenyClick(request.id); // Call handleDenyClick with request ID
133+
}}>
134+
<CloseIcon />
129135
</IconButton>
130136
</Tooltip>
131-
</Link>
137+
</>
132138
) : null}
133139
</div>
134140
</div>
135141
</div>
136142
);
137143
};
144+
138145
ReceivedRequestCard.propTypes = propTypes;
139146

140-
export default ReceivedRequestCard;
147+
export default ReceivedRequestCard;

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

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useContext, useEffect, useState } from 'react';
22
import { styled } from '@mui/material/styles';
3-
import { Autocomplete, Avatar, Button, Checkbox, Chip, TextField, Typography } from '@mui/material';
3+
import { Autocomplete, Avatar, Button, Checkbox, Chip, TextField, Typography, Dialog, DialogActions, DialogContent, DialogTitle } from '@mui/material';
44
import FeedbackResponseCard from './feedback_response_card/FeedbackResponseCard';
55
import { getQuestionsAndAnswers } from '../../api/feedbackanswer';
66
import { getFeedbackRequestById } from '../../api/feedback';
@@ -50,15 +50,13 @@ const Root = styled('div')({
5050
marginRight: '3em',
5151
width: '350px',
5252
['@media (max-width: 800px)']: {
53-
// eslint-disable-line no-useless-computed-key
5453
marginRight: 0,
5554
width: '100%'
5655
}
5756
},
5857
[`& .${classes.responderField}`]: {
5958
minWidth: '500px',
6059
['@media (max-width: 800px)']: {
61-
// eslint-disable-line no-useless-computed-key
6260
minWidth: 0,
6361
width: '100%'
6462
}
@@ -79,6 +77,28 @@ const ViewFeedbackResponses = () => {
7977
useState([]);
8078
const [isLoading, setIsLoading] = useState(true);
8179

80+
// Dialog state for denying feedback
81+
const [denialPopupOpen, setDenialPopupOpen] = useState(false);
82+
const [denialReason, setDenialReason] = useState('');
83+
const [currentResponder, setCurrentResponder] = useState(null); // Track the responder being denied
84+
85+
const handleDenyClick = (responderId) => {
86+
console.log(`Denial process initiated for responder: ${responderId}`);
87+
setCurrentResponder(responderId); // Track the current responder
88+
setDenialPopupOpen(true);
89+
};
90+
91+
const handleDenialClose = () => {
92+
setDenialPopupOpen(false);
93+
console.log("Denial popup closed");
94+
};
95+
96+
const handleDenialSubmit = () => {
97+
console.log(`Denial reason for responder ${currentResponder}:`, denialReason);
98+
setDenialPopupOpen(false);
99+
// Here, you'd normally send the reason to the backend or handle it appropriately
100+
};
101+
82102
useEffect(() => {
83103
setQuery(queryString.parse(location?.search));
84104
}, [location.search]);
@@ -136,7 +156,6 @@ const ViewFeedbackResponses = () => {
136156
});
137157
}, [csrf, query.request]);
138158

139-
// Sets the options for filtering by responders
140159
useEffect(() => {
141160
let allResponders = [];
142161
questionsAndAnswers.forEach(({ answers }) => {
@@ -147,7 +166,6 @@ const ViewFeedbackResponses = () => {
147166
setResponderOptions(allResponders);
148167
}, [state, questionsAndAnswers]);
149168

150-
// Populate all responders as selected by default
151169
useEffect(() => {
152170
setSelectedResponders(responderOptions);
153171
}, [responderOptions]);
@@ -156,12 +174,10 @@ const ViewFeedbackResponses = () => {
156174
let responsesToDisplay = [...questionsAndAnswers];
157175

158176
responsesToDisplay = responsesToDisplay.map(response => {
159-
// Filter based on selected responders
160177
let filteredAnswers = response.answers.filter(answer =>
161178
selectedResponders.includes(answer.responder)
162179
);
163180
if (searchText.trim()) {
164-
// Filter based on search text
165181
filteredAnswers = filteredAnswers.filter(
166182
({ answer }) =>
167183
answer &&
@@ -172,7 +188,7 @@ const ViewFeedbackResponses = () => {
172188
});
173189

174190
setFilteredQuestionsAndAnswers(responsesToDisplay);
175-
}, [searchText, selectedResponders]); // eslint-disable-line react-hooks/exhaustive-deps
191+
}, [searchText, selectedResponders]);
176192

177193
useEffect(() => {
178194
if (isLoading && filteredQuestionsAndAnswers.length > 0) {
@@ -310,15 +326,37 @@ const ViewFeedbackResponses = () => {
310326
answer={answer.answer || ''}
311327
inputType={question.inputType}
312328
sentiment={answer.sentiment}
329+
handleDenyClick={() => handleDenyClick(answer.responder)} // Pass responderId
313330
/>
314331
))}
315332
</div>
316333
);
317334
})}
335+
336+
{/* Dialog for denial reason */}
337+
<Dialog open={denialPopupOpen} onClose={handleDenialClose}>
338+
<DialogTitle>Feedback Request Denial Explanation</DialogTitle>
339+
<DialogContent>
340+
<TextField
341+
autoFocus
342+
margin="dense"
343+
label="Denial Reason"
344+
type="text"
345+
fullWidth
346+
variant="standard"
347+
value={denialReason}
348+
onChange={(e) => setDenialReason(e.target.value)}
349+
/>
350+
</DialogContent>
351+
<DialogActions>
352+
<Button onClick={handleDenialClose}>Cancel</Button>
353+
<Button onClick={handleDenialSubmit}>Send</Button>
354+
</DialogActions>
355+
</Dialog>
318356
</Root>
319357
) : (
320358
<h3>{noPermission}</h3>
321359
);
322360
};
323361

324-
export default ViewFeedbackResponses;
362+
export default ViewFeedbackResponses;
Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,35 @@
1-
import React, { useContext } from 'react';
1+
import React from 'react';
22
import PropTypes from 'prop-types';
33
import Card from '@mui/material/Card';
44
import CardContent from '@mui/material/CardContent';
5-
import { Typography } from '@mui/material';
5+
import { Typography, IconButton } from '@mui/material';
6+
import { Close as CloseIcon } from '@mui/icons-material';
67
import './FeedbackResponseCard.css';
7-
import { AppContext } from '../../../context/AppContext';
8-
import { selectProfile } from '../../../context/selectors';
9-
import Avatar from '@mui/material/Avatar';
10-
import { getAvatarURL } from '../../../api/api.js';
11-
import FeedbackAnswerInput from '../../feedback_answer_input/FeedbackAnswerInput';
12-
13-
const propTypes = {
14-
responderId: PropTypes.string.isRequired,
15-
answer: PropTypes.string.isRequired,
16-
inputType: PropTypes.string.isRequired,
17-
sentiment: PropTypes.number
18-
};
19-
20-
const FeedbackResponseCard = props => {
21-
const { state } = useContext(AppContext);
22-
const userInfo = selectProfile(state, props.responderId);
238

9+
const FeedbackResponseCard = ({ responderId, answer, inputType, sentiment, handleDenyClick }) => {
10+
console.log("Rendering FeedbackResponseCard");
2411
return (
25-
<Card className="response-card">
26-
<CardContent className="response-card-content">
27-
<div className="response-card-recipient-info">
28-
<Avatar
29-
className="avatar-photo"
30-
src={getAvatarURL(userInfo?.workEmail)}
31-
/>
32-
<Typography className="responder-name">{userInfo?.name}</Typography>
33-
</div>
34-
<FeedbackAnswerInput
35-
inputType={props.inputType}
36-
readOnly
37-
answer={props.answer}
38-
/>
12+
<Card>
13+
<CardContent>
14+
<Typography variant="h6">Responder: {responderId}</Typography>
15+
<Typography variant="body2">Answer: {answer}</Typography>
16+
<IconButton aria-label="Deny feedback request" onClick={() => {
17+
console.log(`Deny click for responder ID: ${responderId}`);
18+
handleDenyClick();
19+
}}>
20+
<CloseIcon />
21+
</IconButton>
3922
</CardContent>
4023
</Card>
4124
);
4225
};
4326

44-
FeedbackResponseCard.propTypes = propTypes;
27+
FeedbackResponseCard.propTypes = {
28+
responderId: PropTypes.string.isRequired,
29+
answer: PropTypes.string.isRequired,
30+
inputType: PropTypes.string.isRequired,
31+
sentiment: PropTypes.number,
32+
handleDenyClick: PropTypes.func.isRequired
33+
};
4534

46-
export default FeedbackResponseCard;
35+
export default FeedbackResponseCard;

0 commit comments

Comments
 (0)