diff --git a/package-lock.json b/package-lock.json index 62a5980..c86e969 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "react": "~17.0.2", "react-bootstrap": "^1.6.4", "react-confetti": "^6.1.0", - "react-copy-to-clipboard": "^5.0.3", + "react-copy-to-clipboard": "^5.1.0", "react-dom": "~17.0.2", "react-ga4": "^2.1.0", "react-google-autocomplete": "^2.6.1", diff --git a/package.json b/package.json index abdf2ab..ea7fdf7 100644 --- a/package.json +++ b/package.json @@ -141,7 +141,7 @@ "react": "~17.0.2", "react-bootstrap": "^1.6.4", "react-confetti": "^6.1.0", - "react-copy-to-clipboard": "^5.0.3", + "react-copy-to-clipboard": "^5.1.0", "react-dom": "~17.0.2", "react-ga4": "^2.1.0", "react-google-autocomplete": "^2.6.1", diff --git a/src/App.jsx b/src/App.jsx index 15e22a9..ad47d2b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -31,7 +31,10 @@ const FAQ = React.lazy(() => import(/* webpackChunkName: 'FAQ' */ './js/pages/FA 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 TeamMembers = React.lazy(() => import(/* webpackChunkName: 'TeamMembers' */ './js/pages/TeamMembers')); +const AnswerQuestionsForm = React.lazy(() => import(/* webpackChunkName: 'AnswerQuestionsForm' */ './js/pages/AnswerQuestionsForm')); +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')); const Teams = React.lazy(() => import(/* webpackChunkName: 'Teams' */ './js/pages/Teams')); // There are just too many "prop spreadings" in the use of Route, if someone can figure out an alternative... @@ -276,8 +279,11 @@ class App extends Component { + + + - + diff --git a/src/js/actions/QuestionnaireActions.js b/src/js/actions/QuestionnaireActions.js new file mode 100644 index 0000000..81365dc --- /dev/null +++ b/src/js/actions/QuestionnaireActions.js @@ -0,0 +1,67 @@ +import Dispatcher from '../common/dispatcher/Dispatcher'; + +export default { + questionListRetrieve (questionnaireId, searchText = '') { + // console.log('QuestionnaireActions, questionListRetrieve searchText:', searchText); + if (searchText) { + Dispatcher.loadEndpoint('question-list-retrieve', { + questionnaireId, + searchText, + }); + } else { + Dispatcher.loadEndpoint('question-list-retrieve', { + questionnaireId, + }); + } + }, + + questionnaireListRetrieve (searchText = '') { + // console.log('QuestionnaireActions, questionnaireListRetrieve searchText:', searchText); + if (searchText) { + Dispatcher.loadEndpoint('questionnaire-list-retrieve', { + searchText, + }); + } else { + Dispatcher.loadEndpoint('questionnaire-list-retrieve'); + } + }, + + questionnaireRetrieve (questionnaireId = '') { + // console.log('QuestionnaireActions, questionnaireRetrieve questionnaireId:', questionnaireId); + if (questionnaireId) { + Dispatcher.loadEndpoint('questionnaire-retrieve', { + questionnaireId, + }); + } else { + Dispatcher.loadEndpoint('questionnaire-retrieve'); + } + }, + + questionnaireAnswerListSave (questionnaireId = -1, personId = -1, incomingData = {}) { + const data = { + questionnaireId, + personId, + ...incomingData, + }; + Dispatcher.loadEndpoint('answer-list-save', data); + }, + + questionnaireSave (questionnaireId = -1, incomingData = {}) { + // console.log('QuestionnaireActions, questionnaireSave questionnaireId:', questionnaireId, ', incomingData:', incomingData); + const data = { + questionnaireId, + ...incomingData, + }; + Dispatcher.loadEndpoint('questionnaire-save', data); + }, + + questionSave (questionnaireId = -1, questionId = -1, incomingData = {}) { + // console.log('QuestionnaireActions, questionSave questionId:', questionId, ', incomingData:', incomingData); + const data = { + questionId, + questionnaireId, + ...incomingData, + }; + Dispatcher.loadEndpoint('question-save', data); + }, +}; diff --git a/src/js/common/components/Style/DesignTokenColors.js b/src/js/common/components/Style/DesignTokenColors.js index 2d47c8c..8f6b744 100644 --- a/src/js/common/components/Style/DesignTokenColors.js +++ b/src/js/common/components/Style/DesignTokenColors.js @@ -132,6 +132,10 @@ const DesignTokenColors = { alert300: primitiveColorNames.redUI300, alert400: primitiveColorNames.redUI400, alert500: primitiveColorNames.redUI500, + alert600: primitiveColorNames.redUI600, + alert700: primitiveColorNames.redUI700, + alert800: primitiveColorNames.redUI800, + alert900: primitiveColorNames.redUI900, avatarBlue900: primitiveColorNames.blueUI900, avatarGreen900: primitiveColorNames.greenUI900, avatarOrange900: primitiveColorNames.orangeUI900, @@ -140,10 +144,6 @@ const DesignTokenColors = { avatarYellow800: primitiveColorNames.yellowUI800, avatarYellow900: primitiveColorNames.yellowUI900, avatarGray600: primitiveColorNames.grayUI600, - alert600: primitiveColorNames.redUI600, - alert700: primitiveColorNames.redUI700, - alert800: primitiveColorNames.redUI800, - alert900: primitiveColorNames.redUI900, caution50: primitiveColorNames.yellowUI50, caution100: primitiveColorNames.yellowUI100, caution200: primitiveColorNames.yellowUI200, diff --git a/src/js/common/utils/convertToInteger.js b/src/js/common/utils/convertToInteger.js new file mode 100644 index 0000000..dfd9eef --- /dev/null +++ b/src/js/common/utils/convertToInteger.js @@ -0,0 +1,3 @@ +export default function convertToInteger (incomingNumber) { + return parseInt(incomingNumber, 10) || 0; +} diff --git a/src/js/common/utils/prepareDataPackageFromAppObservableStore.js b/src/js/common/utils/prepareDataPackageFromAppObservableStore.js index a354106..9fe0815 100644 --- a/src/js/common/utils/prepareDataPackageFromAppObservableStore.js +++ b/src/js/common/utils/prepareDataPackageFromAppObservableStore.js @@ -6,8 +6,7 @@ export default function prepareDataPackageFromAppObservableStore (acceptedVariab for (let i = 0; i < acceptedVariables.length; i++) { // Ex/ emailPersonalToBeSaved and emailPersonalChanged // console.log(`prepareData: ${acceptedVariables[i]}ToBeSaved:`, AppObservableStore.getGlobalVariableState(`${acceptedVariables[i]}ToBeSaved`)); - if (AppObservableStore.getGlobalVariableState(`${acceptedVariables[i]}ToBeSaved`) && - AppObservableStore.getGlobalVariableState(`${acceptedVariables[i]}Changed`)) { + if (AppObservableStore.getGlobalVariableState(`${acceptedVariables[i]}Changed`)) { // If the value has changed, add it to the data dictionary if (AppObservableStore.getGlobalVariableState(`${acceptedVariables[i]}Changed`) === true) { data[`${acceptedVariables[i]}Changed`] = true; diff --git a/src/js/components/Drawers/AddPersonDrawer.jsx b/src/js/components/Drawers/AddPersonDrawer.jsx index 33ae443..d985ca4 100644 --- a/src/js/components/Drawers/AddPersonDrawer.jsx +++ b/src/js/components/Drawers/AddPersonDrawer.jsx @@ -7,7 +7,7 @@ import AppObservableStore, { messageService } from '../../stores/AppObservableSt import PersonStore from '../../stores/PersonStore'; import TeamStore from '../../stores/TeamStore'; import { renderLog } from '../../common/utils/logging'; -import AddPersonDrawerMainContent from './AddPersonDrawerMainContent'; +import AddPersonDrawerMainContent from '../Person/AddPersonDrawerMainContent'; const AddPersonDrawer = ({ classes }) => { // classes, teamId diff --git a/src/js/components/Drawers/AddTeamDrawer.jsx b/src/js/components/Drawers/AddTeamDrawer.jsx index 4adee7e..ac108ab 100644 --- a/src/js/components/Drawers/AddTeamDrawer.jsx +++ b/src/js/components/Drawers/AddTeamDrawer.jsx @@ -4,19 +4,16 @@ import PropTypes from 'prop-types'; import { withStyles } from '@mui/styles'; import DrawerTemplateA from './DrawerTemplateA'; import { messageService } from '../../stores/AppObservableStore'; -// import TeamActions from '../actions/TeamActions'; +import PersonStore from '../../stores/PersonStore'; import TeamStore from '../../stores/TeamStore'; -import SearchBar2024 from '../../common/components/Search/SearchBar2024'; import { renderLog } from '../../common/utils/logging'; -import AddTeamForm from '../Team/AddTeamForm'; +import AddTeamDrawerMainContent from '../Team/AddTeamDrawerMainContent'; const AddTeamDrawer = ({ classes }) => { // classes, teamId renderLog('AddTeamDrawer'); // Set LOG_RENDER_EVENTS to log all renders - const [mainContentJsx, setMainContentJsx] = React.useState(<>); const [headerTitleJsx, setHeaderTitleJsx] = React.useState(<>); const [headerFixedJsx, setHeaderFixedJsx] = React.useState(<>); - const [searchText, setSearchText] = React.useState(''); const onAppObservableStoreChange = () => { }; @@ -24,41 +21,23 @@ const AddTeamDrawer = ({ classes }) => { // classes, teamId const onRetrieveTeamChange = () => { }; - const onTeamStoreChange = () => { + const onPersonStoreChange = () => { onRetrieveTeamChange(); }; - const searchFunction = (incomingSearchText) => { - setSearchText(incomingSearchText); - }; - - const clearFunction = () => { - setSearchText(''); + const onTeamStoreChange = () => { + onRetrieveTeamChange(); }; React.useEffect(() => { const appStateSubscription = messageService.getMessage().subscribe(() => onAppObservableStoreChange()); onAppObservableStoreChange(); - const personStoreListener = TeamStore.addListener(onTeamStoreChange); - onTeamStoreChange(); + const personStoreListener = PersonStore.addListener(onPersonStoreChange); + onPersonStoreChange(); const teamStoreListener = TeamStore.addListener(onTeamStoreChange); onTeamStoreChange(); setHeaderTitleJsx(<>Add Team); - const mainContentJsxTemp = ( - - - - - - - ); - setMainContentJsx(mainContentJsxTemp); return () => { appStateSubscription.unsubscribe(); @@ -71,7 +50,7 @@ const AddTeamDrawer = ({ classes }) => { // classes, teamId } headerTitleJsx={headerTitleJsx} headerFixedJsx={headerFixedJsx} /> diff --git a/src/js/components/Drawers/Drawers.jsx b/src/js/components/Drawers/Drawers.jsx index 156f68d..9ac5c4e 100644 --- a/src/js/components/Drawers/Drawers.jsx +++ b/src/js/components/Drawers/Drawers.jsx @@ -1,48 +1,34 @@ -import React, { Suspense } from 'react'; +import React from 'react'; import styled from 'styled-components'; -import PropTypes from 'prop-types'; import { withStyles } from '@mui/styles'; import AddPersonDrawer from './AddPersonDrawer'; +import EditQuestionnaireDrawer from './EditQuestionnaireDrawer'; import AddTeamDrawer from './AddTeamDrawer'; import EditPersonDrawer from './EditPersonDrawer'; -import { messageService } from '../../stores/AppObservableStore'; +import EditQuestionDrawer from './EditQuestionDrawer'; +import PersonProfileDrawer from './PersonProfileDrawer'; import { renderLog } from '../../common/utils/logging'; const Drawers = () => { // classes, teamId renderLog('Drawers'); // Set LOG_RENDER_EVENTS to log all renders - const onAppObservableStoreChange = () => { - }; - - React.useEffect(() => { - const appStateSubscription = messageService.getMessage().subscribe(() => onAppObservableStoreChange()); - onAppObservableStoreChange(); - - return () => { - appStateSubscription.unsubscribe(); - }; - }, []); - return ( - }> + + - + + + ); }; -Drawers.propTypes = { - match: PropTypes.object, -}; const styles = () => ({ }); -const SearchBarWrapper = styled('div')` - // margin-top: 14px; - // margin-bottom: 8px; - width: 100%; +const DrawersWrapper = styled('div')` `; export default withStyles(styles)(Drawers); diff --git a/src/js/components/Drawers/EditPersonDrawer.jsx b/src/js/components/Drawers/EditPersonDrawer.jsx index 32282d4..0411ab9 100644 --- a/src/js/components/Drawers/EditPersonDrawer.jsx +++ b/src/js/components/Drawers/EditPersonDrawer.jsx @@ -7,7 +7,7 @@ import AppObservableStore, { messageService } from '../../stores/AppObservableSt import PersonStore from '../../stores/PersonStore'; import TeamStore from '../../stores/TeamStore'; import { renderLog } from '../../common/utils/logging'; -import EditPersonDrawerMainContent from './EditPersonDrawerMainContent'; +import EditPersonDrawerMainContent from '../Person/EditPersonDrawerMainContent'; const EditPersonDrawer = ({ classes }) => { // classes, teamId diff --git a/src/js/components/Drawers/EditQuestionDrawer.jsx b/src/js/components/Drawers/EditQuestionDrawer.jsx new file mode 100644 index 0000000..44edf56 --- /dev/null +++ b/src/js/components/Drawers/EditQuestionDrawer.jsx @@ -0,0 +1,44 @@ +import React from 'react'; +import DrawerTemplateA from './DrawerTemplateA'; +import { renderLog } from '../../common/utils/logging'; +import EditQuestionDrawerMainContent from '../Questionnaire/EditQuestionDrawerMainContent'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; + + +const EditQuestionDrawer = () => { + renderLog('EditQuestionDrawer'); // Set LOG_RENDER_EVENTS to log all renders + const [headerTitleJsx, setHeaderTitleJsx] = React.useState(<>); + const [headerFixedJsx, setHeaderFixedJsx] = React.useState(<>); + + const onAppObservableStoreChange = () => { + const questionIdTemp = AppObservableStore.getGlobalVariableState('editQuestionDrawerQuestionId'); + if (questionIdTemp >= 0) { + setHeaderTitleJsx(<>Edit Question); + } else { + setHeaderTitleJsx(<>Add Question); + } + }; + + React.useEffect(() => { + const appStateSubscription = messageService.getMessage().subscribe(() => onAppObservableStoreChange()); + onAppObservableStoreChange(); + + return () => { + appStateSubscription.unsubscribe(); + }; + }, []); + + return ( + } + headerTitleJsx={headerTitleJsx} + headerFixedJsx={headerFixedJsx} + /> + ); +}; +EditQuestionDrawer.propTypes = { +}; + +export default EditQuestionDrawer; diff --git a/src/js/components/Drawers/EditQuestionnaireDrawer.jsx b/src/js/components/Drawers/EditQuestionnaireDrawer.jsx new file mode 100644 index 0000000..60ad95d --- /dev/null +++ b/src/js/components/Drawers/EditQuestionnaireDrawer.jsx @@ -0,0 +1,44 @@ +import React from 'react'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import DrawerTemplateA from './DrawerTemplateA'; +import { renderLog } from '../../common/utils/logging'; +import EditQuestionnaireDrawerMainContent from '../Questionnaire/EditQuestionnaireDrawerMainContent'; + + +const EditQuestionnaireDrawer = () => { + renderLog('EditQuestionnaireDrawer'); // Set LOG_RENDER_EVENTS to log all renders + const [headerTitleJsx, setHeaderTitleJsx] = React.useState(<>); + const [headerFixedJsx, setHeaderFixedJsx] = React.useState(<>); + + const onAppObservableStoreChange = () => { + const questionnaireIdTemp = AppObservableStore.getGlobalVariableState('editQuestionnaireDrawerQuestionnaireId'); + if (questionnaireIdTemp >= 0) { + setHeaderTitleJsx(<>Edit Questionnaire); + } else { + setHeaderTitleJsx(<>Add Questionnaire); + } + }; + + React.useEffect(() => { + const appStateSubscription = messageService.getMessage().subscribe(() => onAppObservableStoreChange()); + onAppObservableStoreChange(); + + return () => { + appStateSubscription.unsubscribe(); + }; + }, []); + + return ( + } + headerTitleJsx={headerTitleJsx} + headerFixedJsx={headerFixedJsx} + /> + ); +}; +EditQuestionnaireDrawer.propTypes = { +}; + +export default EditQuestionnaireDrawer; diff --git a/src/js/components/Drawers/PersonProfileDrawer.jsx b/src/js/components/Drawers/PersonProfileDrawer.jsx new file mode 100644 index 0000000..88ce737 --- /dev/null +++ b/src/js/components/Drawers/PersonProfileDrawer.jsx @@ -0,0 +1,67 @@ +import React from 'react'; +import styled from 'styled-components'; +import { withStyles } from '@mui/styles'; +import DrawerTemplateA from './DrawerTemplateA'; +import { messageService } from '../../stores/AppObservableStore'; +import PersonStore from '../../stores/PersonStore'; +import TeamStore from '../../stores/TeamStore'; +import { renderLog } from '../../common/utils/logging'; +import PersonProfileDrawerMainContent from '../Person/PersonProfileDrawerMainContent'; + + +const PersonProfileDrawer = () => { + renderLog('PersonProfileDrawer'); // Set LOG_RENDER_EVENTS to log all renders + const [headerTitleJsx, setHeaderTitleJsx] = React.useState(<>); + const [headerFixedJsx, setHeaderFixedJsx] = React.useState(<>); + // const [teamId, setTeamId] = React.useState(-1); + + const onAppObservableStoreChange = () => { + // setTeamId(AppObservableStore.getGlobalVariableState('personProfileDrawerTeamId')); + }; + + const onRetrieveTeamChange = () => { + }; + + const onPersonStoreChange = () => { + onRetrieveTeamChange(); + }; + + const onTeamStoreChange = () => { + onRetrieveTeamChange(); + }; + + React.useEffect(() => { + const appStateSubscription = messageService.getMessage().subscribe(() => onAppObservableStoreChange()); + onAppObservableStoreChange(); + const personStoreListener = PersonStore.addListener(onPersonStoreChange); + onPersonStoreChange(); + const teamStoreListener = TeamStore.addListener(onTeamStoreChange); + onTeamStoreChange(); + + // setHeaderTitleJsx(<>Person Profile); + + return () => { + appStateSubscription.unsubscribe(); + personStoreListener.remove(); + teamStoreListener.remove(); + }; + }, []); + + return ( + } + headerTitleJsx={headerTitleJsx} + headerFixedJsx={headerFixedJsx} + /> + ); +}; + +const styles = () => ({ +}); + +const PersonProfileDrawerWrapper = styled('div')` +`; + +export default withStyles(styles)(PersonProfileDrawer); diff --git a/src/js/components/Drawers/AddPersonDrawerMainContent.jsx b/src/js/components/Person/AddPersonDrawerMainContent.jsx similarity index 96% rename from src/js/components/Drawers/AddPersonDrawerMainContent.jsx rename to src/js/components/Person/AddPersonDrawerMainContent.jsx index 4599a52..f026c88 100644 --- a/src/js/components/Drawers/AddPersonDrawerMainContent.jsx +++ b/src/js/components/Person/AddPersonDrawerMainContent.jsx @@ -2,6 +2,7 @@ import React from 'react'; import styled from 'styled-components'; import PropTypes from 'prop-types'; import { withStyles } from '@mui/styles'; +import { SpanWithLinkStyle } from '../Style/linkStyles'; import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; import PersonActions from '../../actions/PersonActions'; import TeamActions from '../../actions/TeamActions'; @@ -9,10 +10,9 @@ import PersonStore from '../../stores/PersonStore'; import TeamStore from '../../stores/TeamStore'; import apiCalming from '../../common/utils/apiCalming'; import SearchBar2024 from '../../common/components/Search/SearchBar2024'; -import DesignTokenColors from '../../common/components/Style/DesignTokenColors'; import arrayContains from '../../common/utils/arrayContains'; import { renderLog } from '../../common/utils/logging'; -import AddPersonForm from '../Person/AddPersonForm'; +import AddPersonForm from './AddPersonForm'; const AddPersonDrawerMainContent = ({ classes }) => { // classes, teamId @@ -152,12 +152,6 @@ const AddPersonWrapper = styled('div')` margin-top: 32px; `; -const SpanWithLinkStyle = styled('span')` - text-decoration: underline; - color: ${DesignTokenColors.primary500}; - cursor: pointer; -`; - const PersonDirectoryWrapper = styled('div')` margin-top: 16px; `; diff --git a/src/js/components/Person/AddPersonForm.jsx b/src/js/components/Person/AddPersonForm.jsx index f51d505..98fcffd 100644 --- a/src/js/components/Person/AddPersonForm.jsx +++ b/src/js/components/Person/AddPersonForm.jsx @@ -45,8 +45,7 @@ const AddPersonForm = ({ classes }) => { // classes, teamId }; const saveNewPerson = () => { - const acceptedVariables = FIELDS_IN_FORM; - const data = prepareDataPackageFromAppObservableStore(acceptedVariables); + const data = prepareDataPackageFromAppObservableStore(FIELDS_IN_FORM); if (teamId >= 0) { data.teamId = teamId; data.teamName = TeamStore.getTeamById(teamId).teamName; @@ -111,6 +110,7 @@ const AddPersonForm = ({ classes }) => { // classes, teamId { // classes, teamId diff --git a/src/js/components/Person/EditPersonForm.jsx b/src/js/components/Person/EditPersonForm.jsx index b5f0a4a..963860d 100644 --- a/src/js/components/Person/EditPersonForm.jsx +++ b/src/js/components/Person/EditPersonForm.jsx @@ -10,13 +10,15 @@ import { renderLog } from '../../common/utils/logging'; import prepareDataPackageFromAppObservableStore from '../../common/utils/prepareDataPackageFromAppObservableStore'; import webAppConfig from '../../config'; -const PERSON_FIELDS_IN_FORM = ['emailPersonal', 'firstName', 'firstNamePreferred', 'jobTitle', 'lastName', 'location']; +const PERSON_FIELDS_IN_FORM = [ + 'emailPersonal', 'firstName', 'firstNamePreferred', 'jobTitle', 'lastName', + 'location']; const EditPersonForm = ({ classes }) => { // classes, teamId renderLog('EditPersonForm'); // Set LOG_RENDER_EVENTS to log all renders const [firstPersonDataReceived, setFirstPersonDataReceived] = React.useState(false); const [inputValues, setInputValues] = React.useState({}); - const [personId, setPersonId] = React.useState(-1); + // const [personId, setPersonId] = React.useState(-1); // const [personDictAlreadySaved, setPersonDictAlreadySaved] = React.useState({}); const [saveButtonActive, setSaveButtonActive] = React.useState(false); @@ -33,22 +35,14 @@ const EditPersonForm = ({ classes }) => { // classes, teamId AppObservableStore.setGlobalVariableStateInBulk(globalVariableStates); }; - const onAppObservableStoreChange = () => { - const editPersonDrawerOpenTemp = AppObservableStore.getGlobalVariableState('editPersonDrawerOpen'); - const personIdTemp = AppObservableStore.getGlobalVariableState('editPersonDrawerPersonId'); - if (personIdTemp >= 0 && !editPersonDrawerOpenTemp) { - clearEditFormValuesInAppObservableStore(); - setFirstPersonDataReceived(false); - } - setPersonId(personIdTemp); + const clearEditedValues = () => { + setInputValues({}); + setFirstPersonDataReceived(false); + // setPersonId(-1); + clearEditFormValuesInAppObservableStore(); + AppObservableStore.setGlobalVariableState('editPersonDrawerOpen', false); }; - // const savePersonSuccessful = () => { - // AppObservableStore.setGlobalVariableState('editPersonDrawerOpen', false); - // setFirstPersonDataReceived(false); - // clearEditFormValuesInAppObservableStore(); - // }; - const updateInputValuesFromPersonStore = (inputValuesIncoming) => { const revisedInputValues = { ...inputValuesIncoming }; const personIdTemp = AppObservableStore.getGlobalVariableState('editPersonDrawerPersonId'); @@ -64,6 +58,14 @@ const EditPersonForm = ({ classes }) => { // classes, teamId return revisedInputValues; }; + const onAppObservableStoreChange = () => { + const editPersonDrawerOpenTemp = AppObservableStore.getGlobalVariableState('editPersonDrawerOpen'); + const personIdTemp = AppObservableStore.getGlobalVariableState('editPersonDrawerPersonId'); + if (personIdTemp >= 0 && !editPersonDrawerOpenTemp) { + clearEditedValues(); + } + }; + const onPersonStoreChange = () => { const personIdTemp = AppObservableStore.getGlobalVariableState('editPersonDrawerPersonId'); const personDict = PersonStore.getPersonById(personIdTemp) || {}; @@ -77,17 +79,20 @@ const EditPersonForm = ({ classes }) => { // classes, teamId }; const savePerson = () => { - const acceptedVariables = PERSON_FIELDS_IN_FORM; - const data = prepareDataPackageFromAppObservableStore(acceptedVariables); + const personIdTemp = AppObservableStore.getGlobalVariableState('editPersonDrawerPersonId'); + const data = prepareDataPackageFromAppObservableStore(PERSON_FIELDS_IN_FORM); // console.log('savePerson data:', data); - PersonActions.personSave(personId, data); + PersonActions.personSave(personIdTemp, data); setSaveButtonActive(false); + setTimeout(() => { + clearEditedValues(); + }, 250); }; const updatePersonField = (event) => { // The input name must match the person field being updated - if (event.target.name && event.target.value) { - const newValue = event.target.value; + if (event.target.name) { + const newValue = event.target.value || ''; AppObservableStore.setGlobalVariableState(`${event.target.name}Changed`, true); AppObservableStore.setGlobalVariableState(`${event.target.name}ToBeSaved`, newValue); // console.log('updatePersonField:', event.target.name, ', newValue:', newValue); @@ -104,13 +109,9 @@ const EditPersonForm = ({ classes }) => { // classes, teamId const personStoreListener = PersonStore.addListener(onPersonStoreChange); onPersonStoreChange(); - // const personId = AppObservableStore.getGlobalVariableState('editPersonDrawerPersonId'); - // console.log('Initial load emailPersonalToBeSaved:', AppObservableStore.getGlobalVariableState('emailPersonalToBeSaved')); - return () => { appStateSubscription.unsubscribe(); personStoreListener.remove(); - setFirstPersonDataReceived(false); }; }, []); @@ -118,14 +119,15 @@ const EditPersonForm = ({ classes }) => { // classes, teamId { + renderLog('PersonProfile'); // Set LOG_RENDER_EVENTS to log all renders + const [person, setPerson] = React.useState({}); + const [fullNamePreferred, setFullNamePreferred] = React.useState(''); + + const onAppObservableStoreChange = () => { + // const teamIdTemp = AppObservableStore.getGlobalVariableState('personProfileDrawerTeamId'); + // console.log('PersonProfile AppObservableStore-personProfileDrawerTeamId: ', teamIdTemp); + }; + + const onPersonStoreChange = () => { + const personTemp = PersonStore.getPersonById(personId); + console.log('PersonProfile personId:', personId, ', personTemp:', personTemp); + setPerson(personTemp); + const fullNamePreferredTemp = PersonStore.getFullNamePreferred(personId); + setFullNamePreferred(fullNamePreferredTemp); + // console.log('PersonProfile-onPersonStoreChange personIdTemp: ', personIdTemp); + }; + + const onTeamStoreChange = () => { + // const teamIdTemp = AppObservableStore.getGlobalVariableState('personProfileDrawerTeamId'); + // console.log('PersonProfile-onTeamStoreChange teamIdTemp: ', teamIdTemp); + }; + + 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); + } + + return () => { + // console.log('PersonProfile cleanup'); + appStateSubscription.unsubscribe(); + personStoreListener.remove(); + teamStoreListener.remove(); + }; + }, []); + + return ( + + + {fullNamePreferred} + + {/* */} + + + ); +}; +PersonProfile.propTypes = { + classes: PropTypes.object.isRequired, + personId: PropTypes.number, +}; + +const styles = () => ({ +}); + +const FullName = styled('div')` +`; + +const PersonProfileWrapper = styled('div')` +`; + +export default withStyles(styles)(PersonProfile); diff --git a/src/js/components/Person/PersonProfileDrawerMainContent.jsx b/src/js/components/Person/PersonProfileDrawerMainContent.jsx new file mode 100644 index 0000000..72ad460 --- /dev/null +++ b/src/js/components/Person/PersonProfileDrawerMainContent.jsx @@ -0,0 +1,74 @@ +import React from 'react'; +import styled from 'styled-components'; +import PropTypes from 'prop-types'; +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 apiCalming from '../../common/utils/apiCalming'; +import { renderLog } from '../../common/utils/logging'; +import PersonProfile from './PersonProfile'; + + +const PersonProfileDrawerMainContent = ({ classes }) => { // classes, teamId + renderLog('PersonProfileDrawerMainContent'); // Set LOG_RENDER_EVENTS to log all renders + const [personId, setPersonId] = React.useState(-1); + + const onAppObservableStoreChange = () => { + // const teamIdTemp = AppObservableStore.getGlobalVariableState('personProfileDrawerTeamId'); + // console.log('PersonProfileDrawerMainContent AppObservableStore-personProfileDrawerTeamId: ', teamIdTemp); + }; + + const onPersonStoreChange = () => { + const personIdTemp = AppObservableStore.getGlobalVariableState('personProfileDrawerPersonId'); + // console.log('PersonProfileDrawerMainContent personSearchResultsList:', personSearchResultsListTemp); + setPersonId(personIdTemp); + // console.log('PersonProfileDrawerMainContent-onPersonStoreChange personIdTemp: ', personIdTemp); + }; + + const onTeamStoreChange = () => { + // const teamIdTemp = AppObservableStore.getGlobalVariableState('personProfileDrawerTeamId'); + // console.log('PersonProfileDrawerMainContent-onTeamStoreChange teamIdTemp: ', teamIdTemp); + }; + + 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); + } + + return () => { + // console.log('PersonProfileDrawerMainContent cleanup'); + appStateSubscription.unsubscribe(); + personStoreListener.remove(); + teamStoreListener.remove(); + }; + }, []); + + const personIdTemp = AppObservableStore.getGlobalVariableState('personProfileDrawerPersonId'); + + return ( + + + + ); +}; +PersonProfileDrawerMainContent.propTypes = { + classes: PropTypes.object.isRequired, +}; + +const styles = () => ({ +}); + +const PersonProfileDrawerMainContentWrapper = styled('div')` +`; + +export default withStyles(styles)(PersonProfileDrawerMainContent); diff --git a/src/js/components/Questionnaire/CopyQuestionnaireLink.jsx b/src/js/components/Questionnaire/CopyQuestionnaireLink.jsx new file mode 100644 index 0000000..225fe83 --- /dev/null +++ b/src/js/components/Questionnaire/CopyQuestionnaireLink.jsx @@ -0,0 +1,104 @@ +import React from 'react'; +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'); + // openSnackbar({ message: 'Copied!' }); + setLinkCopied(true); + setTimeout(() => { + setLinkCopied(false); + }, 1500); + }; + + 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(); + }; + }, []); + + return ( + + +
+ {linkCopied ? ( +
Link copied!
+ ) : ( + + copy questionnaire link + + )} +
+
+
+ ); +}; +CopyQuestionnaireLink.propTypes = { + classes: PropTypes.object.isRequired, + personId: PropTypes.number, + questionnaireId: PropTypes.number, +}; + +const styles = () => ({ +}); + +const FullName = styled('div')` +`; + +const CopyQuestionnaireLinkWrapper = styled('div')` +`; + +export default withStyles(styles)(CopyQuestionnaireLink); diff --git a/src/js/components/Questionnaire/EditQuestionDrawerMainContent.jsx b/src/js/components/Questionnaire/EditQuestionDrawerMainContent.jsx new file mode 100644 index 0000000..6f9ec9c --- /dev/null +++ b/src/js/components/Questionnaire/EditQuestionDrawerMainContent.jsx @@ -0,0 +1,41 @@ +import React from 'react'; +import styled from 'styled-components'; +import { withStyles } from '@mui/styles'; +import AppObservableStore from '../../stores/AppObservableStore'; +import QuestionnaireActions from '../../actions/QuestionnaireActions'; +import apiCalming from '../../common/utils/apiCalming'; +import { renderLog } from '../../common/utils/logging'; +import EditQuestionForm from './EditQuestionForm'; + + +const EditQuestionDrawerMainContent = () => { + renderLog('EditQuestionDrawerMainContent'); // Set LOG_RENDER_EVENTS to log all renders + + React.useEffect(() => { + // We currently don't retrieve individual questions, only complete question lists for a questionnaire. + const questionnaireIdTemp = AppObservableStore.getGlobalVariableState('editQuestionDrawerQuestionnaireId'); + if (apiCalming(`questionListRetrieve-${questionnaireIdTemp}`, 30000)) { + QuestionnaireActions.questionListRetrieve(questionnaireIdTemp); + } + }, []); + + return ( + + + + + + ); +}; + +const styles = () => ({ +}); + +const EditQuestionDrawerMainContentWrapper = styled('div')` +`; + +const EditQuestionWrapper = styled('div')` + margin-top: 32px; +`; + +export default withStyles(styles)(EditQuestionDrawerMainContent); diff --git a/src/js/components/Questionnaire/EditQuestionForm.jsx b/src/js/components/Questionnaire/EditQuestionForm.jsx new file mode 100644 index 0000000..8934ceb --- /dev/null +++ b/src/js/components/Questionnaire/EditQuestionForm.jsx @@ -0,0 +1,247 @@ +import { Button, Checkbox, FormControl, FormControlLabel, TextField } from '@mui/material'; +import { withStyles } from '@mui/styles'; +import React from 'react'; +import styled from 'styled-components'; +import PropTypes from 'prop-types'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import QuestionnaireActions from '../../actions/QuestionnaireActions'; +import QuestionnaireStore from '../../stores/QuestionnaireStore'; +import { renderLog } from '../../common/utils/logging'; +import prepareDataPackageFromAppObservableStore from '../../common/utils/prepareDataPackageFromAppObservableStore'; + +const QUESTION_FIELDS_IN_FORM = [ + 'answerType', 'fieldMappingRule', 'questionInstructions', 'questionText', + 'requireAnswer', 'statusActive']; + +const EditQuestionForm = ({ classes }) => { // classes, teamId + renderLog('EditQuestionForm'); // Set LOG_RENDER_EVENTS to log all renders + const [firstQuestionDataReceived, setFirstQuestionDataReceived] = React.useState(false); + const [inputValues, setInputValues] = React.useState({ + answerType: '', + questionInstructions: '', + questionText: '', + requireAnswer: false, + statusActive: true, + }); + // const [questionId, setQuestionId] = React.useState(-1); + // const [questionDictAlreadySaved, setQuestionDictAlreadySaved] = React.useState({}); + const [saveButtonActive, setSaveButtonActive] = React.useState(false); + + // const noNotch = { + // '& .MuiOutlinedInput-notchedOutline legend': { + // display: 'none', + // }, + // }; + + const clearEditFormValuesInAppObservableStore = () => { + const globalVariableStates = {}; + for (let i = 0; i < QUESTION_FIELDS_IN_FORM.length; i++) { + const fieldName = QUESTION_FIELDS_IN_FORM[i]; + globalVariableStates[`${fieldName}Changed`] = false; + globalVariableStates[`${fieldName}ToBeSaved`] = ''; + } + globalVariableStates.editQuestionDrawerQuestionId = -1; + // console.log('clearEditFormValuesInAppObservableStore globalVariableStates:', globalVariableStates); + AppObservableStore.setGlobalVariableStateInBulk(globalVariableStates); + }; + + const clearEditedValues = () => { + setInputValues({}); + setFirstQuestionDataReceived(false); + // setQuestionId(-1); + clearEditFormValuesInAppObservableStore(); + AppObservableStore.setGlobalVariableState('editQuestionDrawerOpen', false); + }; + + const updateInputValuesFromQuestionnaireStore = (inputValuesIncoming) => { + const revisedInputValues = { ...inputValuesIncoming }; + const questionIdTemp = AppObservableStore.getGlobalVariableState('editQuestionDrawerQuestionId'); + const questionDict = QuestionnaireStore.getQuestionById(questionIdTemp) || {}; + // console.log('=== updateInputValuesFromQuestionnaireStore questionIdTemp:', questionIdTemp, ', questionDict:', questionDict); + if (questionIdTemp && questionDict.questionId) { + // console.log('questionIdTemp:', questionIdTemp, ', questionDict.questionId:', questionDict.questionId); + // setQuestionDictAlreadySaved(questionDict); + for (let i = 0; i < QUESTION_FIELDS_IN_FORM.length; i++) { + const fieldName = QUESTION_FIELDS_IN_FORM[i]; + revisedInputValues[fieldName] = questionDict[fieldName]; + } + } + return revisedInputValues; + }; + + const onAppObservableStoreChange = () => { + const editQuestionDrawerOpenTemp = AppObservableStore.getGlobalVariableState('editQuestionDrawerOpen'); + const questionIdTemp = AppObservableStore.getGlobalVariableState('editQuestionDrawerQuestionId'); + if (questionIdTemp >= 0 && !editQuestionDrawerOpenTemp) { + clearEditedValues(); + } + }; + + const onQuestionnaireStoreChange = () => { + const questionIdTemp = AppObservableStore.getGlobalVariableState('editQuestionDrawerQuestionId'); + const questionDict = QuestionnaireStore.getQuestionById(questionIdTemp) || {}; + // console.log('EditQuestionForm onQuestionnaireStoreChange questionIdTemp:', questionIdTemp, ', questionDict:', questionDict); + if (!firstQuestionDataReceived) { + // console.log('onQuestionnaireStoreChange firstQuestionDataReceived:', firstQuestionDataReceived); + if (questionIdTemp && questionDict.questionId) { + const inputValuesRevised = updateInputValuesFromQuestionnaireStore(inputValues); + setFirstQuestionDataReceived(true); + setInputValues(inputValuesRevised); + } + } + }; + + const saveQuestion = () => { + const questionIdTemp = AppObservableStore.getGlobalVariableState('editQuestionDrawerQuestionId'); + const questionnaireIdTemp = AppObservableStore.getGlobalVariableState('editQuestionDrawerQuestionnaireId'); + const data = prepareDataPackageFromAppObservableStore(QUESTION_FIELDS_IN_FORM); + // console.log('saveQuestion questionId: ', questionIdTemp, ', data:', data); + QuestionnaireActions.questionSave(questionnaireIdTemp, questionIdTemp, data); + setSaveButtonActive(false); + setTimeout(() => { + clearEditedValues(); + }, 250); + }; + + const updateQuestionField = (event) => { + if (event.target.name) { + let newValue; + if (event.target.type === 'checkbox') { + newValue = event.target.checked; + } else { + newValue = event.target.value || ''; + } + AppObservableStore.setGlobalVariableState(`${event.target.name}Changed`, true); + AppObservableStore.setGlobalVariableState(`${event.target.name}ToBeSaved`, newValue); + // console.log('updateQuestionField:', event.target.name, ', newValue:', newValue); + setInputValues({ ...inputValues, [event.target.name]: newValue }); + setSaveButtonActive(true); + } else { + console.error('updateQuestionField Invalid event:', event); + } + }; + + React.useEffect(() => { + const appStateSubscription = messageService.getMessage().subscribe(() => onAppObservableStoreChange()); + onAppObservableStoreChange(); + const personStoreListener = QuestionnaireStore.addListener(onQuestionnaireStoreChange); + onQuestionnaireStoreChange(); + + return () => { + appStateSubscription.unsubscribe(); + personStoreListener.remove(); + }; + }, []); + + return ( + + + + + + + )} + label="Require an answer to this question" + /> + + )} + label="Question is active" + /> + + + + ); +}; +EditQuestionForm.propTypes = { + classes: PropTypes.object.isRequired, +}; + +const styles = (theme) => ({ + checkboxRoot: { + paddingTop: 0, + paddingLeft: '9px', + paddingBottom: 0, + }, + checkboxLabel: { + marginTop: 2, + }, + formControl: { + width: '100%', + }, + saveQuestionButton: { + width: 300, + [theme.breakpoints.down('md')]: { + width: '100%', + }, + }, +}); + +const CheckboxLabel = styled(FormControlLabel)` + margin-bottom: 0 !important; +`; + +const EditQuestionFormWrapper = styled('div')` +`; + +export default withStyles(styles)(EditQuestionForm); diff --git a/src/js/components/Questionnaire/EditQuestionnaireDrawerMainContent.jsx b/src/js/components/Questionnaire/EditQuestionnaireDrawerMainContent.jsx new file mode 100644 index 0000000..080c46e --- /dev/null +++ b/src/js/components/Questionnaire/EditQuestionnaireDrawerMainContent.jsx @@ -0,0 +1,38 @@ +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 EditQuestionnaireForm from './EditQuestionnaireForm'; + + +const EditQuestionnaireDrawerMainContent = () => { + renderLog('EditQuestionnaireDrawerMainContent'); // Set LOG_RENDER_EVENTS to log all renders + + React.useEffect(() => { + if (apiCalming('personListRetrieve', 30000)) { + PersonActions.personListRetrieve(); + } + }, []); + + return ( + + + + + + ); +}; + +const styles = () => ({ +}); + +const EditQuestionnaireDrawerMainContentWrapper = styled('div')` +`; + +const AddQuestionnaireWrapper = styled('div')` + margin-top: 32px; +`; + +export default withStyles(styles)(EditQuestionnaireDrawerMainContent); diff --git a/src/js/components/Questionnaire/EditQuestionnaireForm.jsx b/src/js/components/Questionnaire/EditQuestionnaireForm.jsx new file mode 100644 index 0000000..b34d6bb --- /dev/null +++ b/src/js/components/Questionnaire/EditQuestionnaireForm.jsx @@ -0,0 +1,185 @@ +import { Button, FormControl, TextField } from '@mui/material'; +import { withStyles } from '@mui/styles'; +import React from 'react'; +import styled from 'styled-components'; +import PropTypes from 'prop-types'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import QuestionnaireActions from '../../actions/QuestionnaireActions'; +import QuestionnaireStore from '../../stores/QuestionnaireStore'; +import { renderLog } from '../../common/utils/logging'; +import prepareDataPackageFromAppObservableStore from '../../common/utils/prepareDataPackageFromAppObservableStore'; + +const QUESTIONNAIRE_FIELDS_IN_FORM = [ + 'questionnaireInstructions', 'questionnaireName', 'questionnaireTitle']; + +const EditQuestionnaireForm = ({ classes }) => { + renderLog('EditQuestionnaireForm'); // Set LOG_RENDER_EVENTS to log all renders + const [firstQuestionnaireDataReceived, setFirstQuestionnaireDataReceived] = React.useState(false); + const [inputValues, setInputValues] = React.useState({}); + // const [questionnaireId, setQuestionnaireId] = React.useState(-1); + // const [questionnaireDictAlreadySaved, setQuestionnaireDictAlreadySaved] = React.useState({}); + const [saveButtonActive, setSaveButtonActive] = React.useState(false); + + const clearEditFormValuesInAppObservableStore = () => { + const globalVariableStates = {}; + for (let i = 0; i < QUESTIONNAIRE_FIELDS_IN_FORM.length; i++) { + const fieldName = QUESTIONNAIRE_FIELDS_IN_FORM[i]; + globalVariableStates[`${fieldName}Changed`] = false; + globalVariableStates[`${fieldName}ToBeSaved`] = ''; + } + globalVariableStates.editQuestionnaireDrawerQuestionnaireId = -1; + // console.log('clearEditFormValuesInAppObservableStore globalVariableStates:', globalVariableStates); + AppObservableStore.setGlobalVariableStateInBulk(globalVariableStates); + }; + + const clearEditedValues = () => { + setInputValues({}); + setFirstQuestionnaireDataReceived(false); + // setQuestionnaireId(-1); + clearEditFormValuesInAppObservableStore(); + AppObservableStore.setGlobalVariableState('editQuestionnaireDrawerOpen', false); + }; + + const updateInputValuesFromQuestionnaireStore = (inputValuesIncoming) => { + const revisedInputValues = { ...inputValuesIncoming }; + const questionnaireIdTemp = AppObservableStore.getGlobalVariableState('editQuestionnaireDrawerQuestionnaireId'); + const questionnaireDict = QuestionnaireStore.getQuestionnaireById(questionnaireIdTemp) || {}; + // console.log('=== updateInputValuesFromQuestionnaireStore questionnaireIdTemp:', questionnaireIdTemp, ', questionnaireDict:', questionnaireDict); + if (questionnaireIdTemp && questionnaireDict.questionnaireId) { + // console.log('questionnaireIdTemp:', questionnaireIdTemp, ', questionnaireDict.questionnaireId:', questionnaireDict.questionnaireId); + // setQuestionnaireDictAlreadySaved(questionnaireDict); + for (let i = 0; i < QUESTIONNAIRE_FIELDS_IN_FORM.length; i++) { + const fieldName = QUESTIONNAIRE_FIELDS_IN_FORM[i]; + revisedInputValues[fieldName] = questionnaireDict[fieldName]; + } + } + return revisedInputValues; + }; + + const onAppObservableStoreChange = () => { + const editQuestionnaireDrawerOpenTemp = AppObservableStore.getGlobalVariableState('editQuestionnaireDrawerOpen'); + const questionnaireIdTemp = AppObservableStore.getGlobalVariableState('editQuestionnaireDrawerQuestionnaireId'); + if (questionnaireIdTemp >= 0 && !editQuestionnaireDrawerOpenTemp) { + clearEditedValues(); + } + }; + + const onQuestionnaireStoreChange = () => { + const questionnaireIdTemp = AppObservableStore.getGlobalVariableState('editQuestionnaireDrawerQuestionnaireId'); + const questionnaireDict = QuestionnaireStore.getQuestionnaireById(questionnaireIdTemp) || {}; + if (!firstQuestionnaireDataReceived) { + if (questionnaireIdTemp && questionnaireDict.questionnaireId) { + const inputValuesRevised = updateInputValuesFromQuestionnaireStore(inputValues); + setFirstQuestionnaireDataReceived(true); + setInputValues(inputValuesRevised); + } + } + }; + + const saveQuestionnaire = () => { + const questionnaireIdTemp = AppObservableStore.getGlobalVariableState('editQuestionnaireDrawerQuestionnaireId'); + const data = prepareDataPackageFromAppObservableStore(QUESTIONNAIRE_FIELDS_IN_FORM); + // console.log('saveQuestionnaire data:', data); + QuestionnaireActions.questionnaireSave(questionnaireIdTemp, data); + setSaveButtonActive(false); + setTimeout(() => { + clearEditedValues(); + }, 250); + }; + + const updateQuestionnaireField = (event) => { + if (event.target.name) { + const newValue = event.target.value || ''; + AppObservableStore.setGlobalVariableState(`${event.target.name}Changed`, true); + AppObservableStore.setGlobalVariableState(`${event.target.name}ToBeSaved`, newValue); + // console.log('updateQuestionnaireField:', event.target.name, ', newValue:', newValue); + setInputValues({ ...inputValues, [event.target.name]: newValue }); + setSaveButtonActive(true); + } else { + console.error('updateQuestionnaireField Invalid event:', event); + } + }; + + React.useEffect(() => { + const appStateSubscription = messageService.getMessage().subscribe(() => onAppObservableStoreChange()); + onAppObservableStoreChange(); + const personStoreListener = QuestionnaireStore.addListener(onQuestionnaireStoreChange); + onQuestionnaireStoreChange(); + + return () => { + appStateSubscription.unsubscribe(); + personStoreListener.remove(); + }; + }, []); + + return ( + + + + + + + + + ); +}; +EditQuestionnaireForm.propTypes = { + classes: PropTypes.object.isRequired, +}; + +const styles = (theme) => ({ + formControl: { + width: '100%', + }, + saveQuestionnaireButton: { + width: 300, + [theme.breakpoints.down('md')]: { + width: '100%', + }, + }, +}); + +const EditQuestionnaireFormWrapper = styled('div')` +`; + +export default withStyles(styles)(EditQuestionnaireForm); diff --git a/src/js/components/Style/linkStyles.js b/src/js/components/Style/linkStyles.js new file mode 100644 index 0000000..63e0345 --- /dev/null +++ b/src/js/components/Style/linkStyles.js @@ -0,0 +1,10 @@ +import styled from 'styled-components'; +import DesignTokenColors from '../../common/components/Style/DesignTokenColors'; + + +// eslint-disable-next-line import/prefer-default-export +export const SpanWithLinkStyle = styled('span')` + text-decoration: underline; + color: ${DesignTokenColors.primary500}; + cursor: pointer; +`; diff --git a/src/js/components/Team/AddTeamDrawerMainContent.jsx b/src/js/components/Team/AddTeamDrawerMainContent.jsx new file mode 100644 index 0000000..280a36e --- /dev/null +++ b/src/js/components/Team/AddTeamDrawerMainContent.jsx @@ -0,0 +1,109 @@ +import React from 'react'; +import styled from 'styled-components'; +import PropTypes from 'prop-types'; +import { withStyles } from '@mui/styles'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import PersonActions from '../../actions/PersonActions'; +import TeamActions from '../../actions/TeamActions'; +import PersonStore from '../../stores/PersonStore'; +import TeamStore from '../../stores/TeamStore'; +import apiCalming from '../../common/utils/apiCalming'; +import SearchBar2024 from '../../common/components/Search/SearchBar2024'; +import DesignTokenColors from '../../common/components/Style/DesignTokenColors'; +import arrayContains from '../../common/utils/arrayContains'; +import { renderLog } from '../../common/utils/logging'; +import AddTeamForm from './AddTeamForm'; + + +const AddTeamDrawerMainContent = ({ classes }) => { // classes, teamId + renderLog('AddTeamDrawerMainContent'); // Set LOG_RENDER_EVENTS to log all renders + const [allCachedPeopleList, setAllCachedPeopleList] = React.useState([]); + const [searchText, setSearchText] = React.useState(''); + const [personSearchResultsList, setPersonSearchResultsList] = React.useState([]); + const [teamId, setTeamId] = React.useState(-1); + const [teamMemberPersonIdList, setTeamMemberPersonIdList] = React.useState([]); + + const onAppObservableStoreChange = () => { + // console.log('AddTeamDrawerMainContent AppObservableStore-addPersonDrawerTeamId: ', AppObservableStore.getGlobalVariableState('addPersonDrawerTeamId')); + }; + + const onPersonStoreChange = () => { + }; + + const onTeamStoreChange = () => { + // const teamSearchResultsListTemp = TeamStore.getSearchResults(); + }; + + const searchFunction = (incomingSearchText) => { + let searchingJustStarted = false; + if (searchText.length === 0 && incomingSearchText.length > 0) { + searchingJustStarted = true; + } + const isSearching = (incomingSearchText && incomingSearchText.length > 0); + const teamIdTemp = AppObservableStore.getGlobalVariableState('addPersonDrawerTeamId'); + if (apiCalming(`addPersonToTeamSearch-${teamIdTemp}-${incomingSearchText}`, 60000)) { // Only once per 60 seconds + PersonActions.personListRetrieve(incomingSearchText); + } + setSearchText(incomingSearchText); + }; + + const clearFunction = () => { + setPersonSearchResultsList([]); + setSearchText(''); + }; + + React.useEffect(() => { + const appStateSubscription = messageService.getMessage().subscribe(() => onAppObservableStoreChange()); + onAppObservableStoreChange(); + const personStoreListener = PersonStore.addListener(onPersonStoreChange); + onPersonStoreChange(); + const teamStoreListener = TeamStore.addListener(onTeamStoreChange); + onTeamStoreChange(); + + if (apiCalming('teamListRetrieve', 30000)) { + TeamActions.teamListRetrieve(); + } + + return () => { + // console.log('AddTeamDrawerMainContent cleanup'); + appStateSubscription.unsubscribe(); + personStoreListener.remove(); + teamStoreListener.remove(); + }; + }, []); + + return ( + + + + + + + + + ); +}; +AddTeamDrawerMainContent.propTypes = { + classes: PropTypes.object.isRequired, +}; + +const styles = () => ({ +}); + +const AddTeamDrawerMainContentWrapper = styled('div')` +`; + +const AddTeamWrapper = styled('div')` + margin-top: 32px; +`; + +const SearchBarWrapper = styled('div')` + margin-bottom: 16px; +`; + +export default withStyles(styles)(AddTeamDrawerMainContent); diff --git a/src/js/components/Team/AddTeamForm.jsx b/src/js/components/Team/AddTeamForm.jsx index 5a396cb..1858b0c 100644 --- a/src/js/components/Team/AddTeamForm.jsx +++ b/src/js/components/Team/AddTeamForm.jsx @@ -25,7 +25,7 @@ const AddTeamForm = ({ classes }) => { // classes, teamId const onTeamStoreChange = () => { const mostRecentTeamChanged = TeamStore.getMostRecentTeamChanged(); - console.log('AddTeamForm onTeamStoreChange mostRecentTeamChanged:', mostRecentTeamChanged); + // console.log('AddTeamForm onTeamStoreChange mostRecentTeamChanged:', mostRecentTeamChanged); // TODO: Figure out why teamName is not being updated locally // console.log('teamName:', teamName); if (mostRecentTeamChanged.teamName === AppObservableStore.getGlobalVariableState('teamNameToBeSaved')) { @@ -69,21 +69,22 @@ const AddTeamForm = ({ classes }) => { // classes, teamId diff --git a/src/js/components/Team/TeamHeader.jsx b/src/js/components/Team/TeamHeader.jsx new file mode 100644 index 0000000..0f6fb76 --- /dev/null +++ b/src/js/components/Team/TeamHeader.jsx @@ -0,0 +1,78 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import styled from 'styled-components'; +import PropTypes from 'prop-types'; +import { withStyles } from '@mui/styles'; +import { renderLog } from '../../common/utils/logging'; + + +const TeamHeader = ({ classes, showHeaderLabels, team }) => { + renderLog('TeamHeader'); // Set LOG_RENDER_EVENTS to log all renders + + return ( + + {/* Width (below) of this TeamHeaderCell comes from the combined widths of the first x columns in TeamMemberList */} + + {team && ( + + {team.teamName} + + )} + + {showHeaderLabels && ( + + Title / Volunteering Love + + )} + {/* Edit icon */} + {showHeaderLabels && ( + + )} + {/* Delete icon */} + {showHeaderLabels && ( + + )} + + ); +}; +TeamHeader.propTypes = { + classes: PropTypes.object.isRequired, + showHeaderLabels: PropTypes.bool, + team: PropTypes.object.isRequired, +}; + +const styles = (theme) => ({ + ballotButtonIconRoot: { + marginRight: 8, + }, + addTeamButtonRoot: { + width: 120, + [theme.breakpoints.down('md')]: { + width: '100%', + }, + }, +}); + +const OneTeamHeader = styled('div')` + align-items: center; + display: flex; + justify-content: flex-start; + margin-top: 10px; +`; + +const TeamHeaderCell = styled('div', { + shouldForwardProp: (prop) => !['largeFont', 'titleCell', 'width'].includes(prop), +})(({ largeFont, titleCell, width }) => (` + align-content: center; + ${(titleCell) ? '' : 'border-bottom: 1px solid #ccc;'} + ${(largeFont) ? 'font-size: 1.1em;' : 'font-size: .8em;'}; + ${(titleCell) ? '' : 'font-weight: 550;'} + height: 22px; + ${width ? `max-width: ${width}px;` : ''}; + ${width ? `min-width: ${width}px;` : ''}; + overflow: hidden; + white-space: nowrap; + ${width ? `width: ${width}px;` : ''}; +`)); + +export default withStyles(styles)(TeamHeader); diff --git a/src/js/components/Team/TeamMemberList.jsx b/src/js/components/Team/TeamMemberList.jsx index 0df85d7..02846f3 100644 --- a/src/js/components/Team/TeamMemberList.jsx +++ b/src/js/components/Team/TeamMemberList.jsx @@ -1,40 +1,53 @@ import React from 'react'; import styled from 'styled-components'; import PropTypes from 'prop-types'; +import { Edit, Delete } from '@mui/icons-material'; import { withStyles } from '@mui/styles'; +import TeamActions from '../../actions/TeamActions'; import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; import PersonStore from '../../stores/PersonStore'; import TeamStore from '../../stores/TeamStore'; +import DesignTokenColors from '../../common/components/Style/DesignTokenColors'; import { renderLog } from '../../common/utils/logging'; -const TeamMemberList = ({ classes, teamId }) => { +const TeamMemberList = ({ teamId }) => { renderLog('TeamMemberList'); // Set LOG_RENDER_EVENTS to log all renders - const [teamMemberList, setTeamMemberList] = React.useState([]); + // const [teamMemberList, setTeamMemberList] = React.useState([]); const onAppObservableStoreChange = () => { }; const onRetrieveTeamListChange = () => { + // TODO: Why is this 'teamId' value changing to -1 after team-retrieve API returns? // console.log('TeamMemberList onRetrieveTeamListChange, teamId:', teamId, ', TeamStore.getTeamMemberList:', TeamStore.getTeamMemberList(teamId)); - setTeamMemberList(TeamStore.getTeamMemberList(teamId)); + // console.log('TeamStore state:', TeamStore.getState()); + // console.log('TeamMemberList:', TeamStore.getTeamMemberList(teamId)); + // setTeamMemberList(); }; const onPersonStoreChange = () => { - onRetrieveTeamListChange(); + // onRetrieveTeamListChange(); }; const onTeamStoreChange = () => { - onRetrieveTeamListChange(); + // onRetrieveTeamListChange(); + }; + + const editPersonClick = (personId, hasEditRights = true) => { + if (hasEditRights) { + AppObservableStore.setGlobalVariableState('editPersonDrawerOpen', true); + AppObservableStore.setGlobalVariableState('editPersonDrawerPersonId', personId); + } }; - const editPersonClick = (personId) => { - AppObservableStore.setGlobalVariableState('editPersonDrawerOpen', true); - AppObservableStore.setGlobalVariableState('editPersonDrawerPersonId', personId); + const personProfileClick = (personId) => { + AppObservableStore.setGlobalVariableState('personProfileDrawerOpen', true); + AppObservableStore.setGlobalVariableState('personProfileDrawerPersonId', personId); }; React.useEffect(() => { - setTeamMemberList([]); + // setTeamMemberList([]); const appStateSubscription = messageService.getMessage().subscribe(() => onAppObservableStoreChange()); onAppObservableStoreChange(); const personStoreListener = PersonStore.addListener(onPersonStoreChange); @@ -49,14 +62,30 @@ const TeamMemberList = ({ classes, teamId }) => { }; }, []); + React.useEffect(() => { + // console.log('useEffect teamId changed:', teamId); + onRetrieveTeamListChange(); + }, [teamId]); + + const teamMemberList = TeamStore.getTeamMemberList(teamId); + const hasEditRights = true; return ( - {teamMemberList.map((person) => ( + {teamMemberList.map((person, index) => ( + + + {index + 1} + + editPersonClick(person.personId)} - style={{ cursor: 'pointer' }} + onClick={() => personProfileClick(person.personId)} + style={{ + cursor: 'pointer', + textDecoration: 'underline', + color: DesignTokenColors.primary500, + }} width={150} > {PersonStore.getFullNamePreferred(person.personId)} @@ -67,13 +96,46 @@ const TeamMemberList = ({ classes, teamId }) => { {PersonStore.getPersonById(person.personId).jobTitle} + {hasEditRights ? ( + editPersonClick(person.personId, hasEditRights)} + style={{ cursor: 'pointer' }} + width={20} + > + + + ) : ( + +   + + )} + {hasEditRights ? ( + TeamActions.removePersonFromTeam(person.personId, teamId)} + style={{ cursor: 'pointer' }} + width={20} + > + + + ) : ( + +   + + )} ))} ); }; TeamMemberList.propTypes = { - classes: PropTypes.object.isRequired, teamId: PropTypes.number.isRequired, }; @@ -89,6 +151,23 @@ const styles = (theme) => ({ }, }); +const DeleteStyled = styled(Delete)` + color: ${DesignTokenColors.neutral200}; + width: 20px; + height: 20px; +`; + +const EditStyled = styled(Edit)` + color: ${DesignTokenColors.neutral100}; + height: 16px; + margin-left: 2px; + width: 16px; +`; + +const GraySpan = styled('span')` + color: ${DesignTokenColors.neutral400}; +`; + const OnePersonWrapper = styled('div')` display: flex; align-items: center; diff --git a/src/js/config-template.js b/src/js/config-template.js index 5b14bfa..a0eaabb 100644 --- a/src/js/config-template.js +++ b/src/js/config-template.js @@ -3,6 +3,7 @@ module.exports = { // weconnect React server for the "weconnect" web app NAME_FOR_BROWSER_TAB_TITLE: 'WeConnect', + ORGANIZATION_NAME: 'WeVote', PROTOCOL: 'http://', // 'http://' for local dev (if not using SSL), or 'https://' for live server HOSTNAME: 'localhost:4000', // Don't add 'http...' here. Live server: 'WeVote.US', Quality: 'quality.WeVote.US', developers: 'localhost:4000' PORT: 'localhost:4000', // Don't add 'http...' here. Live server: 'WeVote.US', Quality: 'quality.WeVote.US', developers: 'localhost:4000' diff --git a/src/js/pages/AnswerQuestionsForm.jsx b/src/js/pages/AnswerQuestionsForm.jsx new file mode 100644 index 0000000..9105d2a --- /dev/null +++ b/src/js/pages/AnswerQuestionsForm.jsx @@ -0,0 +1,210 @@ +import { Button, 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 AppObservableStore, { messageService } from '../stores/AppObservableStore'; +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 AnswerQuestionsForm = ({ classes, match }) => { + renderLog('AnswerQuestionsForm'); // Set LOG_RENDER_EVENTS to log all renders + const [questionList, setQuestionList] = React.useState([]); + const [questionnaire, setQuestionnaire] = React.useState({}); + const [questionnaireCount, setQuestionnaireCount] = React.useState(0); + const [questionnaireId, setQuestionnaireId] = React.useState(-1); + const [saveButtonActive, setSaveButtonActive] = React.useState(false); + const [inputValues, setInputValues] = React.useState({}); + + const onAppObservableStoreChange = () => { + }; + + 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 saveAnswers = () => { + const { params } = match; + const personIdTemp = convertToInteger(params.personId); + const questionnaireIdTemp = convertToInteger(params.questionnaireId); + + console.log('saveAnswers inputValues:', inputValues); + const data = { ...inputValues }; + // 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); + + return ( +
+ + + Questionnaire For You - + {' '} + {webAppConfig.NAME_FOR_BROWSER_TAB_TITLE} + + + + + {questionnaire.questionnaireTitle && ( + + {questionnaire.questionnaireTitle} + + )} + {questionnaire.questionnaireInstructions && ( + + {questionnaire.questionnaireInstructions} + + )} + + {questionList.map((question) => ( + + + {question.questionText} + {question.requireAnswer && *} + + {question.questionInstructions && ( + + {question.questionInstructions} + + )} + + + + + ))} + + + + + +
+ ); +}; +AnswerQuestionsForm.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 InstructionsWrapper = styled('div')` + color: ${DesignTokenColors.neutralUI300}; + font-size: 1.2em; +`; + +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 SaveButtonWrapper = styled('div')` + margin-top: 24px; +`; + +const TitleWrapper = styled('h1')` + margin-bottom: 8px; +`; + +export default withStyles(styles)(AnswerQuestionsForm); diff --git a/src/js/pages/SystemSettings/Questionnaire.jsx b/src/js/pages/SystemSettings/Questionnaire.jsx new file mode 100644 index 0000000..024e358 --- /dev/null +++ b/src/js/pages/SystemSettings/Questionnaire.jsx @@ -0,0 +1,202 @@ +import { Edit } from '@mui/icons-material'; +import { Button } from '@mui/material'; +import React from 'react'; +import { Helmet } from 'react-helmet-async'; +import { Link } from 'react-router-dom'; +import styled from 'styled-components'; +import PropTypes from 'prop-types'; +import { withStyles } from '@mui/styles'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import QuestionnaireActions from '../../actions/QuestionnaireActions'; +import QuestionnaireStore from '../../stores/QuestionnaireStore'; +import { SpanWithLinkStyle } from '../../components/Style/linkStyles'; +import { PageContentContainer } from '../../components/Style/pageLayoutStyles'; +import DesignTokenColors from '../../common/components/Style/DesignTokenColors'; +import webAppConfig from '../../config'; +import apiCalming from '../../common/utils/apiCalming'; +import { renderLog } from '../../common/utils/logging'; +import convertToInteger from '../../common/utils/convertToInteger'; + + +const Questionnaire = ({ classes, match }) => { + renderLog('Questionnaire'); // Set LOG_RENDER_EVENTS to log all renders + const [questionList, setQuestionList] = React.useState([]); + const [questionnaire, setQuestionnaire] = React.useState({}); + const [questionnaireCount, setQuestionnaireCount] = React.useState(0); + + const onAppObservableStoreChange = () => { + }; + + const onQuestionnaireStoreChange = () => { + const { params } = match; + const questionnaireIdTemp = convertToInteger(params.questionnaireId); + const questionnaireTemp = QuestionnaireStore.getQuestionnaireById(questionnaireIdTemp); + setQuestionnaire(questionnaireTemp); + const questionListTemp = QuestionnaireStore.getQuestionListByQuestionnaireId(questionnaireIdTemp); + // console.log('Questionnaire QuestionnaireStore.getQuestionList:', questionListTemp); + setQuestionList(questionListTemp); + setQuestionnaireCount(questionListTemp.length); + }; + + const addQuestionClick = () => { + const { params } = match; + const questionnaireIdTemp = convertToInteger(params.questionnaireId); + AppObservableStore.setGlobalVariableState('editQuestionDrawerOpen', true); + AppObservableStore.setGlobalVariableState('editQuestionDrawerQuestionId', -1); + AppObservableStore.setGlobalVariableState('editQuestionDrawerQuestionnaireId', questionnaireIdTemp); + }; + + const editQuestionClick = (questionId) => { + const { params } = match; + const questionnaireIdTemp = convertToInteger(params.questionnaireId); + AppObservableStore.setGlobalVariableState('editQuestionDrawerOpen', true); + AppObservableStore.setGlobalVariableState('editQuestionDrawerQuestionId', questionId); + AppObservableStore.setGlobalVariableState('editQuestionDrawerQuestionnaireId', questionnaireIdTemp); + }; + + const editQuestionnaireClick = () => { + const { params } = match; + const questionnaireIdTemp = convertToInteger(params.questionnaireId); + AppObservableStore.setGlobalVariableState('editQuestionnaireDrawerOpen', true); + AppObservableStore.setGlobalVariableState('editQuestionnaireDrawerQuestionnaireId', questionnaireIdTemp); + }; + + 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', 1000)) { + QuestionnaireActions.questionnaireListRetrieve(); + } + if (apiCalming(`questionListRetrieve-${questionnaireIdTemp}`, 1000)) { + QuestionnaireActions.questionListRetrieve(questionnaireIdTemp); + } + } + + return () => { + appStateSubscription.unsubscribe(); + questionnaireStoreListener.remove(); + }; + }, []); + + const { params } = match; + const questionnaireIdTemp = convertToInteger(params.questionnaireId); + + return ( +
+ + + Questionnaire Details - + {' '} + {webAppConfig.NAME_FOR_BROWSER_TAB_TITLE} + + + + +
+ Questionnaires + {' '} + > + {' '} + {questionnaire.questionnaireName} + + + +
+ {questionnaire.questionnaireTitle && ( + + {questionnaire.questionnaireTitle} + + )} + {questionnaire.questionnaireInstructions && ( + + {questionnaire.questionnaireInstructions} + + )} + + {questionList.map((question) => ( + + {question.questionText} + {' '} + {question.requireAnswer && ( + * + )} + editQuestionClick(question.id)}> + + + + ))} + + + + +
+
+ ); +}; +Questionnaire.propTypes = { + classes: PropTypes.object.isRequired, + match: PropTypes.object.isRequired, +}; + +const styles = (theme) => ({ + ballotButtonIconRoot: { + marginRight: 8, + }, + addQuestionnaireButtonRoot: { + width: 185, + [theme.breakpoints.down('md')]: { + width: '100%', + }, + }, +}); + +const AddButtonWrapper = styled('div')` + margin-top: 24px; +`; + +const EditStyled = styled(Edit)` + color: ${DesignTokenColors.neutral100}; + height: 16px; + margin-left: 2px; + width: 16px; +`; + +const InstructionsWrapper = styled('div')` + color: ${DesignTokenColors.neutralUI300}; + font-size: 1.2em; +`; + +const OneQuestionnaireWrapper = styled('div')` + margin-bottom: 20px; +`; + +const QuestionListWrapper = styled('div')` + margin-top: 24px; + padding-bottom: 24px; +`; + +const RequiredStar = styled('span')` + color: ${DesignTokenColors.alert800}; + font-weight: bold; +`; + +const TitleWrapper = styled('h1')` + line-height: 1.1; + margin-bottom: 8px; +`; + +export default withStyles(styles)(Questionnaire); diff --git a/src/js/pages/SystemSettings/SystemSettings.jsx b/src/js/pages/SystemSettings/SystemSettings.jsx new file mode 100644 index 0000000..2d03e79 --- /dev/null +++ b/src/js/pages/SystemSettings/SystemSettings.jsx @@ -0,0 +1,145 @@ +import { Button } from '@mui/material'; +import React from 'react'; +import { Helmet } from 'react-helmet-async'; +import { Link } from 'react-router-dom'; +import styled from 'styled-components'; +import PropTypes from 'prop-types'; +import { withStyles } from '@mui/styles'; +import AppObservableStore, { messageService } from '../../stores/AppObservableStore'; +import QuestionnaireActions from '../../actions/QuestionnaireActions'; +import QuestionnaireStore from '../../stores/QuestionnaireStore'; +import { PageContentContainer } from '../../components/Style/pageLayoutStyles'; +import webAppConfig from '../../config'; +import apiCalming from '../../common/utils/apiCalming'; +import { renderLog } from '../../common/utils/logging'; +import { Edit } from "@mui/icons-material"; +import DesignTokenColors from "../../common/components/Style/DesignTokenColors"; + + +const SystemSettings = ({ classes }) => { + renderLog('SystemSettings'); // Set LOG_RENDER_EVENTS to log all renders + const [questionnaireList, setQuestionnaireList] = React.useState([]); + const [questionnaireCount, setQuestionnaireCount] = React.useState(0); + + const onAppObservableStoreChange = () => { + }; + + const onQuestionnaireStoreChange = () => { + const questionnaireListTemp = QuestionnaireStore.getAllCachedQuestionnairesList(); + // console.log('SystemSettings QuestionnaireStore.getQuestionnaireList:', questionnaireListTemp); + setQuestionnaireList(questionnaireListTemp); + setQuestionnaireCount(questionnaireListTemp.length); + if (apiCalming('questionnaireListRetrieve', 1000)) { + QuestionnaireActions.questionnaireListRetrieve(); + } + }; + + const addQuestionnaireClick = () => { + AppObservableStore.setGlobalVariableState('editQuestionnaireDrawerOpen', true); + AppObservableStore.setGlobalVariableState('editQuestionnaireDrawerQuestionnaireId', -1); + }; + + const editQuestionnaireClick = (questionnaireId) => { + AppObservableStore.setGlobalVariableState('editQuestionnaireDrawerOpen', true); + AppObservableStore.setGlobalVariableState('editQuestionnaireDrawerQuestionnaireId', questionnaireId); + }; + + React.useEffect(() => { + const appStateSubscription = messageService.getMessage().subscribe(() => onAppObservableStoreChange()); + onAppObservableStoreChange(); + const personStoreListener = QuestionnaireStore.addListener(onQuestionnaireStoreChange); + onQuestionnaireStoreChange(); + + if (apiCalming('questionnaireListRetrieve', 1000)) { + QuestionnaireActions.questionnaireListRetrieve(); + } + + return () => { + appStateSubscription.unsubscribe(); + personStoreListener.remove(); + }; + }, []); + + return ( +
+ + + System Settings - + {' '} + {webAppConfig.NAME_FOR_BROWSER_TAB_TITLE} + + + + +
+ System Settings - + {' '} + home +
+ {questionnaireList.map((questionnaire) => ( + + + + {questionnaire.questionnaireName} + + editQuestionnaireClick(questionnaire.questionnaireId)}> + + + + + ))} + + + +
+
+ ); +}; +SystemSettings.propTypes = { + classes: PropTypes.object.isRequired, +}; + +const styles = (theme) => ({ + ballotButtonIconRoot: { + marginRight: 8, + }, + addQuestionnaireButtonRoot: { + width: 185, + [theme.breakpoints.down('md')]: { + width: '100%', + }, + }, +}); + +const AddButtonWrapper = styled('div')` + margin-top: 24px; +`; + +const EditQuestionnaire = styled('div')` +`; + +const EditStyled = styled(Edit)` + color: ${DesignTokenColors.neutral100}; + height: 16px; + margin-left: 2px; + width: 16px; +`; + +const OneQuestionnaireWrapper = styled('div')` +`; + +const QuestionnaireInnerWrapper = styled('div')` + display: flex; + align-items: center; + justify-content: flex-start; + margin-bottom: 6px; +`; + +export default withStyles(styles)(SystemSettings); diff --git a/src/js/pages/TeamMembers.jsx b/src/js/pages/TeamHome.jsx similarity index 55% rename from src/js/pages/TeamMembers.jsx rename to src/js/pages/TeamHome.jsx index 28e0778..a4045b3 100644 --- a/src/js/pages/TeamMembers.jsx +++ b/src/js/pages/TeamHome.jsx @@ -10,56 +10,58 @@ import PersonStore from '../stores/PersonStore'; import TeamActions from '../actions/TeamActions'; import TeamStore from '../stores/TeamStore'; import { PageContentContainer } from '../components/Style/pageLayoutStyles'; +import TeamHeader from '../components/Team/TeamHeader'; +import TeamMemberList from '../components/Team/TeamMemberList'; import webAppConfig from '../config'; import apiCalming from '../common/utils/apiCalming'; -import arrayContains from '../common/utils/arrayContains'; -import DesignTokenColors from '../common/components/Style/DesignTokenColors'; +import convertToInteger from '../common/utils/convertToInteger'; import { renderLog } from '../common/utils/logging'; -const TeamMembers = ({ classes, match }) => { // classes, teamId - renderLog('TeamMembers'); // Set LOG_RENDER_EVENTS to log all renders +const TeamHome = ({ classes, match }) => { // classes, teamId + renderLog('TeamHome'); // Set LOG_RENDER_EVENTS to log all renders const [team, setTeam] = React.useState({}); const [teamId, setTeamId] = React.useState(-1); - const [teamMemberCount, setTeamMemberCount] = React.useState(0); - const [teamMemberList, setTeamMemberList] = React.useState([]); - const [teamMemberPersonIdList, setTeamMemberPersonIdList] = React.useState([]); const onAppObservableStoreChange = () => { }; - const onRetrieveTeamChange = () => { - const { params } = match; - setTeamId(params.teamId); - const teamTemp = TeamStore.getTeamById(params.teamId); + const onRetrieveTeamChange = (teamIdIncoming) => { + // console.log('TeamHome onRetrieveTeamChange, teamIdIncoming:', teamIdIncoming); + const teamTemp = TeamStore.getTeamById(teamIdIncoming); setTeam(teamTemp); - const teamMemberListTemp = TeamStore.getTeamMemberList(params.teamId); - // console.log('TeamMembers onRetrieveTeamChange, params.teamId:', params.teamId, ', TeamStore.getTeamMemberList:', teamMemberListTemp); - setTeamMemberCount(teamMemberListTemp.length); - setTeamMemberList(teamMemberListTemp); - setTeamMemberPersonIdList(TeamStore.getTeamMemberPersonIdList(params.teamId)); }; const onPersonStoreChange = () => { const { params } = match; - onRetrieveTeamChange(); - if (apiCalming(`teamRetrieve-${params.teamId}`, 1000)) { - TeamActions.teamRetrieve(params.teamId); + const teamIdTemp = convertToInteger(params.teamId); + if (teamIdTemp >= 0) { + setTeamId(teamIdTemp); + } + onRetrieveTeamChange(teamIdTemp); + if (apiCalming(`teamRetrieve-${teamIdTemp}`, 1000)) { + TeamActions.teamRetrieve(teamIdTemp); } }; const onTeamStoreChange = () => { - onRetrieveTeamChange(); + const { params } = match; + const teamIdTemp = convertToInteger(params.teamId); + if (teamIdTemp >= 0) { + setTeamId(teamIdTemp); + } + onRetrieveTeamChange(teamIdTemp); }; const addTeamMemberClick = () => { - const { params } = match; + // console.log('TeamHome addTeamMemberClick, teamId:', teamId); AppObservableStore.setGlobalVariableState('addPersonDrawerOpen', true); - AppObservableStore.setGlobalVariableState('addPersonDrawerTeamId', params.teamId); + AppObservableStore.setGlobalVariableState('addPersonDrawerTeamId', teamId); }; React.useEffect(() => { const { params } = match; + const teamIdTemp = convertToInteger(params.teamId); const appStateSubscription = messageService.getMessage().subscribe(() => onAppObservableStoreChange()); onAppObservableStoreChange(); @@ -68,8 +70,10 @@ const TeamMembers = ({ classes, match }) => { // classes, teamId const teamStoreListener = TeamStore.addListener(onTeamStoreChange); onTeamStoreChange(); - if (apiCalming(`teamRetrieve-${params.teamId}`, 1000)) { - TeamActions.teamRetrieve(params.teamId); + if (teamIdTemp >= 0) { + if (apiCalming(`teamRetrieve-${teamIdTemp}`, 1000)) { + TeamActions.teamRetrieve(teamIdTemp); + } } return () => { @@ -83,23 +87,21 @@ const TeamMembers = ({ classes, match }) => { // classes, teamId
- Team Members - + Team Home - {' '} {webAppConfig.NAME_FOR_BROWSER_TAB_TITLE} - +
- Team Members for + Team Home for {' '} {team.teamName} {' '} - ( - {teamMemberCount} - ) - + - {' '} - home + team list
- {teamMemberList.map((teamMember) => ( - - {teamMember.firstName} - {' '} - {teamMember.lastName} - {arrayContains(teamMember.personId, teamMemberPersonIdList) && ( - <> - {' '} - TeamActions.removePersonFromTeam(teamMember.personId, teamId)}>remove - - )} - - ))} + 0)} /> +
); }; -TeamMembers.propTypes = { +TeamHome.propTypes = { classes: PropTypes.object.isRequired, // teamId: PropTypes.number.isRequired, match: PropTypes.object.isRequired, @@ -144,13 +135,7 @@ const styles = (theme) => ({ }, }); -const SpanWithLinkStyle = styled('span')` - text-decoration: underline; - color: ${DesignTokenColors.primary500}; - cursor: pointer; -`; - const TeamMember = styled('div')` `; -export default withStyles(styles)(TeamMembers); +export default withStyles(styles)(TeamHome); diff --git a/src/js/pages/Teams.jsx b/src/js/pages/Teams.jsx index f9ef5bd..036f070 100644 --- a/src/js/pages/Teams.jsx +++ b/src/js/pages/Teams.jsx @@ -9,12 +9,13 @@ import AppObservableStore, { messageService } from '../stores/AppObservableStore import PersonStore from '../stores/PersonStore'; import TeamActions from '../actions/TeamActions'; import TeamStore from '../stores/TeamStore'; +import { SpanWithLinkStyle } from '../components/Style/linkStyles'; import { PageContentContainer } from '../components/Style/pageLayoutStyles'; +import TeamHeader from '../components/Team/TeamHeader'; import TeamMemberList from '../components/Team/TeamMemberList'; import webAppConfig from '../config'; import apiCalming from '../common/utils/apiCalming'; import { renderLog } from '../common/utils/logging'; -import DesignTokenColors from '../common/components/Style/DesignTokenColors'; const Teams = ({ classes, match }) => { // classes, teamId @@ -77,7 +78,7 @@ const Teams = ({ classes, match }) => { // classes, teamId {' '} {webAppConfig.NAME_FOR_BROWSER_TAB_TITLE} - +
@@ -90,6 +91,10 @@ const Teams = ({ classes, match }) => { // classes, teamId ) : ( setShowAllTeamMembers(true)}>show people )} + {' '} + - + {' '} + settings
- {teamList.map((team) => ( + {teamList.map((team, index) => ( - - - - {team.teamName} - - - {showAllTeamMembers && ( - - Title / Volunteering Love - - )} - + 0)} /> {showAllTeamMembers && ( )} @@ -150,35 +144,7 @@ const styles = (theme) => ({ }, }); -const OneTeamHeader = styled('div')` - align-items: center; - display: flex; - justify-content: flex-start; - margin-top: 10px; -`; - const OneTeamWrapper = styled('div')` `; -const SpanWithLinkStyle = styled('span')` - text-decoration: underline; - color: ${DesignTokenColors.primary500}; - cursor: pointer; -`; - -const TeamHeaderCell = styled('div', { - shouldForwardProp: (prop) => !['largeFont', 'titleCell', 'width'].includes(prop), -})(({ largeFont, titleCell, width }) => (` - align-content: center; - ${(titleCell) ? '' : 'border-bottom: 1px solid #ccc;'} - ${(largeFont) ? 'font-size: 1.1em;' : 'font-size: .8em;'}; - ${(titleCell) ? '' : 'font-weight: 550;'} - height: 22px; - ${width ? `max-width: ${width}px;` : ''}; - ${width ? `min-width: ${width}px;` : ''}; - overflow: hidden; - white-space: nowrap; - ${width ? `width: ${width}px;` : ''}; -`)); - export default withStyles(styles)(Teams); diff --git a/src/js/stores/QuestionnaireStore.js b/src/js/stores/QuestionnaireStore.js new file mode 100644 index 0000000..99938de --- /dev/null +++ b/src/js/stores/QuestionnaireStore.js @@ -0,0 +1,225 @@ +import { ReduceStore } from 'flux/utils'; +import Dispatcher from '../common/dispatcher/Dispatcher'; + +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 + mostRecentQuestionIdSaved: -1, + mostRecentQuestionSaved: { + questionnaireId: -1, + }, + mostRecentQuestionnaireIdSaved: -1, + mostRecentQuestionnaireSaved: { + firstName: '', + lastName: '', + questionnaireId: -1, + }, + searchResults: [], + }; + } + + getAllCachedQuestionnairesList () { + const { allCachedQuestionnairesDict } = this.getState(); + const questionnaireListRaw = Object.values(allCachedQuestionnairesDict); + + const questionnaireList = []; + let questionnaireFiltered; + let questionnaireRaw; + for (let i = 0; i < questionnaireListRaw.length; i++) { + questionnaireRaw = questionnaireListRaw[i]; + // console.log('QuestionnaireStore getAllCachedQuestionnairesList questionnaire:', questionnaire); + questionnaireFiltered = questionnaireRaw; + questionnaireList.push(questionnaireFiltered); + } + return questionnaireList; + } + + getFirstName (questionnaireId) { + const questionnaire = this.getQuestionnaireById(questionnaireId); + return questionnaire.firstName || ''; + } + + getLastName (questionnaireId) { + const questionnaire = this.getQuestionnaireById(questionnaireId); + return questionnaire.lastName || ''; + } + + getMostRecentQuestionnaireChanged () { + // console.log('QuestionnaireStore getMostRecentQuestionnaireChanged Id:', this.getState().mostRecentQuestionnaireIdSaved); + if (this.getState().mostRecentQuestionnaireIdSaved !== -1) { + return this.getQuestionnaireById(this.getState().mostRecentQuestionnaireIdSaved); + } + return {}; + } + + getMostRecentQuestionnaireIdChanged () { + // console.log('QuestionnaireStore getMostRecentQuestionnaireChanged Id:', this.getState().mostRecentQuestionnaireIdSaved); + return this.getState().mostRecentQuestionnaireIdSaved; + } + + getQuestionListByQuestionnaireId (questionnaireId) { + const { allCachedQuestionsDict } = this.getState(); + const questionListRaw = Object.values(allCachedQuestionsDict); + const questionListForQuestionnaire = []; + for (let i = 0; i < questionListRaw.length; i++) { + if (questionListRaw[i].questionnaireId === questionnaireId) { + questionListForQuestionnaire.push(questionListRaw[i]); + } + } + // console.log('QuestionnaireStore getQuestionnaireById:', questionnaireId, ', questionListForQuestionnaire:', questionListForQuestionnaire); + return questionListForQuestionnaire; + } + + getQuestionById (questionId) { + const { allCachedQuestionsDict } = this.getState(); + // console.log('QuestionnaireStore getQuestionById:', questionId, ', allCachedQuestionsDict:', allCachedQuestionsDict); + return allCachedQuestionsDict[questionId] || {}; + } + + getQuestionnaireById (questionnaireId) { + const { allCachedQuestionnairesDict } = this.getState(); + // console.log('QuestionnaireStore getQuestionnaireById:', questionnaireId, ', allCachedQuestionnairesDict:', allCachedQuestionnairesDict); + return allCachedQuestionnairesDict[questionnaireId] || {}; + } + + getSearchResults () { + // console.log('QuestionnaireStore getSearchResults:', this.getState().searchResults); + return this.getState().searchResults || []; + } + + reduce (state, action) { + const { allCachedQuestionsDict, allCachedQuestionnairesDict } = state; + // let questionnaireTemp = {}; + let questionId = -1; + let questionnaireId = -1; + let revisedState = state; + let searchResults = []; + + switch (action.type) { + case 'question-list-retrieve': + if (!action.res.success) { + console.log('QuestionnaireStore ', action.type, ' FAILED action.res:', action.res); + return state; + } + revisedState = state; + // console.log('QuestionnaireStore question-list-retrieve questionList:', action.res.questionList); + if (action.res.isSearching && action.res.isSearching === true) { + // console.log('QuestionnaireStore isSearching:', action.res.isSearching); + searchResults = action.res.questionList; + // console.log('QuestionnaireStore searchResults:', searchResults); + revisedState = { + ...revisedState, + searchResults, + }; + } + if (action.res.questionList) { + action.res.questionList.forEach((question) => { + // console.log('QuestionnaireStore team-retrieve adding question:', question); + if (question && (question.id >= 0)) { + allCachedQuestionsDict[question.id] = question; + } + }); + // console.log('allCachedQuestionsDict:', allCachedQuestionsDict); + revisedState = { + ...revisedState, + allCachedQuestionsDict, + }; + } + // console.log('QuestionnaireStore revisedState:', revisedState); + return revisedState; + + case 'question-save': + if (!action.res.success) { + console.log('QuestionnaireStore ', action.type, ' FAILED action.res:', action.res); + return state; + } + revisedState = state; + if (action.res.questionId >= 0) { + questionId = action.res.questionId; + } else { + questionId = -1; + } + + if (questionId >= 0) { + if (action.res.questionCreated || action.res.questionUpdated) { + // console.log('QuestionnaireStore question-save questionId:', questionId); + allCachedQuestionsDict[questionId] = action.res; + revisedState = { + ...revisedState, + allCachedQuestionsDict, + mostRecentQuestionIdSaved: questionId, + }; + } else { + console.log('QuestionnaireStore question-save NOT updated or saved.'); + } + } else { + console.log('QuestionnaireStore question-save MISSING questionId:', questionId); + } + return revisedState; + + case 'questionnaire-list-retrieve': + if (!action.res.success) { + console.log('QuestionnaireStore ', action.type, ' FAILED action.res:', action.res); + return state; + } + revisedState = state; + // console.log('QuestionnaireStore questionnaire-list-retrieve questionnaireList:', action.res.questionnaireList); + if (action.res.isSearching && action.res.isSearching === true) { + // console.log('QuestionnaireStore isSearching:', action.res.isSearching); + searchResults = action.res.questionnaireList; + // console.log('QuestionnaireStore searchResults:', searchResults); + revisedState = { + ...revisedState, + searchResults, + }; + } + if (action.res.questionnaireList) { + action.res.questionnaireList.forEach((questionnaire) => { + // console.log('QuestionnaireStore team-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-save': + if (!action.res.success) { + console.log('QuestionnaireStore ', action.type, ' FAILED action.res:', action.res); + return state; + } + revisedState = state; + if (action.res.questionnaireId >= 0) { + questionnaireId = action.res.questionnaireId; + } else { + questionnaireId = -1; + } + + if (questionnaireId >= 0) { + // console.log('QuestionnaireStore questionnaire-save questionnaireId:', questionnaireId); + allCachedQuestionnairesDict[questionnaireId] = action.res; + revisedState = { + ...revisedState, + allCachedQuestionnairesDict, + mostRecentQuestionnaireIdSaved: questionnaireId, + }; + } else { + console.log('QuestionnaireStore questionnaire-save MISSING questionnaireId:', questionnaireId); + } + return revisedState; + + default: + return state; + } + } +} + +export default new QuestionnaireStore(Dispatcher); diff --git a/src/js/stores/TeamStore.js b/src/js/stores/TeamStore.js index f989f36..b46797e 100644 --- a/src/js/stores/TeamStore.js +++ b/src/js/stores/TeamStore.js @@ -2,6 +2,7 @@ import { ReduceStore } from 'flux/utils'; import Dispatcher from '../common/dispatcher/Dispatcher'; import PersonStore from './PersonStore'; import arrayContains from '../common/utils/arrayContains'; +import convertToInteger from '../common/utils/convertToInteger'; class TeamStore extends ReduceStore { getInitialState () { @@ -18,7 +19,7 @@ class TeamStore extends ReduceStore { } getMostRecentTeamChanged () { - console.log('TeamStore getMostRecentTeamChanged Id:', this.getState().mostRecentTeamIdSaved); + // console.log('TeamStore getMostRecentTeamChanged Id:', this.getState().mostRecentTeamIdSaved); if (this.getState().mostRecentTeamIdSaved !== -1) { return this.getTeamById(this.getState().mostRecentTeamIdSaved); } @@ -75,8 +76,10 @@ class TeamStore extends ReduceStore { reduce (state, action) { const { allCachedTeamMembersDict, allCachedTeamsDict } = state; let personId = -1; + let personIdTemp = -1; let revisedState = state; let teamId = -1; + let teamIdTemp = -1; let teamList = []; let teamMemberList = []; let teamMemberIdList = []; @@ -89,8 +92,9 @@ class TeamStore extends ReduceStore { } revisedState = state; // console.log('TeamStore add-person-to-team action.res: ', action.res); - if (action.res.personId >= 0) { - personId = action.res.personId; + personIdTemp = convertToInteger(action.res.personId); + if (personIdTemp >= 0) { + personId = personIdTemp; } else { personId = -1; } @@ -126,13 +130,15 @@ class TeamStore extends ReduceStore { } revisedState = state; // console.log('TeamStore add-person-to-team action.res: ', action.res); - if (action.res.personId >= 0) { - personId = action.res.personId; + personIdTemp = convertToInteger(action.res.personId); + if (personIdTemp >= 0) { + personId = personIdTemp; } else { personId = -1; } - if (action.res.teamId >= 0) { - teamId = action.res.teamId; + teamIdTemp = convertToInteger(action.res.teamId); + if (teamIdTemp >= 0) { + teamId = teamIdTemp; } else { teamId = -1; } @@ -190,11 +196,14 @@ class TeamStore extends ReduceStore { console.log('TeamStore ', action.type, ' FAILED action.res:', action.res); return state; } - if (action.res.teamId >= 0) { - teamId = action.res.teamId; + teamIdTemp = convertToInteger(action.res.teamId); + if (teamIdTemp >= 0) { + teamId = teamIdTemp; } else { teamId = -1; + console.log('TeamStore team-retrieve MISSING teamId: ', teamId); } + // console.log('TeamStore team-retrieve teamId:', teamId); teamMemberIdList = []; revisedState = state; @@ -230,13 +239,14 @@ class TeamStore extends ReduceStore { return state; } revisedState = state; - if (action.res.teamId >= 0) { - teamId = action.res.teamId; + teamIdTemp = convertToInteger(action.res.teamId); + if (teamIdTemp >= 0) { + teamId = teamIdTemp; } else { teamId = -1; } if (teamId >= 0) { - console.log('TeamStore team-save teamId:', teamId); + // console.log('TeamStore team-save teamId:', teamId); allCachedTeamsDict[teamId] = action.res; if (action.res.teamMemberList) { // If missing teamMemberList do not alter data in the store