Skip to content

Commit

Permalink
Merge pull request #18 from SailingSteve/steveStaffClientJan24=8pm
Browse files Browse the repository at this point in the history
Questionnnaire Details working again in the new way in AnswerQuestionsForm
  • Loading branch information
DaleMcGrew authored Jan 25, 2025
2 parents d07dbaf + d6c26e6 commit a9b361f
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 126 deletions.
6 changes: 5 additions & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { normalizedHref } from './js/common/utils/hrefUtils';
import initializejQuery from './js/common/utils/initializejQuery';
import { renderLog } from './js/common/utils/logging';
import Drawers from './js/components/Drawers/Drawers';
import webAppConfig from './js/config';
import ConnectAppContext from './js/contexts/ConnectAppContext';
import Login from './js/pages/Login';

Expand All @@ -34,6 +35,7 @@ const Teams = React.lazy(() => import(/* webpackChunkName: 'Teams' */ './js/page
function App () {
renderLog('App');
const [hideHeader] = useState(false);
const [showDevtools] = useState(webAppConfig.ENABLE_REACT_QUERY_TOOLS !== undefined ? webAppConfig.ENABLE_REACT_QUERY_TOOLS : true);


// Inject this once for the app, for all react-query queries
Expand Down Expand Up @@ -88,7 +90,9 @@ function App () {
<Route path="*" element={<PageNotFound />} />
</Routes>
{/* Hack 1/14/25 <Footer /> */}
<ReactQueryDevtools />
{showDevtools && (
<ReactQueryDevtools />
)}
</WeVoteBody>
</BrowserRouter>
</ThemeProvider>
Expand Down
3 changes: 3 additions & 0 deletions src/js/components/Questionnaire/EditQuestionForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ const EditQuestionForm = ({ classes }) => {

const handleRadioChange = (event) => {
setRadioValue(event.target.value);
if (!saveButtonActive) {
setSaveButtonActive(true);
}
};

return (
Expand Down
30 changes: 6 additions & 24 deletions src/js/components/Questionnaire/QuestionnaireResponsesList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,17 @@ const QuestionnaireResponsesList = ({ personId }) => {
// Although we are sending a list, there will only be one person id, if there were more, just append them with commas
const requestParams = `personIdList[]=${person.id}`;

const { data: dataQRS, isSuccess: isSuccessQRS, isFetching: isFetchingQRS } = useFetchData(['questionnaire-responses-list-retrieve'], requestParams);
if (isFetchingQRS) {
const { data: dataQRL, isSuccess: isSuccessQRL, isFetching: isFetchingQRL } = useFetchData(['questionnaire-responses-list-retrieve'], requestParams);
if (isFetchingQRL) {
console.log('isFetching ------------ \'questionnaire-responses-list-retrieve\'');
}
useEffect(() => {
if (dataQRS !== undefined && isFetchingQRS === false && person) {
console.log('useFetchData in QuestionnaireResponsesList useEffect dataQRS is good:', dataQRS, isSuccessQRS, isFetchingQRS);
if (dataQRL !== undefined && isFetchingQRL === false && person) {
console.log('useFetchData in QuestionnaireResponsesList useEffect dataQRL is good:', dataQRL, isSuccessQRL, isFetchingQRL);
console.log('Successfully retrieved QuestionnaireResponsesList...');

// TODO: 1/20/25 is this questionList or questionnaireList?
// It seems like an answered questionnaire question should be a questionAnswerList, but questionnaire and question seem tyo be used inconsistently
// So this is hard to figure out without having some "answers" data

// const questionnaireListTempModified = [];
// for (let i = 0; i < questionnaireListTemp.length; i++) {
// const questionnaire = questionnaireListTemp[i];
// if (dateQuestionnairesCompletedDictTemp[questionnaire.questionnaireId]) {
// questionnaire.dateQuestionnaireCompleted = new Date(dateQuestionnairesCompletedDictTemp[questionnaire.questionnaireId]);
// } else {
// questionnaire.dateQuestionnaireCompleted = null;
// }
// // console.log('QuestionnaireList questionnaire:', questionnaire);
// questionnaireListTempModified[i] = questionnaire;
// }
// setQuestionnaireList(questionnaireListTempModified);

setQuestionnaireList(dataQRS.questionnaireList);
setQuestionnaireList(dataQRL.questionnaireList);
}
}, [dataQRS, isFetchingQRS, person]);
}, [dataQRL, isFetchingQRL, person]);

return (
<div>
Expand Down
14 changes: 1 addition & 13 deletions src/js/components/Task/EditTaskDefinitionDrawerMainContent.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
import React from 'react';
import styled from 'styled-components';
import { withStyles } from '@mui/styles';
import PersonActions from '../../actions/PersonActions';
import apiCalming from '../../common/utils/apiCalming';
import { renderLog } from '../../common/utils/logging';
import EditTaskDefinitionForm from './EditTaskDefinitionForm';


const EditTaskDefinitionDrawerMainContent = () => {
renderLog('EditTaskDefinitionDrawerMainContent'); // Set LOG_RENDER_EVENTS to log all renders

React.useEffect(() => {
if (apiCalming('personListRetrieve', 30000)) {
PersonActions.personListRetrieve();
}
}, []);

return (
<EditTaskDefinitionDrawerMainContentWrapper>
<AddTaskDefinitionWrapper>
Expand All @@ -25,14 +16,11 @@ const EditTaskDefinitionDrawerMainContent = () => {
);
};

const styles = () => ({
});

const EditTaskDefinitionDrawerMainContentWrapper = styled('div')`
`;

const AddTaskDefinitionWrapper = styled('div')`
margin-top: 32px;
`;

export default withStyles(styles)(EditTaskDefinitionDrawerMainContent);
export default EditTaskDefinitionDrawerMainContent;
8 changes: 0 additions & 8 deletions src/js/components/Task/EditTaskGroupDrawerMainContent.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
import React from 'react';
import styled from 'styled-components';
import { withStyles } from '@mui/styles';
import PersonActions from '../../actions/PersonActions';
import apiCalming from '../../common/utils/apiCalming';
import { renderLog } from '../../common/utils/logging';
import EditTaskGroupForm from './EditTaskGroupForm';


const EditTaskGroupDrawerMainContent = () => {
renderLog('EditTaskGroupDrawerMainContent'); // Set LOG_RENDER_EVENTS to log all renders

React.useEffect(() => {
if (apiCalming('personListRetrieve', 30000)) {
PersonActions.personListRetrieve();
}
}, []);

return (
<EditTaskGroupDrawerMainContentWrapper>
<AddTaskGroupWrapper>
Expand Down
5 changes: 3 additions & 2 deletions src/js/config-template.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ module.exports = {
LOG_ONLY_FIRST_RENDER_EVENTS: false,
LOG_HTTP_REQUESTS: false,
LOG_ROUTING: false,
LOG_SIGNIN_STEPS: false, // oAuthLog function prints to console
LOG_SIGNIN_STEPS: false, // oAuthLog function prints to console
LOG_CORDOVA_OFFSETS: false,
SHOW_CORDOVA_URL_FIELD: false, // Only needed for debugging in Cordova
SHOW_CORDOVA_URL_FIELD: false, // Only needed for debugging in Cordova
ENABLE_REACT_QUERY_TOOLS: false, // Show ReactQueryDevtools icon/console

// Use 1 or 0 as opposed to true or false
test: {
Expand Down
188 changes: 111 additions & 77 deletions src/js/pages/AnswerQuestionsForm.jsx
Original file line number Diff line number Diff line change
@@ -1,88 +1,120 @@
import { Button, FormControl, TextField } from '@mui/material';
import { withStyles } from '@mui/styles';
import PropTypes from 'prop-types';
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import { useParams } from 'react-router';
import styled from 'styled-components';
import QuestionnaireActions from '../actions/QuestionnaireActions';
import DesignTokenColors from '../common/components/Style/DesignTokenColors';
import convertToInteger from '../common/utils/convertToInteger';
import { renderLog } from '../common/utils/logging';
import { PageContentContainer } from '../components/Style/pageLayoutStyles';
import webAppConfig from '../config';
import makeRequestParams from '../react-query/makeRequestParams';
import { useQuestionnaireAnswersSaveMutation } from '../react-query/mutations';
import { useFetchData } from '../react-query/WeConnectQuery';


// eslint-disable-next-line no-unused-vars
const AnswerQuestionsForm = ({ classes, match }) => {
renderLog('AnswerQuestionsForm'); // Set LOG_RENDER_EVENTS to log all renders
const [questionList] = useState([]);
const [questionnaire] = useState({});
// const [questionnaireCount, setQuestionnaireCount] = useState(0);
// const [questionnaireId, setQuestionnaireId] = useState(-1);
const { mutate } = useQuestionnaireAnswersSaveMutation();
const params = useParams();

const [questionnaireId] = useState(params.questionnaireId);
const [personId] = useState(params.personId);
const [questionList, setQuestionList] = useState(undefined);
const [questionnaireList, setQuestionnaireList] = useState(undefined);
const [questionnaire, setQuestionnaire] = useState(undefined);
const [questionAnswerList, setQuestionAnswerList] = useState(undefined);
const [saveButtonActive, setSaveButtonActive] = useState(false);
const [inputValues, setInputValues] = useState({});

//
// const onQuestionnaireStoreChange = () => {
// const { params } = match;
// const questionnaireIdTemp = convertToInteger(params.questionnaireId);
// const questionnaireTemp = QuestionnaireStore.getQuestionnaireById(questionnaireIdTemp);
// setQuestionnaire(questionnaireTemp);
// const questionListTemp = QuestionnaireStore.getQuestionListByQuestionnaireId(questionnaireIdTemp);
// // console.log('AnswerQuestionsForm QuestionnaireStore.getQuestionList:', questionListTemp);
// setQuestionList(questionListTemp);
// setQuestionnaireCount(questionListTemp.length);
// };

const updateQuestionAnswer = (event) => {
// The input name must match the person field being updated
if (event.target.name) {
const newValue = event.target.value || '';
// console.log('updateQuestionAnswer:', event.target.name, ', newValue:', newValue);
setInputValues({ ...inputValues, [event.target.name]: newValue });
setSaveButtonActive(true);
} else {
console.error('updateQuestionAnswer Invalid event:', event);
const [errorMessage, setErrorMessage] = useState(undefined);

const requestParams = `personIdList[]=${personId}&questionnaireId=${questionnaireId}`;
const { data: dataQRL, isSuccess: isSuccessQRL, isFetching: isFetchingQRL } = useFetchData(['questionnaire-responses-list-retrieve'], requestParams);
if (isFetchingQRL) {
console.log('isFetching ------------ \'questionnaire-responses-list-retrieve\'');
}

useEffect(() => {
if (dataQRL !== undefined && isFetchingQRL === false && personId) {
// console.log('useFetchData in AnswerQuestionsForm useEffect dataQRL is good:', dataQRL, isSuccessQRL, isFetchingQRL);
// console.log('Successfully retrieved QuestionnaireResponsesList...');
setQuestionnaireList(dataQRL.questionnaireList);
if (questionnaireList && questionnaireList.length) {
setQuestionnaire(questionnaireList[questionnaireId]);
}
setQuestionAnswerList(dataQRL.questionAnswerList);
setQuestionList(dataQRL.questionList);
}
}, [dataQRL, isFetchingQRL, isSuccessQRL, personId]);

const updateQuestionAnswer = (questionId) => {
// eslint-disable-next-line no-restricted-globals
const newValue = event.target.value;
setInputValues({ ...inputValues, [questionId]: newValue });
setSaveButtonActive(true);
};

const saveAnswers = () => {
const { params } = match;
const personIdTemp = convertToInteger(params.personId);
const questionnaireIdTemp = convertToInteger(params.questionnaireId);
let foundError = false;
Object.keys(inputValues).forEach((key) => {
const cleanKey = parseInt(key.match(/\d+/g));
const question = questionList.find((q) => q.questionId === cleanKey);
if (question.answerType === 'BOOLEAN') {
const boolAnswers = ['t', 'f', 'true', 'false', '1', '0'];
if (boolAnswers.includes(inputValues[key])) {
setErrorMessage(`"${question.questionText}" requires a boolean answer ('true' or 't' or 'false' or 'f')`);
setSaveButtonActive(false);
foundError = true;
}
} else if (question.answerType === 'INTEGER') {
// eslint-disable-next-line no-restricted-globals
if (isNaN(inputValues[key])) {
setErrorMessage(`"${question.questionText}" requires a numeric answer`);
setSaveButtonActive(false);
foundError = true;
}
}
});
if (!foundError) {
setErrorMessage(undefined);
}

console.log('saveAnswers inputValues:', inputValues);
const data = { ...inputValues };
const requestParams2 = makeRequestParams({
questionnaireId,
personId,
...inputValues,
}, {});

mutate(requestParams2);
// console.log('saveAnswers data:', data);
QuestionnaireActions.questionnaireAnswerListSave(questionnaireIdTemp, personIdTemp, data);
setSaveButtonActive(false);
};

// React.useEffect(() => {
// const { params } = match;
// const questionnaireIdTemp = convertToInteger(params.questionnaireId);
//
// // const appStateSubscription = messageService.getMessage().subscribe(() => onAppObservableStoreChange());
// // onAppObservableStoreChange();
// // const questionnaireStoreListener = QuestionnaireStore.addListener(onQuestionnaireStoreChange);
// // onQuestionnaireStoreChange();
//
// if (questionnaireIdTemp >= 0) {
// if (apiCalming('questionnaireListRetrieve', 10000)) {
// QuestionnaireActions.questionnaireListRetrieve();
// }
// if (apiCalming(`questionListRetrieve-${questionnaireIdTemp}`, 10000)) {
// QuestionnaireActions.questionListRetrieve(questionnaireIdTemp);
// }
// }
//
// return () => {
// // appStateSubscription.unsubscribe();
// // questionnaireStoreListener.remove();
// };
// }, []);

// const { params } = match;
// const questionnaireIdTemp = convertToInteger(params.questionnaireId);
const getInitialAnswer = (questionId) => {
if (!questionAnswerList || questionAnswerList.length === 0) {
console.log(questionId, 'n/a');
return '';
}
const answer = questionAnswerList.filter((answerIteration) => answerIteration.questionId === questionId);
let initVal = '';
if (answer.length) {
switch (answer[0].answerType) {
case 'BOOLEAN':
initVal = answer.length ? answer[0].answerBoolean : '';
break;
case 'INTEGER':
initVal = answer.length ? answer[0].answerInteger : '';
break;
default:
case 'STRING':
initVal = answer.length ? answer[0].answerString : '';
break;
}
}
return initVal;
};

return (
<div>
Expand All @@ -95,18 +127,14 @@ const AnswerQuestionsForm = ({ classes, match }) => {
<meta name="robots" content="noindex" data-react-helmet="true" />
</Helmet>
<PageContentContainer>
{questionnaire.questionnaireTitle && (
<TitleWrapper>
{questionnaire.questionnaireTitle}
</TitleWrapper>
)}
{questionnaire.questionnaireInstructions && (
<InstructionsWrapper>
{questionnaire.questionnaireInstructions}
</InstructionsWrapper>
)}
<TitleWrapper>
{questionnaire && questionnaire.questionnaireTitle}
</TitleWrapper>
<InstructionsWrapper>
{questionnaire && questionnaire.questionnaireInstructions}
</InstructionsWrapper>
<FormControl classes={{ root: classes.formControl }}>
{questionList.map((question) => (
{questionList && questionList.map((question) => (
<OneQuestionWrapper key={`questionnaire-${question.id}`}>
<QuestionText>
{question.questionText}
Expand All @@ -120,18 +148,18 @@ const AnswerQuestionsForm = ({ classes, match }) => {
<QuestionFormWrapper>
<TextField
classes={(question.answerType === 'INTEGER') ? {} : { root: classes.formControl }}
defaultValue={getInitialAnswer(question.id)}
id={`questionAnswerToBeSaved-${question.id}`}
// label={`${question.id}`}
name={`questionAnswer-${question.id}`}
label={`${question.answerType}`}
margin="dense"
name={`questionAnswer-${question.id}`}
onChange={() => updateQuestionAnswer(`questionAnswer-${question.id}`)}
variant="outlined"
placeholder={question.questionPlaceholder || ''}
value={inputValues[`questionAnswer-${question.id}`] || ''}
onChange={updateQuestionAnswer}
/>
</QuestionFormWrapper>
</OneQuestionWrapper>
))}
<ErrorLine>{errorMessage}</ErrorLine>
<SaveButtonWrapper>
<Button
classes={{ root: classes.saveAnswersButton }}
Expand Down Expand Up @@ -198,6 +226,12 @@ const SaveButtonWrapper = styled('div')`
margin-top: 24px;
`;

const ErrorLine = styled('div')`
margin-top: 24px;
font-weight: 500;
color: red;
`;

const TitleWrapper = styled('h1')`
margin-bottom: 8px;
`;
Expand Down
Loading

0 comments on commit a9b361f

Please sign in to comment.