From 1919d5d2bd8adecc06bc0915c9ff37401ab48ea3 Mon Sep 17 00:00:00 2001 From: dalemcgrew Date: Mon, 30 Dec 2024 19:40:23 -0800 Subject: [PATCH] Adding ability to see QuestionAnswers. --- src/App.jsx | 4 +- src/js/actions/QuestionnaireActions.js | 11 + src/js/components/Person/PersonProfile.jsx | 2 +- .../Person/PersonProfileDrawerMainContent.jsx | 2 + .../Questionnaire/CopyQuestionnaireLink.jsx | 44 ---- .../QuestionnaireResponsesList.jsx | 120 +++++++++++ src/js/components/Team/TeamHeader.jsx | 2 +- src/js/pages/QuestionnaireAnswers.jsx | 201 ++++++++++++++++++ src/js/stores/PersonStore.js | 24 +++ src/js/stores/QuestionnaireStore.js | 145 ++++++++++++- 10 files changed, 505 insertions(+), 50 deletions(-) create mode 100644 src/js/components/Questionnaire/QuestionnaireResponsesList.jsx create mode 100644 src/js/pages/QuestionnaireAnswers.jsx diff --git a/src/App.jsx b/src/App.jsx index ad47d2b..96d6be8 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -26,12 +26,13 @@ import { PrivateRoute } from './js/auth'; // Root URL pages +const AnswerQuestionsForm = React.lazy(() => import(/* webpackChunkName: 'AnswerQuestionsForm' */ './js/pages/AnswerQuestionsForm')); const Drawers = React.lazy(() => import(/* webpackChunkName: 'Drawers' */ './js/components/Drawers/Drawers')); const FAQ = React.lazy(() => import(/* webpackChunkName: 'FAQ' */ './js/pages/FAQ')); const Footer = React.lazy(() => import(/* webpackChunkName: 'Footer' */ './js/components/Navigation/Footer')); const Header = React.lazy(() => import(/* webpackChunkName: 'Header' */ './js/components/Navigation/Header')); const PageNotFound = React.lazy(() => import(/* webpackChunkName: 'PageNotFound' */ './js/pages/PageNotFound')); -const AnswerQuestionsForm = React.lazy(() => import(/* webpackChunkName: 'AnswerQuestionsForm' */ './js/pages/AnswerQuestionsForm')); +const QuestionnaireAnswers = React.lazy(() => import(/* webpackChunkName: 'QuestionnaireAnswers' */ './js/pages/QuestionnaireAnswers')); const QuestionnaireQuestionList = React.lazy(() => import(/* webpackChunkName: 'QuestionnaireQuestionList' */ './js/pages/SystemSettings/Questionnaire')); const SystemSettings = React.lazy(() => import(/* webpackChunkName: 'SystemSettings' */ './js/pages/SystemSettings/SystemSettings')); const TeamMembers = React.lazy(() => import(/* webpackChunkName: 'TeamMembers' */ './js/pages/TeamHome')); @@ -277,6 +278,7 @@ class App extends Component { }> + diff --git a/src/js/actions/QuestionnaireActions.js b/src/js/actions/QuestionnaireActions.js index 81365dc..0120644 100644 --- a/src/js/actions/QuestionnaireActions.js +++ b/src/js/actions/QuestionnaireActions.js @@ -26,6 +26,17 @@ export default { } }, + questionnaireResponsesListRetrieve (personIdList = []) { + // console.log('QuestionnaireActions, questionnaireRetrieve personIdList:', personIdList); + if (personIdList) { + Dispatcher.loadEndpoint('questionnaire-responses-list-retrieve', { + personIdList, + }); + } else { + Dispatcher.loadEndpoint('questionnaire-responses-list-retrieve'); + } + }, + questionnaireRetrieve (questionnaireId = '') { // console.log('QuestionnaireActions, questionnaireRetrieve questionnaireId:', questionnaireId); if (questionnaireId) { diff --git a/src/js/components/Person/PersonProfile.jsx b/src/js/components/Person/PersonProfile.jsx index 6ef4383..1cf6fd2 100644 --- a/src/js/components/Person/PersonProfile.jsx +++ b/src/js/components/Person/PersonProfile.jsx @@ -23,7 +23,7 @@ const PersonProfile = ({ personId }) => { const onPersonStoreChange = () => { const personTemp = PersonStore.getPersonById(personId); - console.log('PersonProfile personId:', personId, ', personTemp:', personTemp); + // console.log('PersonProfile personId:', personId, ', personTemp:', personTemp); setPerson(personTemp); const fullNamePreferredTemp = PersonStore.getFullNamePreferred(personId); setFullNamePreferred(fullNamePreferredTemp); diff --git a/src/js/components/Person/PersonProfileDrawerMainContent.jsx b/src/js/components/Person/PersonProfileDrawerMainContent.jsx index 72ad460..f958824 100644 --- a/src/js/components/Person/PersonProfileDrawerMainContent.jsx +++ b/src/js/components/Person/PersonProfileDrawerMainContent.jsx @@ -9,6 +9,7 @@ import TeamStore from '../../stores/TeamStore'; import apiCalming from '../../common/utils/apiCalming'; import { renderLog } from '../../common/utils/logging'; import PersonProfile from './PersonProfile'; +import QuestionnaireResponsesList from '../Questionnaire/QuestionnaireResponsesList'; const PersonProfileDrawerMainContent = ({ classes }) => { // classes, teamId @@ -58,6 +59,7 @@ const PersonProfileDrawerMainContent = ({ classes }) => { // classes, teamId return ( + ); }; diff --git a/src/js/components/Questionnaire/CopyQuestionnaireLink.jsx b/src/js/components/Questionnaire/CopyQuestionnaireLink.jsx index 225fe83..6dcdbdf 100644 --- a/src/js/components/Questionnaire/CopyQuestionnaireLink.jsx +++ b/src/js/components/Questionnaire/CopyQuestionnaireLink.jsx @@ -3,41 +3,15 @@ import styled from 'styled-components'; import PropTypes from 'prop-types'; import CopyToClipboard from 'react-copy-to-clipboard'; import { withStyles } from '@mui/styles'; -import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; -import PersonActions from '../../actions/PersonActions'; -import PersonStore from '../../stores/PersonStore'; -import TeamStore from '../../stores/TeamStore'; import { SpanWithLinkStyle } from '../Style/linkStyles'; -import apiCalming from '../../common/utils/apiCalming'; import { renderLog } from '../../common/utils/logging'; import webAppConfig from '../../config'; const CopyQuestionnaireLink = ({ personId, questionnaireId }) => { renderLog('CopyQuestionnaireLink'); // Set LOG_RENDER_EVENTS to log all renders - const [fullNamePreferred, setFullNamePreferred] = React.useState(''); const [linkCopied, setLinkCopied] = React.useState(false); const [linkToBeShared, setLinkToBeShared] = React.useState(''); - const [person, setPerson] = React.useState({}); - - const onAppObservableStoreChange = () => { - // const teamIdTemp = AppObservableStore.getGlobalVariableState('personProfileDrawerTeamId'); - // console.log('CopyQuestionnaireLink AppObservableStore-personProfileDrawerTeamId: ', teamIdTemp); - }; - - const onPersonStoreChange = () => { - const personTemp = PersonStore.getPersonById(personId); - console.log('CopyQuestionnaireLink personId:', personId, ', personTemp:', personTemp); - setPerson(personTemp); - const fullNamePreferredTemp = PersonStore.getFullNamePreferred(personId); - setFullNamePreferred(fullNamePreferredTemp); - // console.log('CopyQuestionnaireLink-onPersonStoreChange personIdTemp: ', personIdTemp); - }; - - const onTeamStoreChange = () => { - // const teamIdTemp = AppObservableStore.getGlobalVariableState('personProfileDrawerTeamId'); - // console.log('CopyQuestionnaireLink-onTeamStoreChange teamIdTemp: ', teamIdTemp); - }; const copyLink = () => { // console.log('CopyQuestionnaireLink copyLink'); @@ -49,24 +23,10 @@ const CopyQuestionnaireLink = ({ personId, questionnaireId }) => { }; React.useEffect(() => { - const appStateSubscription = messageService.getMessage().subscribe(() => onAppObservableStoreChange()); - onAppObservableStoreChange(); - const personStoreListener = PersonStore.addListener(onPersonStoreChange); - onPersonStoreChange(); - const teamStoreListener = TeamStore.addListener(onTeamStoreChange); - onTeamStoreChange(); - - // const personIdTemp = AppObservableStore.getGlobalVariableState('personProfileDrawerPersonId'); - // if (apiCalming(`personRetrieve-${personIdTemp}`, 30000)) { - // PersonActions.personRetrieve(personIdTemp); - // } setLinkToBeShared(`${webAppConfig.PROTOCOL}${webAppConfig.HOSTNAME}/q/${questionnaireId}/${personId}`); return () => { // console.log('CopyQuestionnaireLink cleanup'); - appStateSubscription.unsubscribe(); - personStoreListener.remove(); - teamStoreListener.remove(); }; }, []); @@ -87,7 +47,6 @@ const CopyQuestionnaireLink = ({ personId, questionnaireId }) => { ); }; CopyQuestionnaireLink.propTypes = { - classes: PropTypes.object.isRequired, personId: PropTypes.number, questionnaireId: PropTypes.number, }; @@ -95,9 +54,6 @@ CopyQuestionnaireLink.propTypes = { const styles = () => ({ }); -const FullName = styled('div')` -`; - const CopyQuestionnaireLinkWrapper = styled('div')` `; diff --git a/src/js/components/Questionnaire/QuestionnaireResponsesList.jsx b/src/js/components/Questionnaire/QuestionnaireResponsesList.jsx new file mode 100644 index 0000000..5a5df62 --- /dev/null +++ b/src/js/components/Questionnaire/QuestionnaireResponsesList.jsx @@ -0,0 +1,120 @@ +import React, { Suspense } from 'react'; +import styled from 'styled-components'; +import PropTypes from 'prop-types'; +import { Launch } from '@mui/icons-material'; +import { Tooltip } from '@mui/material'; +import QuestionnaireActions from '../../actions/QuestionnaireActions'; +import QuestionnaireStore from '../../stores/QuestionnaireStore'; +import DesignTokenColors from '../../common/components/Style/DesignTokenColors'; +import apiCalming from '../../common/utils/apiCalming'; +import { renderLog } from '../../common/utils/logging'; +import CopyQuestionnaireLink from './CopyQuestionnaireLink'; +import webAppConfig from '../../config'; + +const OpenExternalWebSite = React.lazy(() => import(/* webpackChunkName: 'OpenExternalWebSite' */ '../../common/components/Widgets/OpenExternalWebSite')); + +const QuestionnaireResponsesList = ({ personId }) => { + renderLog('QuestionnaireList'); // Set LOG_RENDER_EVENTS to log all renders + const [questionnaireList, setQuestionnaireList] = React.useState([]); + + const onQuestionnaireStoreChange = () => { + const questionnaireListTemp = QuestionnaireStore.getQuestionnaireListByPersonId(personId); + // console.log('QuestionnaireList QuestionnaireStore.getQuestionnaireListByPersonId:', questionnaireListTemp); + const dateQuestionnairesCompletedDictTemp = QuestionnaireStore.getDateQuestionnairesCompletedDictByPersonId(personId); + 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); + }; + + React.useEffect(() => { + const questionnaireStoreListener = QuestionnaireStore.addListener(onQuestionnaireStoreChange); + onQuestionnaireStoreChange(); + + if (personId >= 0) { + const personIdList = [personId]; + if (apiCalming(`questionnaireResponsesListRetrieve-${personId}`, 10000)) { + QuestionnaireActions.questionnaireResponsesListRetrieve(personIdList); + } + } + + return () => { + questionnaireStoreListener.remove(); + }; + }, []); + + return ( +
+ {questionnaireList.length > 0 && ( + + Questionnaire Responses + {questionnaireList.map((questionnaire) => ( + + + {questionnaire.questionnaireName} + + + }> + + view + + + )} + /> + + {questionnaire.dateQuestionnaireCompleted && ( + + Completed on + {' '} + {questionnaire.dateQuestionnaireCompleted.toLocaleString('en-US', {})} + + )} + + ))} + + )} +
+ ); +}; +QuestionnaireResponsesList.propTypes = { + personId: PropTypes.number, +}; + +const LaunchStyled = styled(Launch)` + height: 14px; + margin-left: 2px; + margin-top: -3px; + width: 14px; +`; + +const WhenCompleted = styled('div')` + color: ${DesignTokenColors.neutralUI300}; + font-size: .9em; +`; + +const OneQuestionnaireWrapper = styled('div')` + font-weight: 550; + margin-top: 6px; +`; + +const QuestionText = styled('div')` +`; + +const QuestionnaireListWrapper = styled('div')` + margin-top: 30px; +`; + +export default QuestionnaireResponsesList; diff --git a/src/js/components/Team/TeamHeader.jsx b/src/js/components/Team/TeamHeader.jsx index 0f6fb76..6d3477a 100644 --- a/src/js/components/Team/TeamHeader.jsx +++ b/src/js/components/Team/TeamHeader.jsx @@ -38,7 +38,7 @@ const TeamHeader = ({ classes, showHeaderLabels, team }) => { TeamHeader.propTypes = { classes: PropTypes.object.isRequired, showHeaderLabels: PropTypes.bool, - team: PropTypes.object.isRequired, + team: PropTypes.object, }; const styles = (theme) => ({ diff --git a/src/js/pages/QuestionnaireAnswers.jsx b/src/js/pages/QuestionnaireAnswers.jsx new file mode 100644 index 0000000..cb920e9 --- /dev/null +++ b/src/js/pages/QuestionnaireAnswers.jsx @@ -0,0 +1,201 @@ +import { FormControl, TextField } from '@mui/material'; +import React from 'react'; +import { Helmet } from 'react-helmet-async'; +import styled from 'styled-components'; +import PropTypes from 'prop-types'; +import { withStyles } from '@mui/styles'; +import PersonActions from '../actions/PersonActions'; +import PersonStore from '../stores/PersonStore'; +import QuestionnaireActions from '../actions/QuestionnaireActions'; +import QuestionnaireStore from '../stores/QuestionnaireStore'; +import { PageContentContainer } from '../components/Style/pageLayoutStyles'; +import webAppConfig from '../config'; +import DesignTokenColors from '../common/components/Style/DesignTokenColors'; +import apiCalming from '../common/utils/apiCalming'; +import { renderLog } from '../common/utils/logging'; +import convertToInteger from '../common/utils/convertToInteger'; + + +const QuestionnaireAnswers = ({ classes, match }) => { + renderLog('QuestionnaireAnswers'); // Set LOG_RENDER_EVENTS to log all renders + const [allCachedAnswersDict, setAllCachedAnswersDict] = React.useState({}); + const [fullNamePreferred, setFullNamePreferred] = React.useState(''); + const [questionList, setQuestionList] = React.useState([]); + const [questionnaire, setQuestionnaire] = React.useState({}); + + const onPersonStoreChange = () => { + const { params } = match; + const personIdTemp = convertToInteger(params.personId); + const fullNamePreferredTemp = PersonStore.getFullNamePreferred(personIdTemp); + setFullNamePreferred(fullNamePreferredTemp); + // console.log('QuestionnaireAnswers-onPersonStoreChange personIdTemp: ', personIdTemp, ', fullNamePreferredTemp:', fullNamePreferredTemp); + }; + + const onQuestionnaireStoreChange = () => { + const { params } = match; + const personIdTemp = convertToInteger(params.personId); + const questionnaireIdTemp = convertToInteger(params.questionnaireId); + const questionnaireTemp = QuestionnaireStore.getQuestionnaireById(questionnaireIdTemp); + setQuestionnaire(questionnaireTemp); + const questionListTemp = QuestionnaireStore.getQuestionListByQuestionnaireId(questionnaireIdTemp); + // console.log('QuestionnaireAnswers QuestionnaireStore.getQuestionList:', questionListTemp); + setQuestionList(questionListTemp); + const allCachedAnswersDictTemp = QuestionnaireStore.getAllCachedAnswersDictByPersonId(personIdTemp); + setAllCachedAnswersDict(allCachedAnswersDictTemp); + }; + + const getAnswerValue = (questionId) => { + if (allCachedAnswersDict && allCachedAnswersDict[questionId]) { + const questionAnswer = allCachedAnswersDict[questionId]; + if (questionAnswer.answerType === 'BOOLEAN') { + return questionAnswer.answerBoolean; + } else if (questionAnswer.answerType === 'INTEGER') { + return questionAnswer.answerInteger || 0; + } else if (questionAnswer.answerType === 'STRING') { + return questionAnswer.answerString || ''; + } + return ''; + } + return ''; + }; + + React.useEffect(() => { + const { params } = match; + const personIdTemp = convertToInteger(params.personId); + const questionnaireIdTemp = convertToInteger(params.questionnaireId); + + const personStoreListener = PersonStore.addListener(onPersonStoreChange); + onPersonStoreChange(); + const questionnaireStoreListener = QuestionnaireStore.addListener(onQuestionnaireStoreChange); + onQuestionnaireStoreChange(); + + if (questionnaireIdTemp >= 0) { + if (apiCalming('questionnaireListRetrieve', 10000)) { + QuestionnaireActions.questionnaireListRetrieve(); + } + if (apiCalming(`questionListRetrieve-${questionnaireIdTemp}`, 10000)) { + QuestionnaireActions.questionListRetrieve(questionnaireIdTemp); + } + } + if (personIdTemp >= 0) { + if (apiCalming(`personRetrieve-${personIdTemp}`, 30000)) { + PersonActions.personRetrieve(personIdTemp); + } + const personIdList = [personIdTemp]; + if (apiCalming(`questionnaireResponsesListRetrieve-${personIdTemp}`, 10000)) { + QuestionnaireActions.questionnaireResponsesListRetrieve(personIdList); + } + } + + return () => { + personStoreListener.remove(); + questionnaireStoreListener.remove(); + }; + }, []); + + return ( +
+ + + Questionnaire Answers - + {' '} + {webAppConfig.NAME_FOR_BROWSER_TAB_TITLE} + + + + + {questionnaire.questionnaireName && ( + + {questionnaire.questionnaireName} + + )} + + Answered by: + {' '} + {fullNamePreferred} + + + {questionList.map((question) => ( + + + {question.questionText} + {question.requireAnswer && *} + + {question.questionInstructions && ( + + {question.questionInstructions} + + )} + + + + + ))} + + +
+ ); +}; +QuestionnaireAnswers.propTypes = { + classes: PropTypes.object.isRequired, + match: PropTypes.object.isRequired, +}; + +const styles = (theme) => ({ + ballotButtonIconRoot: { + marginRight: 8, + }, + formControl: { + width: '100%', + }, + saveAnswersButton: { + width: 300, + [theme.breakpoints.down('md')]: { + width: '100%', + }, + }, +}); + +const AnsweredBy = styled('div')` + font-size: 1.3em; + font-weight: 300; +`; + +const AnsweredBySpan = styled('span')` + font-weight: bold; +`; + +const OneQuestionWrapper = styled('div')` + border-top: 1px solid ${DesignTokenColors.neutralUI200}; + margin-top: 24px; +`; + +const QuestionInstructions = styled('div')` + color: ${DesignTokenColors.neutralUI300}; +`; + +const QuestionFormWrapper = styled('div')` + width: 100%; +`; + +const QuestionText = styled('div')` +`; + +const RequiredStar = styled('span')` + color: ${DesignTokenColors.alert800}; + font-weight: bold; +`; + +const TitleWrapper = styled('h1')` + margin-bottom: 8px; +`; + +export default withStyles(styles)(QuestionnaireAnswers); diff --git a/src/js/stores/PersonStore.js b/src/js/stores/PersonStore.js index 81d9a7d..4251732 100644 --- a/src/js/stores/PersonStore.js +++ b/src/js/stores/PersonStore.js @@ -177,6 +177,30 @@ class PersonStore extends ReduceStore { // console.log('PersonStore revisedState:', revisedState); return revisedState; + case 'person-retrieve': + if (!action.res.success) { + console.log('PersonStore ', action.type, ' FAILED action.res:', action.res); + return state; + } + revisedState = state; + if (action.res.personId >= 0) { + personId = action.res.personId; + } else { + personId = -1; + } + + if (personId >= 0) { + // console.log('PersonStore person-save personId:', personId); + allCachedPeopleDict[personId] = action.res; + revisedState = { + ...revisedState, + allCachedPeopleDict, + }; + } else { + console.log('PersonStore person-retrieve MISSING personId:', personId); + } + return revisedState; + case 'person-save': if (!action.res.success) { console.log('PersonStore ', action.type, ' FAILED action.res:', action.res); diff --git a/src/js/stores/QuestionnaireStore.js b/src/js/stores/QuestionnaireStore.js index 99938de..874f207 100644 --- a/src/js/stores/QuestionnaireStore.js +++ b/src/js/stores/QuestionnaireStore.js @@ -1,11 +1,14 @@ import { ReduceStore } from 'flux/utils'; import Dispatcher from '../common/dispatcher/Dispatcher'; +import arrayContains from '../common/utils/arrayContains'; class QuestionnaireStore extends ReduceStore { getInitialState () { return { allCachedQuestionnairesDict: {}, // This is a dictionary key: questionnaireId, value: questionnaire dict allCachedQuestionsDict: {}, // This is a dictionary key: questionId, value: question dict + allCachedAnswersDict: {}, // This is a dictionary key: personId, value: another dictionary key: questionId, value: answer dict + dateQuestionnaireCompletedDict: {}, // This is a dictionary key: personId, value: another dictionary key: questionnaireId, value: dateQuestionnaireCompleted mostRecentQuestionIdSaved: -1, mostRecentQuestionSaved: { questionnaireId: -1, @@ -16,10 +19,22 @@ class QuestionnaireStore extends ReduceStore { lastName: '', questionnaireId: -1, }, + questionsAnsweredPersonIdList: {}, // This is a dictionary key: questionId, value: list of personIds who have answered the question + questionnairesAnsweredByPersonList: {}, // This is a dictionary key: questionnaireId, value: list of personIds who have answered the questionnaire + questionnairesAnsweredListByPersonId: {}, // This is a dictionary key: personId, value: list of questionnaireIds the person has answered searchResults: [], }; } + getAllCachedAnswersDictByPersonId (personId) { + // This lets us know when the person answered the questionnaire + const { allCachedAnswersDict } = this.getState(); + if (allCachedAnswersDict[personId]) { + return allCachedAnswersDict[personId]; + } + return {}; + } + getAllCachedQuestionnairesList () { const { allCachedQuestionnairesDict } = this.getState(); const questionnaireListRaw = Object.values(allCachedQuestionnairesDict); @@ -36,6 +51,15 @@ class QuestionnaireStore extends ReduceStore { return questionnaireList; } + getDateQuestionnairesCompletedDictByPersonId (personId) { + // This lets us know when the person answered the questionnaire + const { dateQuestionnaireCompletedDict } = this.getState(); + if (dateQuestionnaireCompletedDict[personId]) { + return dateQuestionnaireCompletedDict[personId]; + } + return {}; + } + getFirstName (questionnaireId) { const questionnaire = this.getQuestionnaireById(questionnaireId); return questionnaire.firstName || ''; @@ -84,13 +108,28 @@ class QuestionnaireStore extends ReduceStore { return allCachedQuestionnairesDict[questionnaireId] || {}; } + getQuestionnaireListByPersonId (personId) { + const { questionnairesAnsweredListByPersonId } = this.getState(); + // console.log('QuestionnaireStore getQuestionnaireById:', questionnaireId, ', allCachedQuestionnairesDict:', allCachedQuestionnairesDict); + const questionnairesAnsweredIdList = questionnairesAnsweredListByPersonId[personId] || []; + const questionnairesAnsweredListForPerson = []; + for (let i = 0; i < questionnairesAnsweredIdList.length; i++) { + questionnairesAnsweredListForPerson.push(this.getQuestionnaireById(questionnairesAnsweredIdList[i])); + } + return questionnairesAnsweredListForPerson; + } + getSearchResults () { // console.log('QuestionnaireStore getSearchResults:', this.getState().searchResults); return this.getState().searchResults || []; } reduce (state, action) { - const { allCachedQuestionsDict, allCachedQuestionnairesDict } = state; + const { + allCachedAnswersDict, allCachedQuestionsDict, allCachedQuestionnairesDict, + dateQuestionnaireCompletedDict, + questionnairesAnsweredByPersonList, questionnairesAnsweredListByPersonId, questionsAnsweredPersonIdList, + } = state; // let questionnaireTemp = {}; let questionId = -1; let questionnaireId = -1; @@ -116,7 +155,7 @@ class QuestionnaireStore extends ReduceStore { } if (action.res.questionList) { action.res.questionList.forEach((question) => { - // console.log('QuestionnaireStore team-retrieve adding question:', question); + // console.log('QuestionnaireStore question-list-retrieve adding question:', question); if (question && (question.id >= 0)) { allCachedQuestionsDict[question.id] = question; } @@ -159,6 +198,106 @@ class QuestionnaireStore extends ReduceStore { } return revisedState; + case 'questionnaire-responses-list-retrieve': + if (!action.res.success) { + console.log('QuestionnaireStore ', action.type, ' FAILED action.res:', action.res); + return state; + } + revisedState = state; + // questionnairesAnsweredByPersonList: {}, // This is a dictionary key: questionnaireId, value: list of personIds who have answered the questionnaire + // questionnairesAnsweredListByPersonId: {}, // This is a dictionary key: personId, value: list of questionnaireIds answered + // questionsAnsweredPersonIdList: {}, // This is a dictionary key: questionId, value: list of personIds who have answered the question + if (action.res.questionAnswerList) { + action.res.questionAnswerList.forEach((answer) => { + // console.log('QuestionnaireStore questionnaire-responses-list-retrieve adding answer:', answer); + if (answer && (answer.personId >= 0)) { + if (answer.questionId >= 0) { + if (!allCachedAnswersDict[answer.personId]) { + allCachedAnswersDict[answer.personId] = {}; + } + allCachedAnswersDict[answer.personId][answer.questionId] = answer; + // + // Add personId to questionnairesAnsweredByPersonList + if (!Array.isArray(questionnairesAnsweredByPersonList[answer.questionnaireId])) { + // Create if needed + questionnairesAnsweredByPersonList[answer.questionnaireId] = []; + } + if (!arrayContains(answer.personId, questionnairesAnsweredByPersonList[answer.questionnaireId])) { + // Add + questionnairesAnsweredByPersonList[answer.questionnaireId].push(answer.personId); + } + // + // This lets us know when the person answered the questionnaire + if (!dateQuestionnaireCompletedDict[answer.personId]) { + // Create if needed + dateQuestionnaireCompletedDict[answer.personId] = {}; + } + if (!dateQuestionnaireCompletedDict[answer.personId][answer.questionnaireId] && answer.dateCreated) { + // Just use any of the answers to set the dateQuestionnaireCompletedDict + dateQuestionnaireCompletedDict[answer.personId][answer.questionnaireId] = answer.dateCreated; + } + // + // Add personId to questionnairesAnsweredByPersonList + if (!Array.isArray(questionnairesAnsweredListByPersonId[answer.personId])) { + // Create if needed + questionnairesAnsweredListByPersonId[answer.personId] = []; + } + if (!arrayContains(answer.questionnaireId, questionnairesAnsweredListByPersonId[answer.personId])) { + // Add + questionnairesAnsweredListByPersonId[answer.personId].push(answer.questionnaireId); + } + // + // Add personId to questionsAnsweredPersonIdList + if (!Array.isArray(questionsAnsweredPersonIdList[answer.questionId])) { + // Create if needed + questionsAnsweredPersonIdList[answer.questionId] = []; + } + if (!arrayContains(answer.personId, questionsAnsweredPersonIdList[answer.questionId])) { + // Add + questionsAnsweredPersonIdList[answer.questionId].push(answer.personId); + } + } + } + }); + // console.log('allCachedAnswersDict:', allCachedAnswersDict); + revisedState = { + ...revisedState, + allCachedAnswersDict, + questionnairesAnsweredByPersonList, + questionnairesAnsweredListByPersonId, + questionsAnsweredPersonIdList, + }; + } + if (action.res.questionList) { + action.res.questionList.forEach((question) => { + // console.log('QuestionnaireStore questionnaire-responses-list-retrieve adding question:', question); + if (question && (question.id >= 0)) { + allCachedQuestionsDict[question.id] = question; + } + }); + // console.log('allCachedQuestionsDict:', allCachedQuestionsDict); + revisedState = { + ...revisedState, + allCachedQuestionsDict, + }; + } + // console.log('QuestionnaireStore questionnaire-responses-list-retrieve questionnaireList:', action.res.questionnaireList); + if (action.res.questionnaireList) { + action.res.questionnaireList.forEach((questionnaire) => { + // console.log('QuestionnaireStore questionnaire-responses-list-retrieve adding questionnaire:', questionnaire); + if (questionnaire && (questionnaire.id >= 0)) { + allCachedQuestionnairesDict[questionnaire.id] = questionnaire; + } + }); + // console.log('allCachedQuestionnairesDict:', allCachedQuestionnairesDict); + revisedState = { + ...revisedState, + allCachedQuestionnairesDict, + }; + } + // console.log('QuestionnaireStore revisedState:', revisedState); + return revisedState; + case 'questionnaire-list-retrieve': if (!action.res.success) { console.log('QuestionnaireStore ', action.type, ' FAILED action.res:', action.res); @@ -177,7 +316,7 @@ class QuestionnaireStore extends ReduceStore { } if (action.res.questionnaireList) { action.res.questionnaireList.forEach((questionnaire) => { - // console.log('QuestionnaireStore team-retrieve adding questionnaire:', questionnaire); + // console.log('QuestionnaireStore questionnaire-list-retrieve adding questionnaire:', questionnaire); if (questionnaire && (questionnaire.id >= 0)) { allCachedQuestionnairesDict[questionnaire.id] = questionnaire; }