Skip to content

Commit

Permalink
Merge pull request #33 from DaleMcGrew/Dale_WCC_Feb18-2025
Browse files Browse the repository at this point in the history
Continued extending viewerCanSeeOrDo & viewerAccessRights implementation. We can now control ability to edit a person based on whether they are in a team the viewer is a teamAdmin for. Now displaying Answers to questionnaires again. Moved ability to delete a team onto the TeamHome page, so it's harder to delete accidentally.
  • Loading branch information
DaleMcGrew authored Feb 23, 2025
2 parents 8cf9d67 + a5f2067 commit 840c69a
Show file tree
Hide file tree
Showing 14 changed files with 193 additions and 93 deletions.
2 changes: 1 addition & 1 deletion src/js/components/Drawers/DrawerTemplateA.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const DrawerTemplateA = (props) => {

// eslint-disable-next-line no-unused-vars
const [scrolledDown, setScrolledDown] = useState(false);
const drawerOpen = getAppContextValue(drawerOpenGlobalVariableName);
const drawerOpen = getAppContextValue(drawerOpenGlobalVariableName) || false;

// console.log('DrawerTemplateA drawerOpen: ', drawerOpenGlobalVariableName, drawerOpen);

Expand Down
8 changes: 6 additions & 2 deletions src/js/components/Navigation/HeaderBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { normalizedHrefPage } from '../../common/utils/hrefUtils';
import { renderLog } from '../../common/utils/logging';
import { useConnectAppContext } from '../../contexts/ConnectAppContext';
import { clearSignedInGlobals } from '../../contexts/contextFunctions';
import { viewerCanSeeOrDo } from '../../models/AuthModel';
import { useLogoutMutation } from '../../react-query/mutations';
import weConnectQueryFn, { METHOD } from '../../react-query/WeConnectQuery';
import { displayTopMenuShadow } from '../../utils/applicationUtils';
Expand All @@ -21,7 +22,8 @@ import HeaderBarLogo from './HeaderBarLogo';
const HeaderBar = ({ hideTabs }) => {
renderLog('HeaderBar');
const navigate = useNavigate();
const { getAppContextValue, setAppContextValue } = useConnectAppContext();
const { apiDataCache, getAppContextValue, setAppContextValue } = useConnectAppContext();
const { viewerAccessRights } = apiDataCache;
const { mutate: mutateLogout } = useLogoutMutation();

const [scrolledDown] = useState(false);
Expand Down Expand Up @@ -141,7 +143,9 @@ const HeaderBar = ({ hideTabs }) => {
>
<Tab value="1" label="Dashboard" onClick={() => handleTabChangeClick('1')} />
<Tab value="2" label="Teams" onClick={() => handleTabChangeClick('2')} />
<Tab value="3" label="Settings" onClick={() => handleTabChangeClick('3')} />
{viewerCanSeeOrDo('canViewSystemSettings', viewerAccessRights) && (
<Tab value="3" label="Settings" onClick={() => handleTabChangeClick('3')} />
)}
</Tabs>
)}
</TopRowOneMiddleContainer>
Expand Down
7 changes: 4 additions & 3 deletions src/js/components/Person/PersonSummaryRow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import {
} from '../../models/PersonModel';
import { useRemoveTeamMemberMutation } from '../../react-query/mutations';
import { DeleteStyled, EditStyled } from '../Style/iconStyles';
import { viewerCanSeeOrDo } from '../../models/AuthModel';
import { viewerCanSeeOrDo, viewerCanSeeOrDoForThisTeam } from '../../models/AuthModel';
// import { useRemoveTeamMemberMutationDiverged } from '../../models/TeamModel';


const PersonSummaryRow = ({ person, rowNumberForDisplay, teamId }) => {
renderLog('PersonSummaryRow'); // Set LOG_RENDER_EVENTS to log all renders
const { apiDataCache, setAppContextValue } = useConnectAppContext();
const { viewerAccessRights } = apiDataCache;
const { viewerAccessRights, viewerTeamAccessRights } = apiDataCache;
const { mutate } = useRemoveTeamMemberMutation();

// const [person, setPerson] = useState(useGetPersonById(personId)); 2/5/2025 does not work
Expand Down Expand Up @@ -50,6 +50,7 @@ const PersonSummaryRow = ({ person, rowNumberForDisplay, teamId }) => {
// }
// }, [apiDataCache]);

const canEditPerson = viewerCanSeeOrDo('canEditPersonAnyone', viewerAccessRights) || viewerCanSeeOrDoForThisTeam('canEditPersonThisTeam', teamId, viewerTeamAccessRights);
const hasEditRights = true;
return (
<OnePersonWrapper key={`teamMember-${person.personId}`}>
Expand Down Expand Up @@ -91,7 +92,7 @@ const PersonSummaryRow = ({ person, rowNumberForDisplay, teamId }) => {
>
{person.jobTitle}
</PersonCell>
{viewerCanSeeOrDo('canEditPersonAnyone', viewerAccessRights) ? (
{canEditPerson ? (
<PersonCell
id={`editPerson-personId-${person.personId}`}
onClick={() => editPersonClick(hasEditRights)}
Expand Down
2 changes: 1 addition & 1 deletion src/js/components/PrivateRoute.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const PrivateRoute = () => {
const { data: dataAuth, isSuccess: isSuccessAuth } = useFetchData(['get-auth'], {}, METHOD.POST);
useEffect(() => {
if (isSuccessAuth) {
console.log('useFetchData in PrivateRoute useEffect dataAuth good:', dataAuth, isSuccessAuth);
// console.log('useFetchData in PrivateRoute useEffect dataAuth good:', dataAuth, isSuccessAuth);
setIsAuthenticated(dataAuth.isAuthenticated);
// setAppContextValue('loggedInPersonIsAdmin', dataAuth.loggedInPersonIsAdmin);
captureAccessRightsData(dataAuth, isSuccessAuth, apiDataCache, dispatch);
Expand Down
36 changes: 24 additions & 12 deletions src/js/components/Questionnaire/QuestionnaireResponsesList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@ import styled from 'styled-components';
import DesignTokenColors from '../../common/components/Style/DesignTokenColors';
import { renderLog } from '../../common/utils/logging';
import webAppConfig from '../../config';
import { useConnectAppContext } from '../../contexts/ConnectAppContext';
import { useConnectAppContext, useConnectDispatch } from '../../contexts/ConnectAppContext';
import { useGetPersonById } from '../../models/PersonModel';
import { METHOD, useFetchData } from '../../react-query/WeConnectQuery';
import CopyQuestionnaireLink from './CopyQuestionnaireLink';
import { captureQuestionnaireListRetrieveData } from '../../models/QuestionnaireModel';

const OpenExternalWebSite = React.lazy(() => import(/* webpackChunkName: 'OpenExternalWebSite' */ '../../common/components/Widgets/OpenExternalWebSite'));

const QuestionnaireResponsesList = ({ personId }) => {
renderLog('QuestionnaireList'); // Set LOG_RENDER_EVENTS to log all renders
const { getAppContextValue } = useConnectAppContext();
const { apiDataCache, getAppContextValue } = useConnectAppContext();
const { allQuestionsCache } = apiDataCache;
const dispatch = useConnectDispatch();

// const [person] = useState(getAppContextValue('personDrawersPerson'));
const [person] = useState(useGetPersonById(getAppContextValue('personDrawersPersonId')));
Expand All @@ -24,17 +26,27 @@ const QuestionnaireResponsesList = ({ personId }) => {
// Although we are sending a list, there will only be one person id, if there were more, just append them with commas
const requestParams = `personIdList[]=${person.id}`;

const { data: dataQRL, isSuccess: isSuccessQRL, isFetching: isFetchingQRL } = useFetchData(['questionnaire-responses-list-retrieve'], requestParams, METHOD.GET);
if (isFetchingQRL) {
console.log('isFetching ------------ \'questionnaire-responses-list-retrieve\'');
}
const questionnaireResponsesListRetrieveResults = useFetchData(['questionnaire-responses-list-retrieve'], requestParams, METHOD.GET);
// const { data: dataQRL, isSuccess: isSuccessQRL, isFetching: isFetchingQRL } = responsesRetrieveResults;
const { data: dataQRL, isFetching: isFetchingQRL } = questionnaireResponsesListRetrieveResults;
// if (isFetchingQRL) {
// console.log('isFetching ------------ \'questionnaire-responses-list-retrieve\'');
// }
// useEffect(() => {
// if (dataQRL !== undefined && isFetchingQRL === false && person) {
// console.log('useFetchData in QuestionnaireResponsesList useEffect dataQRL is good:', dataQRL, isSuccessQRL, isFetchingQRL);
// console.log('Successfully retrieved QuestionnaireResponsesList...');
// setQuestionnaireList(dataQRL.questionnaireList);
// }
// }, [dataQRL, isFetchingQRL, isSuccessQRL, person]);
useEffect(() => {
if (dataQRL !== undefined && isFetchingQRL === false && person) {
console.log('useFetchData in QuestionnaireResponsesList useEffect dataQRL is good:', dataQRL, isSuccessQRL, isFetchingQRL);
console.log('Successfully retrieved QuestionnaireResponsesList...');
setQuestionnaireList(dataQRL.questionnaireList);
if (questionnaireResponsesListRetrieveResults) {
captureQuestionnaireListRetrieveData(questionnaireResponsesListRetrieveResults, apiDataCache, dispatch);
if (dataQRL && dataQRL.questionnaireList && isFetchingQRL === false) {
setQuestionnaireList(dataQRL.questionnaireList);
}
}
}, [dataQRL, isFetchingQRL, isSuccessQRL, person]);
}, [questionnaireResponsesListRetrieveResults, allQuestionsCache]);

return (
<div>
Expand Down
25 changes: 5 additions & 20 deletions src/js/components/Team/TeamHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,21 @@ import styled from 'styled-components';
import { renderLog } from '../../common/utils/logging';
import { useConnectAppContext } from '../../contexts/ConnectAppContext';
import { viewerCanSeeOrDo } from '../../models/AuthModel';
import { useRemoveTeamMutation } from '../../react-query/mutations';
import { DeleteStyled, EditStyled } from '../Style/iconStyles';
import { EditStyled } from '../Style/iconStyles';


// eslint-disable-next-line no-unused-vars
const TeamHeader = ({ classes, showHeaderLabels, showIcons, team }) => {
const TeamHeader = ({ showHeaderLabels, showIcons, team }) => {
renderLog('TeamHeader');
const { apiDataCache, getAppContextValue, setAppContextValue } = useConnectAppContext();
const { viewerAccessRights } = apiDataCache;
const { mutate } = useRemoveTeamMutation();

let teamLocal = team;
if (!teamLocal || !teamLocal.teamName) {
teamLocal = getAppContextValue('teamForAddTeamDrawer');
}

const removeTeamClick = () => {
console.log('removeTeamMutation team: ', teamLocal.id);
mutate({ teamId: teamLocal.id });
};

const editTeamClick = () => {
console.log('editTeamClick: ', teamLocal);
// console.log('editTeamClick: ', teamLocal);
setAppContextValue('addTeamDrawerOpen', true);
setAppContextValue('AddTeamDrawerLabel', 'Edit Team Name');
setAppContextValue('teamForAddTeamDrawer', teamLocal);
Expand Down Expand Up @@ -61,21 +53,14 @@ const TeamHeader = ({ classes, showHeaderLabels, showIcons, team }) => {
)}
</>
)}
{/* Delete icon */}
{/* Delete icon - Moved to TeamHome */}
{showIcons && (
<>
{viewerCanSeeOrDo('canRemoveTeam', viewerAccessRights) && (
<TeamHeaderCell cellwidth={20} onClick={removeTeamClick}>
<DeleteStyled />
</TeamHeaderCell>
)}
</>
<></>
)}
</OneTeamHeader>
);
};
TeamHeader.propTypes = {
classes: PropTypes.object.isRequired,
showHeaderLabels: PropTypes.bool,
team: PropTypes.object,
showIcons: PropTypes.bool,
Expand Down
14 changes: 12 additions & 2 deletions src/js/components/Team/TeamMemberList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import { renderLog } from '../../common/utils/logging';
import { isSearchTextFoundInPerson } from '../../controllers/PersonController';
import { useConnectAppContext } from '../../contexts/ConnectAppContext';
import { useConnectAppContext, useConnectDispatch } from '../../contexts/ConnectAppContext';
import capturePersonListRetrieveData from '../../models/capturePersonListRetrieveData';
import { getTeamMembersListByTeamId } from '../../models/TeamModel';
import { METHOD, useFetchData } from '../../react-query/WeConnectQuery';
import PersonSummaryRow from '../Person/PersonSummaryRow';
Expand All @@ -13,12 +14,21 @@ import PersonSummaryRow from '../Person/PersonSummaryRow';
const TeamMemberList = ({ searchText, teamId, team }) => { // teamMemberList
renderLog('TeamMemberList');
const { apiDataCache } = useConnectAppContext();
// const { allPeopleCache, allTeamsCache } = apiDataCache;
const { allPeopleCache } = apiDataCache;
const dispatch = useConnectDispatch();

const [teamMemberListApiDataCache, setTeamMemberListApiDataCache] = useState([]);
const [teamMemberListReactQuery, setTeamMemberListReactQuery] = useState(team.teamMemberList || []);
// const teamMemberList = useGetTeamMembersListByTeamId(teamId);
// console.log('TeamMemberList teamMemberList:', teamMemberList);

const personListRetrieveResults = useFetchData(['person-list-retrieve'], {}, METHOD.GET);
useEffect(() => {
if (personListRetrieveResults) {
capturePersonListRetrieveData(personListRetrieveResults, apiDataCache, dispatch);
}
}, [personListRetrieveResults, allPeopleCache, dispatch]);

const { data: dataTLR, isSuccess: isSuccessTLR, isFetching: isFetchingTLR } = useFetchData(['team-list-retrieve'], {}, METHOD.GET);
// console.log('useFetchData in TeamMemberList:', dataTLR, isSuccessTLR, isFetchingTLR);
useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/js/contexts/ConnectAppContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const ConnectAppContextProvider = ({ children }) => {
const { data: dataAuth, isSuccess: isSuccessAuth, isFetching: isFetchingAuth } = useFetchData(['get-auth'], {}, METHOD.POST);
useEffect(() => {
if (isSuccessAuth) {
console.log('useFetchData in ConnectAppContext useEffect dataAuth good:', dataAuth, isSuccessAuth, isFetchingAuth);
// console.log('useFetchData in ConnectAppContext useEffect dataAuth good:', dataAuth, isSuccessAuth, isFetchingAuth);
const { isAuthenticated } = dataAuth;
setAppContextValue('authenticatedPerson', dataAuth.person);
setAppContextValue('authenticatedPersonId', dataAuth.personId);
Expand Down
37 changes: 37 additions & 0 deletions src/js/models/AuthModel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,32 @@ export const viewerCanSeeOrDo = (accessRightName, viewerAccessRights) => {
return viewerAccessRights[accessRightName] || false;
};

export const viewerCanSeeOrDoForThisTeam = (accessRightName, teamId = -1, teamAccessRights = {}) => {
if (!accessRightName || !teamId || !teamAccessRights) {
return false;
}
if (teamId > -1 && teamAccessRights && teamAccessRights[teamId] && teamAccessRights[teamId][accessRightName]) {
return teamAccessRights[teamId][accessRightName] || false;
}
return false;
};

export function captureAccessRightsData (data = {}, isSuccess = false, apiDataCache = {}, dispatch) {
const viewerTeamAccessRights = apiDataCache.viewerTeamAccessRights || {};
const viewerAccessRights = apiDataCache.viewerAccessRights || {};
let changeResults = {
viewerAccessRights,
viewerAccessRightsChanged: false,
viewerTeamAccessRights,
viewerTeamAccessRightsChanged: false,
};
let viewerAccessRightsNew = { ...viewerAccessRights };
let viewerTeamAccessRightsNew = { ...viewerTeamAccessRights };
// console.log('captureAccessRightsData data:', data);
if (data && data.accessRights && isSuccess === true) {
let newDataReceived = false;
const { accessRights } = data;
// Checking to make sure common access right exists so we know results were returned
if (accessRights && !('canAddPerson' in accessRights)) {
viewerAccessRightsNew = accessRights;
newDataReceived = true;
Expand All @@ -33,10 +48,32 @@ export function captureAccessRightsData (data = {}, isSuccess = false, apiDataCa
// console.log('=== captureAccessRightsData viewerAccessRightsNew:', viewerAccessRightsNew, ', newDataReceived:', newDataReceived);
dispatch({ type: 'updateByKeyValue', key: 'viewerAccessRights', value: viewerAccessRightsNew });
changeResults = {
...changeResults,
viewerAccessRights: viewerAccessRightsNew,
viewerAccessRightsChanged: true,
};
}
}
if (data && data.teamAccessRights && isSuccess === true) {
let newDataReceived = false;
const { teamAccessRights } = data;
// Checking to make sure common access right exists so we know results were returned
if (teamAccessRights && !('canEditPersonThisTeam' in teamAccessRights)) {
viewerTeamAccessRightsNew = teamAccessRights;
newDataReceived = true;
} else if (!isEqual(teamAccessRights, viewerTeamAccessRightsNew)) {
viewerTeamAccessRightsNew = teamAccessRights;
newDataReceived = true;
}
if (newDataReceived) {
// console.log('=== captureAccessRightsData viewerTeamAccessRightsNew:', viewerTeamAccessRightsNew, ', newDataReceived:', newDataReceived);
dispatch({ type: 'updateByKeyValue', key: 'viewerTeamAccessRights', value: viewerTeamAccessRightsNew });
changeResults = {
...changeResults,
viewerTeamAccessRights: viewerTeamAccessRightsNew,
viewerTeamAccessRightsChanged: true,
};
}
}
return changeResults;
}
2 changes: 1 addition & 1 deletion src/js/models/QuestionnaireModel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export const getAnswerToQuestion = (personId, questionId, allAnswersCache) => {
return answer;
};

export const getAnswerValueToQuestion = (personId, questionId, allAnswersCache) => {
export const getAnswerValueToQuestion = (questionId, personId, allAnswersCache) => {
const answer = getAnswerToQuestion(personId, questionId, allAnswersCache) || {};
if (!answer || !answer.answerType) {
// console.log(`No answer found for questionId: ${questionId}`);
Expand Down
6 changes: 3 additions & 3 deletions src/js/pages/AnswerQuestions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const AnswerQuestions = ({ classes, setShowHeaderFooter }) => {
if (`questionAnswer-${question.id}` in inputValuesRevised) {
answerValue = inputValuesRevised[`questionAnswer-${question.id}`];
} else {
answerValue = getAnswerValueToQuestion(personId, question.id, allAnswersCache);
answerValue = getAnswerValueToQuestion(question.id, personId, allAnswersCache);
}
if (answerValue === undefined || answerValue === null || answerValue === '') {
requiredValueMissing = true;
Expand Down Expand Up @@ -253,13 +253,13 @@ const AnswerQuestions = ({ classes, setShowHeaderFooter }) => {
<AnswerText>
YOU ANSWERED:
{' '}
{getAnswerValueToQuestion(personId, question.id, allAnswersCache)}
{getAnswerValueToQuestion(question.id, personId, allAnswersCache)}
</AnswerText>
) : (
<QuestionFormWrapper>
<TextField
classes={(question.answerType === 'INTEGER') ? {} : { root: classes.formControl }}
defaultValue={getAnswerValueToQuestion(personId, question.id, allAnswersCache)}
defaultValue={getAnswerValueToQuestion(question.id, personId, allAnswersCache)}
error={isQuestionIdInError(question.id)}
helperText={isQuestionIdInError(question.id) ? helperTextIfQuestionIdInError(question.id) : ''}
id={`questionAnswer-${question.id}`}
Expand Down
Loading

0 comments on commit 840c69a

Please sign in to comment.