From 7eb19b41af8adc5882bfb842445f57181701edfb Mon Sep 17 00:00:00 2001 From: Will Thelen Date: Mon, 7 Oct 2024 09:49:32 -0500 Subject: [PATCH 1/6] Complete feedback response updates --- .../ViewFeedbackResponses.css | 13 ++- .../ViewFeedbackResponses.jsx | 106 ++++++++++++------ .../FeedbackResponseCard.jsx | 4 +- .../components/volunteer/Organizations.jsx | 1 - 4 files changed, 88 insertions(+), 36 deletions(-) diff --git a/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.css b/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.css index 6b0870be1e..5e5a54a720 100644 --- a/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.css +++ b/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.css @@ -24,6 +24,17 @@ text-align: center; border-radius: 4px; padding: 10px; + display: flex; + align-items: center; +} + +.caution-icon { + display: inline-block; + width: 16px; + height: 16px; + background-image: url('path-to-caution-icon.png'); /* Add the correct icon path */ + background-size: cover; + margin-right: 8px; } .question-responses-container { @@ -48,4 +59,4 @@ height: 200px; margin-bottom: 2em; } -} +} \ No newline at end of file diff --git a/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx b/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx index 5b344b460f..baff9398b5 100644 --- a/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx +++ b/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx @@ -1,6 +1,6 @@ import React, { useContext, useEffect, useState } from 'react'; import { styled } from '@mui/material/styles'; -import { Autocomplete, Avatar, Button, Checkbox, Chip, TextField, Typography } from '@mui/material'; +import { Autocomplete, Avatar, Button, Checkbox, Chip, TextField, Typography, Box } from '@mui/material'; import FeedbackResponseCard from './feedback_response_card/FeedbackResponseCard'; import { getQuestionsAndAnswers } from '../../api/feedbackanswer'; import { getFeedbackRequestById } from '../../api/feedback'; @@ -15,6 +15,7 @@ import { getAvatarURL } from '../../api/api'; import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; import CheckBoxIcon from '@mui/icons-material/CheckBox'; import SkeletonLoader from '../skeleton_loader/SkeletonLoader'; +import ReportProblemOutlinedIcon from '@mui/icons-material/ReportProblemOutlined'; // Import the caution icon import './ViewFeedbackResponses.css'; @@ -85,7 +86,21 @@ const ViewFeedbackResponses = () => { ? requests : [requests] : []; - return await getQuestionsAndAnswers(requests, cookie); + const res = await getQuestionsAndAnswers(requests, cookie); + + if (res) { + console.log('Retrieved Questions and Answers:', res); // Debugging log + res.sort((a, b) => a.questionNumber - b.questionNumber); + setQuestionsAndAnswers(res); + } else { + window.snackDispatch({ + type: UPDATE_TOAST, + payload: { + severity: 'error', + toast: 'Failed to retrieve questions and answers' + } + }); + } } if (!csrf || !query.request) { @@ -115,20 +130,7 @@ const ViewFeedbackResponses = () => { }); } }); - retrieveQuestionsAndAnswers(query.request, csrf).then(res => { - if (res) { - res.sort((a, b) => a.questionNumber - b.questionNumber); - setQuestionsAndAnswers(res); - } else { - window.snackDispatch({ - type: UPDATE_TOAST, - payload: { - severity: 'error', - toast: 'Failed to retrieve questions and answers' - } - }); - } - }); + retrieveQuestionsAndAnswers(query.request, csrf); }, [csrf, query.request]); // Sets the options for filtering by responders @@ -179,6 +181,10 @@ const ViewFeedbackResponses = () => { setSelectedResponders(responderOptions); }; + const isEmptyOrWhitespace = (text) => { + return !text || text.trim() === ''; + }; + return ( { ))} {!isLoading && filteredQuestionsAndAnswers?.map(question => { + // Handle Section Headers for questions 3 and 10 + if (question.questionNumber === 3) { + return ( + + Section 1: How often has this team member displayed each of the following behaviors during the period covered by this review? + + ); + } + + if (question.questionNumber === 10) { + return ( + + Section 2: You can provide more detailed context to your review of this team member below. Be as specific as possible! + + ); + } + + // Handle other questions by removing "Q#: " + const questionText = question.question.replace(/^Q\d+: /, ''); + const hasResponses = question.answers.length > 0; + return (
{ className="question-text" style={{ marginBottom: '0.5em', fontWeight: 'bold' }} > - Q{question.questionNumber}: {question.question} + {questionText} - {question.answers.length === 0 && ( + + {!hasResponses && (
- - No matching responses found + + {/* Display caution icon */} + Not yet submitted
)} - {question.inputType !== 'NONE' && - question.answers.length > 0 && - question.answers.map(answer => ( - - ))} + + {hasResponses && question.answers.map(answer => ( + + ))}
); })} @@ -314,4 +356,4 @@ const ViewFeedbackResponses = () => { ); }; -export default ViewFeedbackResponses; +export default ViewFeedbackResponses; \ No newline at end of file diff --git a/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx b/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx index 42a14d3c32..1b6e7cc749 100644 --- a/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx +++ b/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx @@ -34,7 +34,7 @@ const FeedbackResponseCard = props => { @@ -43,4 +43,4 @@ const FeedbackResponseCard = props => { FeedbackResponseCard.propTypes = propTypes; -export default FeedbackResponseCard; +export default FeedbackResponseCard; \ No newline at end of file diff --git a/web-ui/src/components/volunteer/Organizations.jsx b/web-ui/src/components/volunteer/Organizations.jsx index 8af7b69d60..7481ef1410 100644 --- a/web-ui/src/components/volunteer/Organizations.jsx +++ b/web-ui/src/components/volunteer/Organizations.jsx @@ -66,7 +66,6 @@ const Organizations = ({ onlyMe = false }) => { // Add organization handler const addOrganization = useCallback(() => { - console.log("Add Organization button clicked"); // Debugging log setNewOrganization({ name: '', description: '', website: '' }); // Reset the new organization form setOrganizationDialogOpen(true); }, []); From 89dc34fb6a023c1586c61ccd7c8c026b498e76aa Mon Sep 17 00:00:00 2001 From: Will Thelen Date: Mon, 7 Oct 2024 10:09:43 -0500 Subject: [PATCH 2/6] Pulled develop + small UI upgrade --- .../feedback_response_card/FeedbackResponseCard.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx b/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx index 1b6e7cc749..22eb675968 100644 --- a/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx +++ b/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx @@ -34,7 +34,7 @@ const FeedbackResponseCard = props => { From 681b616a67570ca67c8bfadc162103d417207bea Mon Sep 17 00:00:00 2001 From: Will Thelen Date: Mon, 7 Oct 2024 13:39:15 -0500 Subject: [PATCH 3/6] Some response cards still fail to display answer or replacement text. Investigating backend code --- .../ViewFeedbackResponses.css | 1 - .../ViewFeedbackResponses.jsx | 68 ++++++++----------- .../FeedbackResponseCard.jsx | 12 +++- .../components/volunteer/Organizations.jsx | 1 - 4 files changed, 38 insertions(+), 44 deletions(-) diff --git a/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.css b/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.css index 5e5a54a720..96bb179aff 100644 --- a/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.css +++ b/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.css @@ -32,7 +32,6 @@ display: inline-block; width: 16px; height: 16px; - background-image: url('path-to-caution-icon.png'); /* Add the correct icon path */ background-size: cover; margin-right: 8px; } diff --git a/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx b/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx index baff9398b5..bce72a4185 100644 --- a/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx +++ b/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx @@ -89,9 +89,17 @@ const ViewFeedbackResponses = () => { const res = await getQuestionsAndAnswers(requests, cookie); if (res) { - console.log('Retrieved Questions and Answers:', res); // Debugging log - res.sort((a, b) => a.questionNumber - b.questionNumber); - setQuestionsAndAnswers(res); + const sanitizedResponses = res.map(question => ({ + ...question, + answers: question.answers.map(answer => ({ + ...answer, + answer: isEmptyOrWhitespace(answer.answer) ? ' ⚠️ No response submitted' : String(answer.answer) + })) + })); + + sanitizedResponses.sort((a, b) => a.questionNumber - b.questionNumber); + setQuestionsAndAnswers(sanitizedResponses); + } else { window.snackDispatch({ type: UPDATE_TOAST, @@ -165,12 +173,23 @@ const ViewFeedbackResponses = () => { answer.toLowerCase().includes(searchText.trim().toLowerCase()) ); } + + // Ensure blank, null, undefined, or non-string answers are handled + filteredAnswers = filteredAnswers.map(answer => ({ + ...answer, + answer: isEmptyOrWhitespace(answer.answer) ? ' ⚠️ No response submitted' : String(answer.answer) + })); + return { ...response, answers: filteredAnswers }; }); setFilteredQuestionsAndAnswers(responsesToDisplay); }, [searchText, selectedResponders]); // eslint-disable-line react-hooks/exhaustive-deps + useEffect(() => { + console.log("CSRF Token:", csrf); + }, [csrf, state]); + useEffect(() => { if (isLoading && filteredQuestionsAndAnswers.length > 0) { setIsLoading(false); @@ -181,8 +200,9 @@ const ViewFeedbackResponses = () => { setSelectedResponders(responderOptions); }; + // Updated isEmptyOrWhitespace function to handle non-string values const isEmptyOrWhitespace = (text) => { - return !text || text.trim() === ''; + return typeof text !== 'string' || !text.trim(); }; return ( @@ -284,39 +304,7 @@ const ViewFeedbackResponses = () => { ))} {!isLoading && filteredQuestionsAndAnswers?.map(question => { - // Handle Section Headers for questions 3 and 10 - if (question.questionNumber === 3) { - return ( - - Section 1: How often has this team member displayed each of the following behaviors during the period covered by this review? - - ); - } - - if (question.questionNumber === 10) { - return ( - - Section 2: You can provide more detailed context to your review of this team member below. Be as specific as possible! - - ); - } - - // Handle other questions by removing "Q#: " - const questionText = question.question.replace(/^Q\d+: /, ''); + const questionText = question.question; const hasResponses = question.answers.length > 0; return ( @@ -334,8 +322,8 @@ const ViewFeedbackResponses = () => { {!hasResponses && (
- {/* Display caution icon */} - Not yet submitted + + ⚠️ No response submitted
)} @@ -344,7 +332,7 @@ const ViewFeedbackResponses = () => { diff --git a/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx b/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx index 22eb675968..b4b03c3b8d 100644 --- a/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx +++ b/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx @@ -12,7 +12,7 @@ import FeedbackAnswerInput from '../../feedback_answer_input/FeedbackAnswerInput const propTypes = { responderId: PropTypes.string.isRequired, - answer: PropTypes.string.isRequired, + answer: PropTypes.string, // Make answer optional in case it's null inputType: PropTypes.string.isRequired, sentiment: PropTypes.number }; @@ -21,6 +21,14 @@ const FeedbackResponseCard = props => { const { state } = useContext(AppContext); const userInfo = selectProfile(state, props.responderId); + // Fallback answer handling + const getFormattedAnswer = () => { + // Check if the answer is a string and has content, otherwise return the fallback + return typeof props.answer === 'string' && props.answer.trim() + ? props.answer + : ' ⚠️ No response submitted'; + }; + return ( @@ -34,7 +42,7 @@ const FeedbackResponseCard = props => { diff --git a/web-ui/src/components/volunteer/Organizations.jsx b/web-ui/src/components/volunteer/Organizations.jsx index 7481ef1410..49e774eee0 100644 --- a/web-ui/src/components/volunteer/Organizations.jsx +++ b/web-ui/src/components/volunteer/Organizations.jsx @@ -203,7 +203,6 @@ const Organizations = ({ onlyMe = false }) => { aria-label="Add Organization" onClick={addOrganization} // Open the dialog to add an organization > - {console.log("Add Organization button rendered")} From 7e9d353c57ec1adff0c34bec94466e84aab376bb Mon Sep 17 00:00:00 2001 From: Will Thelen Date: Mon, 7 Oct 2024 14:55:34 -0500 Subject: [PATCH 4/6] Complete --- .../ViewFeedbackResponses.jsx | 62 +++++++++---------- .../FeedbackResponseCard.jsx | 20 +++--- 2 files changed, 42 insertions(+), 40 deletions(-) diff --git a/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx b/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx index bce72a4185..eefbbc5b7d 100644 --- a/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx +++ b/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx @@ -15,7 +15,7 @@ import { getAvatarURL } from '../../api/api'; import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; import CheckBoxIcon from '@mui/icons-material/CheckBox'; import SkeletonLoader from '../skeleton_loader/SkeletonLoader'; -import ReportProblemOutlinedIcon from '@mui/icons-material/ReportProblemOutlined'; // Import the caution icon +import ReportProblemOutlinedIcon from '@mui/icons-material/ReportProblemOutlined'; import './ViewFeedbackResponses.css'; @@ -46,7 +46,6 @@ const Root = styled('div')({ marginRight: '3em', width: '350px', ['@media (max-width: 800px)']: { - // eslint-disable-line no-useless-computed-key marginRight: 0, width: '100%' } @@ -54,7 +53,6 @@ const Root = styled('div')({ [`& .${classes.responderField}`]: { minWidth: '500px', ['@media (max-width: 800px)']: { - // eslint-disable-line no-useless-computed-key minWidth: 0, width: '100%' } @@ -71,8 +69,7 @@ const ViewFeedbackResponses = () => { const [searchText, setSearchText] = useState(''); const [responderOptions, setResponderOptions] = useState([]); const [selectedResponders, setSelectedResponders] = useState([]); - const [filteredQuestionsAndAnswers, setFilteredQuestionsAndAnswers] = - useState([]); + const [filteredQuestionsAndAnswers, setFilteredQuestionsAndAnswers] = useState([]); const [isLoading, setIsLoading] = useState(true); useEffect(() => { @@ -93,7 +90,8 @@ const ViewFeedbackResponses = () => { ...question, answers: question.answers.map(answer => ({ ...answer, - answer: isEmptyOrWhitespace(answer.answer) ? ' ⚠️ No response submitted' : String(answer.answer) + // Ensure blank, null, undefined, or non-string answers are handled + answer: isEmptyOrWhitespace(answer.answer) ? ' ⚠️ No response submitted' : String(answer.answer), })) })); @@ -161,12 +159,10 @@ const ViewFeedbackResponses = () => { let responsesToDisplay = [...questionsAndAnswers]; responsesToDisplay = responsesToDisplay.map(response => { - // Filter based on selected responders let filteredAnswers = response.answers.filter(answer => selectedResponders.includes(answer.responder) ); if (searchText.trim()) { - // Filter based on search text filteredAnswers = filteredAnswers.filter( ({ answer }) => answer && @@ -174,22 +170,13 @@ const ViewFeedbackResponses = () => { ); } - // Ensure blank, null, undefined, or non-string answers are handled - filteredAnswers = filteredAnswers.map(answer => ({ - ...answer, - answer: isEmptyOrWhitespace(answer.answer) ? ' ⚠️ No response submitted' : String(answer.answer) - })); - return { ...response, answers: filteredAnswers }; }); setFilteredQuestionsAndAnswers(responsesToDisplay); }, [searchText, selectedResponders]); // eslint-disable-line react-hooks/exhaustive-deps - useEffect(() => { - console.log("CSRF Token:", csrf); - }, [csrf, state]); - + // Add "No input" for questions with inputType "NONE" useEffect(() => { if (isLoading && filteredQuestionsAndAnswers.length > 0) { setIsLoading(false); @@ -200,7 +187,6 @@ const ViewFeedbackResponses = () => { setSelectedResponders(responderOptions); }; - // Updated isEmptyOrWhitespace function to handle non-string values const isEmptyOrWhitespace = (text) => { return typeof text !== 'string' || !text.trim(); }; @@ -319,24 +305,34 @@ const ViewFeedbackResponses = () => { {questionText}
- {!hasResponses && ( + {/* If the question has no answers or inputType is "NONE" */} + {!hasResponses || question.inputType === 'NONE' ? (
- - - ⚠️ No response submitted + + + {question.inputType === 'NONE' ? 'No input available for this question.' : '⚠️ No response submitted'}
+ ) : ( + question.answers.map(answer => ( + + )) )} - - {hasResponses && question.answers.map(answer => ( - - ))} ); })} diff --git a/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx b/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx index b4b03c3b8d..9a5f7d010d 100644 --- a/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx +++ b/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx @@ -12,7 +12,7 @@ import FeedbackAnswerInput from '../../feedback_answer_input/FeedbackAnswerInput const propTypes = { responderId: PropTypes.string.isRequired, - answer: PropTypes.string, // Make answer optional in case it's null + answer: PropTypes.string, // Allow answer to be null or undefined inputType: PropTypes.string.isRequired, sentiment: PropTypes.number }; @@ -21,12 +21,18 @@ const FeedbackResponseCard = props => { const { state } = useContext(AppContext); const userInfo = selectProfile(state, props.responderId); - // Fallback answer handling + // Handle different input types and answer values const getFormattedAnswer = () => { - // Check if the answer is a string and has content, otherwise return the fallback - return typeof props.answer === 'string' && props.answer.trim() - ? props.answer - : ' ⚠️ No response submitted'; + if (props.inputType === 'NONE') { + return 'No input'; // Display "No input" if the question input type is "NONE" + } + + // Return fallback if the answer is null, undefined, or empty + if (props.answer === null || props.answer === undefined || !props.answer.trim()) { + return '⚠️ No response submitted'; + } + + return props.answer; }; return ( @@ -42,7 +48,7 @@ const FeedbackResponseCard = props => { From dafe0f3864a77e6e3336519f61b1bdf286be503d Mon Sep 17 00:00:00 2001 From: Will Thelen Date: Mon, 7 Oct 2024 15:18:34 -0500 Subject: [PATCH 5/6] Fixed edge case w/ recipient filter + UI upgrades --- .../view_feedback_responses/ViewFeedbackResponses.jsx | 9 ++++++++- .../feedback_response_card/FeedbackResponseCard.jsx | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx b/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx index eefbbc5b7d..65afb3e3ca 100644 --- a/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx +++ b/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx @@ -157,12 +157,19 @@ const ViewFeedbackResponses = () => { useEffect(() => { let responsesToDisplay = [...questionsAndAnswers]; - + // Filter based on selected responders responsesToDisplay = responsesToDisplay.map(response => { let filteredAnswers = response.answers.filter(answer => selectedResponders.includes(answer.responder) ); + + // If no filtered answers remain after filtering recipients, display a unified error message + if (filteredAnswers.length === 0) { + filteredAnswers = [{ answer: 'No input due to recipient filter', responder: null }]; + } + if (searchText.trim()) { + // Filter based on search text filteredAnswers = filteredAnswers.filter( ({ answer }) => answer && diff --git a/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx b/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx index 9a5f7d010d..03583e8853 100644 --- a/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx +++ b/web-ui/src/components/view_feedback_responses/feedback_response_card/FeedbackResponseCard.jsx @@ -23,6 +23,10 @@ const FeedbackResponseCard = props => { // Handle different input types and answer values const getFormattedAnswer = () => { + if (props.answer === 'No input due to recipient filter') { + return props.answer; + } + if (props.inputType === 'NONE') { return 'No input'; // Display "No input" if the question input type is "NONE" } From 9fb60faf355acad8e8f36e17c65ee86e48c51f99 Mon Sep 17 00:00:00 2001 From: Will Thelen Date: Mon, 7 Oct 2024 15:50:38 -0500 Subject: [PATCH 6/6] Removed cards under non-input questions --- .../ViewFeedbackResponses.jsx | 31 ++----------------- .../FeedbackResponseCard.jsx | 19 +++++------- 2 files changed, 11 insertions(+), 39 deletions(-) diff --git a/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx b/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx index 65afb3e3ca..c6a7e24b6d 100644 --- a/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx +++ b/web-ui/src/components/view_feedback_responses/ViewFeedbackResponses.jsx @@ -15,8 +15,6 @@ import { getAvatarURL } from '../../api/api'; import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; import CheckBoxIcon from '@mui/icons-material/CheckBox'; import SkeletonLoader from '../skeleton_loader/SkeletonLoader'; -import ReportProblemOutlinedIcon from '@mui/icons-material/ReportProblemOutlined'; - import './ViewFeedbackResponses.css'; const PREFIX = 'MuiCardContent'; @@ -90,7 +88,6 @@ const ViewFeedbackResponses = () => { ...question, answers: question.answers.map(answer => ({ ...answer, - // Ensure blank, null, undefined, or non-string answers are handled answer: isEmptyOrWhitespace(answer.answer) ? ' ⚠️ No response submitted' : String(answer.answer), })) })); @@ -139,37 +136,32 @@ const ViewFeedbackResponses = () => { retrieveQuestionsAndAnswers(query.request, csrf); }, [csrf, query.request]); - // Sets the options for filtering by responders useEffect(() => { let allResponders = []; questionsAndAnswers.forEach(({ answers }) => { const responders = answers.map(answer => answer.responder); allResponders.push(...responders); }); - allResponders = [...new Set(allResponders)]; // Remove duplicate responders + allResponders = [...new Set(allResponders)]; setResponderOptions(allResponders); }, [state, questionsAndAnswers]); - // Populate all responders as selected by default useEffect(() => { setSelectedResponders(responderOptions); }, [responderOptions]); useEffect(() => { let responsesToDisplay = [...questionsAndAnswers]; - // Filter based on selected responders responsesToDisplay = responsesToDisplay.map(response => { let filteredAnswers = response.answers.filter(answer => selectedResponders.includes(answer.responder) ); - // If no filtered answers remain after filtering recipients, display a unified error message if (filteredAnswers.length === 0) { filteredAnswers = [{ answer: 'No input due to recipient filter', responder: null }]; } if (searchText.trim()) { - // Filter based on search text filteredAnswers = filteredAnswers.filter( ({ answer }) => answer && @@ -181,9 +173,8 @@ const ViewFeedbackResponses = () => { }); setFilteredQuestionsAndAnswers(responsesToDisplay); - }, [searchText, selectedResponders]); // eslint-disable-line react-hooks/exhaustive-deps + }, [searchText, selectedResponders]); - // Add "No input" for questions with inputType "NONE" useEffect(() => { if (isLoading && filteredQuestionsAndAnswers.length > 0) { setIsLoading(false); @@ -313,23 +304,7 @@ const ViewFeedbackResponses = () => { {/* If the question has no answers or inputType is "NONE" */} - {!hasResponses || question.inputType === 'NONE' ? ( -
- - - {question.inputType === 'NONE' ? 'No input available for this question.' : '⚠️ No response submitted'} - -
- ) : ( + {!hasResponses || question.inputType === 'NONE' ? null : ( question.answers.map(answer => ( { const { state } = useContext(AppContext); const userInfo = selectProfile(state, props.responderId); - // Handle different input types and answer values const getFormattedAnswer = () => { - if (props.answer === 'No input due to recipient filter') { - return props.answer; - } - if (props.inputType === 'NONE') { - return 'No input'; // Display "No input" if the question input type is "NONE" + return null; // Return null to display nothing } // Return fallback if the answer is null, undefined, or empty @@ -49,11 +44,13 @@ const FeedbackResponseCard = props => { /> {userInfo?.name} - + {props.inputType !== 'NONE' && ( + + )} );