Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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. #32

Merged
merged 1 commit into from
Feb 20, 2025
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
Loading