Skip to content

Commit

Permalink
Merge pull request #32 from DaleMcGrew/Dale_WCC_Feb18-2025
Browse files Browse the repository at this point in the history
First pass on viewerCanSeeOrDo & viewerAccessRights implementation. Added finer-grained viewerCanSeeOrDo switch to PersonSummaryRow & TeamHeader, so we turn off interface elements the person cannot access. Tested signin/signout, and confirmed that is still working. Registration requires manual browser refresh for signed in access rights to be recognized. Replaced loggedInPersonIsAdmin with viewerCanSeeOrDo & viewerAccessRights implementation. Control which PersonProfile we want to show with incoming prop. Working on bringing QuestionnaireResponsesList back to life. Implemented models/PersonModel - capturePersonRetrieveData. We may decide not to use person-retrieve in the future but I'd like to leave in place.
  • Loading branch information
DaleMcGrew authored Feb 20, 2025
2 parents 20ae397 + a9bbad2 commit 8cf9d67
Show file tree
Hide file tree
Showing 19 changed files with 211 additions and 140 deletions.
1 change: 1 addition & 0 deletions src/js/components/Navigation/HeaderBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const HeaderBar = ({ hideTabs }) => {
}, [isAuth]);

const logoutApi = async () => {
// I don't think we want to make the weConnectQueryFn call here since we are about to call mutateLogout
const data = await weConnectQueryFn('logout', {}, METHOD.POST);
console.log(`/logout response in HeaderBar -- status: '${'status'}', data: ${JSON.stringify(data)}`);
clearSignedInGlobals(setAppContextValue);
Expand Down
8 changes: 5 additions & 3 deletions src/js/components/Person/PersonProfile.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import PropTypes from 'prop-types';
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import { renderLog } from '../../common/utils/logging';
Expand All @@ -9,14 +10,12 @@ import { METHOD, useFetchData } from '../../react-query/WeConnectQuery';
import { captureQuestionnaireListRetrieveData } from '../../models/QuestionnaireModel';


const PersonProfile = () => {
const PersonProfile = ({ personId }) => {
renderLog('PersonProfile'); // Set LOG_RENDER_EVENTS to log all renders
const { getAppContextValue } = useConnectAppContext();
const { apiDataCache } = useConnectAppContext();
const { allQuestionnairesCache } = apiDataCache;
const dispatch = useConnectDispatch();

const [personId] = useState(getAppContextValue('personDrawersPersonId'));
const [questionnaireList, setQuestionnaireList] = useState([]);
const [showQuestionnaireList, setShowQuestionnaireList] = useState(false);

Expand Down Expand Up @@ -66,6 +65,9 @@ const PersonProfile = () => {
</PersonProfileWrapper>
);
};
PersonProfile.propTypes = {
personId: PropTypes.number,
};

const FullName = styled('h2')`
`;
Expand Down
11 changes: 7 additions & 4 deletions src/js/components/Person/PersonProfileDrawerMainContent.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import React from 'react';
import React, { useState } from 'react';
import styled from 'styled-components';
import { renderLog } from '../../common/utils/logging';
// import QuestionnaireResponsesList from '../Questionnaire/QuestionnaireResponsesList';
import { useConnectAppContext } from '../../contexts/ConnectAppContext';
import QuestionnaireResponsesList from '../Questionnaire/QuestionnaireResponsesList';
import PersonProfile from './PersonProfile';


const PersonProfileDrawerMainContent = () => {
renderLog('PersonProfileDrawerMainContent');
const { getAppContextValue } = useConnectAppContext();
const [personId] = useState(getAppContextValue('personDrawersPersonId'));

return (
<PersonProfileDrawerMainContentWrapper>
<PersonProfile />
{/* <QuestionnaireResponsesList /> */}
<PersonProfile personId={personId} />
<QuestionnaireResponsesList personId={personId} />
</PersonProfileDrawerMainContentWrapper>
);
};
Expand Down
14 changes: 6 additions & 8 deletions src/js/components/Person/PersonSummaryRow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ import {
} from '../../models/PersonModel';
import { useRemoveTeamMemberMutation } from '../../react-query/mutations';
import { DeleteStyled, EditStyled } from '../Style/iconStyles';
import { viewerCanSeeOrDo } from '../../models/AuthModel';
// import { useRemoveTeamMemberMutationDiverged } from '../../models/TeamModel';


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

// const [person, setPerson] = useState(useGetPersonById(personId)); 2/5/2025 does not work
const { setAppContextValue } = useConnectAppContext();
const { mutate } = useRemoveTeamMemberMutation();

const removeTeamMemberClick = () => {
const params = { personId: person.personId, teamId };
Expand Down Expand Up @@ -90,7 +91,7 @@ const PersonSummaryRow = ({ person, rowNumberForDisplay, teamId }) => {
>
{person.jobTitle}
</PersonCell>
{hasEditRights ? (
{viewerCanSeeOrDo('canEditPersonAnyone', viewerAccessRights) ? (
<PersonCell
id={`editPerson-personId-${person.personId}`}
onClick={() => editPersonClick(hasEditRights)}
Expand All @@ -102,7 +103,6 @@ const PersonSummaryRow = ({ person, rowNumberForDisplay, teamId }) => {
</PersonCell>
) : (
<PersonCell
id={`editPerson-personId-${person.personId}`}
// cellwidth="20"
cellwidth={20}
>
Expand All @@ -111,7 +111,7 @@ const PersonSummaryRow = ({ person, rowNumberForDisplay, teamId }) => {
)}
{teamId > 0 && (
<>
{hasEditRights ? (
{viewerCanSeeOrDo('canRemoveTeamMemberAnyTeam', viewerAccessRights) ? (
<PersonCell
id={`removeMember-personId-${person.personId}`}
onClick={() => removeTeamMemberClick(person)}
Expand All @@ -123,8 +123,6 @@ const PersonSummaryRow = ({ person, rowNumberForDisplay, teamId }) => {
</PersonCell>
) : (
<PersonCell
id={`removeMember-personId-${person.personId}`}
onClick={() => removeTeamMemberClick(person)}
// cellwidth="20"
cellwidth={20}
>
Expand Down
9 changes: 6 additions & 3 deletions src/js/components/PrivateRoute.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React, { useEffect, useState } from 'react';
import { Navigate, Outlet, useLocation } from 'react-router';
import { authLog } from '../common/utils/logging';
import { useConnectAppContext } from '../contexts/ConnectAppContext';
import { useConnectAppContext, useConnectDispatch } from '../contexts/ConnectAppContext';
import { METHOD, useFetchData } from '../react-query/WeConnectQuery';
import { captureAccessRightsData } from '../models/AuthModel';

const PrivateRoute = () => {
const location = useLocation();
const { getAppContextValue, setAppContextValue } = useConnectAppContext();
const { apiDataCache, getAppContextValue } = useConnectAppContext();
const dispatch = useConnectDispatch();

const [isAuthenticated, setIsAuthenticated] = useState(null);

Expand All @@ -15,7 +17,8 @@ const PrivateRoute = () => {
if (isSuccessAuth) {
console.log('useFetchData in PrivateRoute useEffect dataAuth good:', dataAuth, isSuccessAuth);
setIsAuthenticated(dataAuth.isAuthenticated);
setAppContextValue('loggedInPersonIsAdmin', dataAuth.loggedInPersonIsAdmin);
// setAppContextValue('loggedInPersonIsAdmin', dataAuth.loggedInPersonIsAdmin);
captureAccessRightsData(dataAuth, isSuccessAuth, apiDataCache, dispatch);
authLog('========= PrivateRoute =========== INNER isAuthenticated: ', dataAuth.isAuthenticated);
}
}, [dataAuth, isSuccessAuth]);
Expand Down
2 changes: 1 addition & 1 deletion src/js/components/Questionnaire/CopyQuestionnaireLink.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const styles = () => ({
});


const CopyQuestionnaireLinkWrapper = styled('div')`
const CopyQuestionnaireLinkWrapper = styled('span')`
`;

export default withStyles(styles)(CopyQuestionnaireLink);
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ const QuestionnaireResponsesList = ({ personId }) => {
{questionnaireList.length > 0 && (
<>
<QuestionnaireResponses>
Questionnaire Responses
Answered
</QuestionnaireResponses>
<QuestionnaireListWrapper>
{questionnaireList.map((questionnaire) => (
<OneQuestionnaireWrapper key={`questionnaire-${questionnaire.id}`}>
<QuestionText>
{questionnaire.questionnaireName}
</QuestionText>
<CopyQuestionnaireLink personId={personId} questionnaireId={questionnaire.id} />
{/* <CopyQuestionnaireLink personId={personId} questionnaireId={questionnaire.id} /> */}
<Suspense fallback={<></>}>
<OpenExternalWebSite
linkIdAttribute="view answers"
Expand Down Expand Up @@ -108,8 +108,7 @@ const QuestionText = styled('div')`
`;

const QuestionnaireListWrapper = styled('div')`
margin-top: 30px;
margin-left: 10px;
margin-bottom: 30px;
`;

export default QuestionnaireResponsesList;
24 changes: 17 additions & 7 deletions src/js/components/Team/TeamHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import { Link } from 'react-router';
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';


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

let teamLocal = team;
Expand Down Expand Up @@ -51,15 +53,23 @@ const TeamHeader = ({ classes, showHeaderLabels, showIcons, team }) => {
</TeamHeaderCell>
{/* Edit icon */}
{showIcons && (
<TeamHeaderCell cellwidth={20} onClick={editTeamClick}>
<EditStyled />
</TeamHeaderCell>
<>
{viewerCanSeeOrDo('canEditTeamAnyTeam', viewerAccessRights) && (
<TeamHeaderCell cellwidth={20} onClick={editTeamClick}>
<EditStyled />
</TeamHeaderCell>
)}
</>
)}
{/* Delete icon */}
{showIcons && (
<TeamHeaderCell cellwidth={20} onClick={removeTeamClick}>
<DeleteStyled />
</TeamHeaderCell>
<>
{viewerCanSeeOrDo('canRemoveTeam', viewerAccessRights) && (
<TeamHeaderCell cellwidth={20} onClick={removeTeamClick}>
<DeleteStyled />
</TeamHeaderCell>
)}
</>
)}
</OneTeamHeader>
);
Expand Down
37 changes: 3 additions & 34 deletions src/js/contexts/ConnectAppContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, { createContext, useContext, useEffect, useReducer, useState } fro
import initialApiDataCache from '../models/initialApiDataCache';
// import capturePersonListRetrieveData from '../models/capturePersonListRetrieveData';
import { METHOD, useFetchData } from '../react-query/WeConnectQuery';
import { captureAccessRightsData } from '../models/AuthModel';
// import { getInitialGlobalPersonVariables, PersonListRetrieveDataCapture } from '../models/PersonModel';
// import { getInitialGlobalTaskVariables } from '../models/TaskModel';
// import { getInitialGlobalTeamVariables } from '../models/TeamModel';
Expand Down Expand Up @@ -66,39 +67,6 @@ export const ConnectAppContextProvider = ({ children }) => {
}
};

// const { data: dataP, isSuccess: isSuccessP, isFetching: isFetchingP, isStale: isStaleP } = useFetchData(['person-list-retrieve'], {}, METHOD.GET);
// const personListRetrieveResults = useFetchData(['person-list-retrieve'], {}, METHOD.GET);
// This is not currently the right place to pass these values, but I'm saving these here for the next 30 days until we work out the correct place.
// {
// cacheTime: 0,
// networkMode: 'no-cache', <-- This is not a solution, it just covers up some problem in our code, while disabling the biggest benefit of ReactQueries.
// refetchOnMount: true,
// refetchOnWindowFocus: true,
// refetchInterval: 0,
// staleTime: 0,
// }

// Moved to root pages: Teams, TeamHome, etc.
// useEffect(() => {
// // console.log('useFetchData person-list-retrieve in Teams useEffect:', personListRetrieveResults);
// if (personListRetrieveResults) {
// // console.log('In useEffect apiDataCache:', apiDataCache);
// // const changeResults =
// capturePersonListRetrieveData(personListRetrieveResults, apiDataCache, dispatch);
// // console.log('ConnectAppContext useEffect capturePersonListRetrieveData changeResults:', changeResults);
// }
// }, [personListRetrieveResults]);

// const { data: dataP, isSuccess: isSuccessP, isFetching: isFetchingP } = personListRetrieveResults;
// useEffect(() => {
// // console.log('useFetchData in TeamHome (person-list-retrieve) useEffect:', dataP, isSuccessP, isFetchingP, isStaleP);
// if (isSuccessP) {
// // console.log('useFetchData in TeamHome (person-list-retrieve)useEffect data good:', dataP, isSuccessP, isFetchingP, isStaleP);
// setAppContextValue('allPeopleList', dataP ? dataP.personList : []);
// // console.log('ConnectAppContext useEffect allPeopleList fetched');
// }
// }, [dataP, isSuccessP, isFetchingP]);

// The following prints console log errors
const { data: dataAuth, isSuccess: isSuccessAuth, isFetching: isFetchingAuth } = useFetchData(['get-auth'], {}, METHOD.POST);
useEffect(() => {
Expand All @@ -108,7 +76,8 @@ export const ConnectAppContextProvider = ({ children }) => {
setAppContextValue('authenticatedPerson', dataAuth.person);
setAppContextValue('authenticatedPersonId', dataAuth.personId);
setAppContextValue('isAuthenticated', isAuthenticated);
setAppContextValue('loggedInPersonIsAdmin', dataAuth.loggedInPersonIsAdmin);
// setAppContextValue('loggedInPersonIsAdmin', dataAuth.loggedInPersonIsAdmin);
captureAccessRightsData(dataAuth, isSuccessAuth, apiDataCache, dispatch);

console.log('=============== ConnectAppContextProvider ======= isAuthenticated: ', isAuthenticated, ' ===========');
}
Expand Down
2 changes: 1 addition & 1 deletion src/js/contexts/contextFunctions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ export const clearSignedInGlobals = (setAppContextValue) => {
setAppContextValue('authenticatedPerson', undefined);
setAppContextValue('authenticatedPersonId', -1);
setAppContextValue('isAuthenticated', false);
setAppContextValue('loggedInPersonIsAdmin', false);
// setAppContextValue('loggedInPersonIsAdmin', false);
setAppContextValue('personIsSignedIn', false);
};
42 changes: 42 additions & 0 deletions src/js/models/AuthModel.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// AuthModel.js
// Functions related to getting data from the apiDataCache, which stores data
// received from our API servers.
import isEqual from 'lodash-es/isEqual';


export const viewerCanSeeOrDo = (accessRightName, viewerAccessRights) => {
if (!viewerAccessRights || !(accessRightName in viewerAccessRights)) {
return false;
}
return viewerAccessRights[accessRightName] || false;
};

export function captureAccessRightsData (data = {}, isSuccess = false, apiDataCache = {}, dispatch) {
const viewerAccessRights = apiDataCache.viewerAccessRights || {};
let changeResults = {
viewerAccessRights,
viewerAccessRightsChanged: false,
};
let viewerAccessRightsNew = { ...viewerAccessRights };
// console.log('captureAccessRightsData data:', data);
if (data && data.accessRights && isSuccess === true) {
let newDataReceived = false;
const { accessRights } = data;
if (accessRights && !('canAddPerson' in accessRights)) {
viewerAccessRightsNew = accessRights;
newDataReceived = true;
} else if (!isEqual(accessRights, viewerAccessRightsNew)) {
viewerAccessRightsNew = accessRights;
newDataReceived = true;
}
if (newDataReceived) {
// console.log('=== captureAccessRightsData viewerAccessRightsNew:', viewerAccessRightsNew, ', newDataReceived:', newDataReceived);
dispatch({ type: 'updateByKeyValue', key: 'viewerAccessRights', value: viewerAccessRightsNew });
changeResults = {
viewerAccessRights: viewerAccessRightsNew,
viewerAccessRightsChanged: true,
};
}
}
return changeResults;
}
34 changes: 34 additions & 0 deletions src/js/models/PersonModel.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,44 @@
// PersonModel.js
// Functions related to getting data from the apiDataCache, which stores data
// received from our API servers.
import isEqual from 'lodash-es/isEqual';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useConnectAppContext } from '../contexts/ConnectAppContext';
import weConnectQueryFn, { METHOD } from '../react-query/WeConnectQuery';

export function capturePersonRetrieveData (incomingResults = {}, apiDataCache = {}, dispatch) {
const { data, isSuccess } = incomingResults;
const allPeopleCache = apiDataCache.allPeopleCache || {};
let changeResults = {
allPeopleCache,
allPeopleCacheChanged: false,
};
const allPeopleCacheNew = { ...allPeopleCache };
// We need to only update allPeopleCache the first time we have received new data from the API server
if (data && data.personId && isSuccess === true) {
let newDataReceived = false;
const person = data;
if (person && person.personId && person.personId >= 0) {
if (!allPeopleCacheNew[person.personId]) {
allPeopleCacheNew[person.personId] = person;
newDataReceived = true;
} else if (!isEqual(person, allPeopleCacheNew[person.personId])) {
allPeopleCacheNew[person.personId] = person;
newDataReceived = true;
}
}
// console.log('person-retrieve setting allPeopleCacheNew:', allPeopleCacheNew, ', newDataReceived:', newDataReceived);
if (newDataReceived) {
// setAppContextValue('allPeopleCache', allPeopleCache);
dispatch({ type: 'updateByKeyValue', key: 'allPeopleCache', value: allPeopleCacheNew });
changeResults = {
allPeopleCache: allPeopleCacheNew,
allPeopleCacheChanged: true,
};
}
}
return changeResults;
}

export const useGetPersonById = (personId) => {
const { apiDataCache } = useConnectAppContext();
Expand Down
Loading

0 comments on commit 8cf9d67

Please sign in to comment.