From 53f89435a3ffdb508a92ae3d83abc5bb20b1840a Mon Sep 17 00:00:00 2001 From: Chad Elliott Date: Mon, 20 Jan 2025 11:23:07 -0600 Subject: [PATCH] Handle the view/create/update private note permissions. --- .../components/private-note/PrivateNote.jsx | 91 ++++++++++++------- web-ui/src/context/reducer.js | 6 +- web-ui/src/context/selectors.js | 12 +++ web-ui/src/pages/CheckinsPage.jsx | 2 + web-ui/src/pages/ErrorBoundaryPage.jsx | 16 +++- 5 files changed, 90 insertions(+), 37 deletions(-) diff --git a/web-ui/src/components/private-note/PrivateNote.jsx b/web-ui/src/components/private-note/PrivateNote.jsx index 4e7eaf717b..6a975cf3fb 100644 --- a/web-ui/src/components/private-note/PrivateNote.jsx +++ b/web-ui/src/components/private-note/PrivateNote.jsx @@ -12,8 +12,12 @@ import { selectIsPDL, selectIsAdmin, selectCheckin, - selectProfile + selectProfile, + selectCanViewPrivateNotesPermission, + selectCanCreatePrivateNotesPermission, + selectCanUpdatePrivateNotesPermission, } from '../../context/selectors'; +import { UPDATE_TOAST } from '../../context/actions'; import { debounce } from 'lodash/function'; import { Editor } from '@tinymce/tinymce-react'; import LockIcon from '@mui/icons-material/Lock'; @@ -49,19 +53,36 @@ const PrivateNote = () => { useEffect(() => { async function getPrivateNotes() { - setIsLoading(true); - try { - let res = await getPrivateNoteByCheckinId(checkinId, csrf); - if (res.error) throw new Error(res.error); - const currentNote = - res.payload && res.payload.data && res.payload.data.length > 0 - ? res.payload.data[0] - : null; - if (currentNote) { - setNote(currentNote); - } else if (currentUserId === pdlId) { - if (!noteRef.current.some(id => id === checkinId)) { - noteRef.current.push(checkinId); + if (selectCanViewPrivateNotesPermission(state)) { + setIsLoading(true); + try { + let res = await getPrivateNoteByCheckinId(checkinId, csrf); + if (res.error) throw new Error(res.error); + const currentNote = + res.payload && res.payload.data && res.payload.data.length > 0 + ? res.payload.data[0] + : null; + if (currentNote) { + setNote(currentNote); + } else if (currentUserId === pdlId) { + if (!noteRef.current.some(id => id === checkinId) && + selectCanCreatePrivateNotesPermission(state)) { + noteRef.current.push(checkinId); + res = await createPrivateNote( + { + checkinid: checkinId, + createdbyid: currentUserId, + description: '' + }, + csrf + ); + noteRef.current = noteRef.current.filter(id => id !== checkinId); + if (res.error) throw new Error(res.error); + if (res && res.payload && res.payload.data) { + setNote(res.payload.data); + } + } + } else if (selectCanCreatePrivateNotesPermission(state)) { res = await createPrivateNote( { checkinid: checkinId, @@ -70,30 +91,16 @@ const PrivateNote = () => { }, csrf ); - noteRef.current = noteRef.current.filter(id => id !== checkinId); if (res.error) throw new Error(res.error); if (res && res.payload && res.payload.data) { setNote(res.payload.data); } } - } else { - res = await createPrivateNote( - { - checkinid: checkinId, - createdbyid: currentUserId, - description: '' - }, - csrf - ); - if (res.error) throw new Error(res.error); - if (res && res.payload && res.payload.data) { - setNote(res.payload.data); - } + } catch (e) { + console.error("getPrivateNotes: " + e); } - } catch (e) { - console.error("getPrivateNotes: " + e); + setIsLoading(false); } - setIsLoading(false); } if (csrf) { getPrivateNotes(); @@ -101,6 +108,28 @@ const PrivateNote = () => { }, [csrf, checkinId, currentUserId, pdlId]); const handleNoteChange = (content, delta, source, editor) => { + if (note == null) { + window.snackDispatch({ + type: UPDATE_TOAST, + payload: { + severity: 'error', + toast: selectCanCreatePrivateNotesPermission(state) + ? 'No private note was created' + : 'No permission to create private notes' + } + }); + return; + } + if (!selectCanUpdatePrivateNotesPermission(state)) { + window.snackDispatch({ + type: UPDATE_TOAST, + payload: { + severity: 'error', + toast: 'No permission to update private notes' + } + }); + return; + } if (Object.keys(note).length === 0 || !csrf || currentCheckin?.completed) { return; } diff --git a/web-ui/src/context/reducer.js b/web-ui/src/context/reducer.js index 4e9d952e61..6c484898d9 100644 --- a/web-ui/src/context/reducer.js +++ b/web-ui/src/context/reducer.js @@ -68,7 +68,11 @@ export const reducer = (state, action) => { state.userProfile.memberProfile.bioText = action.payload; break; case ADD_CHECKIN: - state.checkins = [...state.checkins, action.payload]; + if (state?.checkins?.length > 0) { + state.checkins = [...state.checkins, action.payload]; + } else { + state.checkins = [action.payload]; + } break; case UPDATE_CHECKINS: if (state?.checkins?.length > 0) { diff --git a/web-ui/src/context/selectors.js b/web-ui/src/context/selectors.js index 9ecfb34ed9..05a131d297 100644 --- a/web-ui/src/context/selectors.js +++ b/web-ui/src/context/selectors.js @@ -190,6 +190,18 @@ export const selectCanViewCheckinsPermission = hasPermission( 'CAN_VIEW_CHECKINS' ); +export const selectCanViewPrivateNotesPermission = hasPermission( + 'CAN_VIEW_PRIVATE_NOTE' +); + +export const selectCanCreatePrivateNotesPermission = hasPermission( + 'CAN_CREATE_PRIVATE_NOTE' +); + +export const selectCanUpdatePrivateNotesPermission = hasPermission( + 'CAN_UPDATE_PRIVATE_NOTE' +); + export const selectIsPDL = createSelector( selectUserProfile, userProfile => diff --git a/web-ui/src/pages/CheckinsPage.jsx b/web-ui/src/pages/CheckinsPage.jsx index 5c0b104682..7a292fbbeb 100644 --- a/web-ui/src/pages/CheckinsPage.jsx +++ b/web-ui/src/pages/CheckinsPage.jsx @@ -14,6 +14,7 @@ import { selectProfile, selectCheckinsForMember, selectCanViewCheckinsPermission, + selectCanViewPrivateNotesPermission, } from '../context/selectors'; import { getCheckins, createNewCheckin } from '../context/thunks'; import { UPDATE_CHECKIN, UPDATE_TOAST } from '../context/actions'; @@ -91,6 +92,7 @@ const CheckinsPage = () => { const isPdl = selectIsPDL(state); const canViewPrivateNote = + selectCanViewPrivateNotesPermission(state) && (isAdmin || selectedProfile?.pdlId === currentUserId) && currentUserId !== memberId; diff --git a/web-ui/src/pages/ErrorBoundaryPage.jsx b/web-ui/src/pages/ErrorBoundaryPage.jsx index eac988c564..deae70e772 100644 --- a/web-ui/src/pages/ErrorBoundaryPage.jsx +++ b/web-ui/src/pages/ErrorBoundaryPage.jsx @@ -40,15 +40,21 @@ const ErrorFallback = ({ error }) => { //before upload to server let sanitizeBody = sanitizeQuillElements(body); let res = await newGitHubIssue(sanitizeBody, title, csrf); - if (res && res.payload) { + if (res?.error) { + window.snackDispatch({ + type: UPDATE_TOAST, + payload: { + severity: 'error', + toast: res.error.message, + } + }); + } else if (res?.payload?.data) { setLink(res.payload.data[0].html_url); window.snackDispatch({ type: UPDATE_TOAST, payload: { - severity: !res.error ? 'success' : 'error', - toast: !res.error - ? `New issue ${title} created! Gratzie 😀` - : res.error.message + severity: 'success', + toast: `New issue ${title} created! Gratzie 😀`, } }); }