From 88a2439f8e78531ddeee5d2af9a4fc50f3f40d50 Mon Sep 17 00:00:00 2001 From: Abdul Aziz Hatkou Date: Tue, 28 Oct 2025 13:22:17 +0100 Subject: [PATCH 1/3] Fixed issue #256 by passing a null value to setStrikeToEdit when adding a new strike and clearing the form after adding a strike. --- .../education/StrikeDetailsModal.tsx | 4 +++ .../components/education/StrikesComponent.tsx | 29 ++++++++++--------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/client/src/components/education/StrikeDetailsModal.tsx b/client/src/components/education/StrikeDetailsModal.tsx index f6c78724..82281ad4 100644 --- a/client/src/components/education/StrikeDetailsModal.tsx +++ b/client/src/components/education/StrikeDetailsModal.tsx @@ -57,6 +57,9 @@ export const StrikeDetailsModal = ({ setIsEditMode(true); return; } + else { + setIsEditMode(false); + } resetForm(); }, [strikeToEdit]); @@ -111,6 +114,7 @@ export const StrikeDetailsModal = ({ onConfirmEdit(strikeFields); } else { onConfirmAdd(strikeFields); + resetForm(); } }; diff --git a/client/src/components/education/StrikesComponent.tsx b/client/src/components/education/StrikesComponent.tsx index 35d5b50e..8e215ff5 100644 --- a/client/src/components/education/StrikesComponent.tsx +++ b/client/src/components/education/StrikesComponent.tsx @@ -11,36 +11,36 @@ import { useState } from 'react'; import { useTraineeProfileContext } from '../../hooks/useTraineeProfileContext'; export const StrikesComponent = () => { - const [isModalOpen, setIsModalOpen] = useState(false); + const [isModalOpen, setIsModalOpen] = useState(false); //NOTE: bool for modal state - const [modalError, setModalError] = useState(''); - const [strikeToEdit, setStrikeToEdit] = useState(null); - const { traineeId } = useTraineeProfileContext(); - const { mutate: addStrike, isLoading: addStrikeLoading } = useAddStrike(traineeId); + const [modalError, setModalError] = useState(''); //NOTE: string for modal error + const [strikeToEdit, setStrikeToEdit] = useState(null); //NOTE: strike to edit state + const { traineeId } = useTraineeProfileContext(); //NOTE: collects id from context + const { mutate: addStrike, isLoading: addStrikeLoading } = useAddStrike(traineeId); //NOTE: how does mutate work? this is for the database const { mutate: deleteStrike, isLoading: deleteStrikeLoading, error: deleteStrikeError } = useDeleteStrike(traineeId); const { mutate: editStrike, isLoading: editStrikeLoading } = useEditStrike(traineeId); - const { data: strikes, isLoading: strikesLoading, error: strikesError } = useGetStrikes(traineeId); - const [isConfirmationDialogOpen, setIsConfirmationDialogOpen] = useState(false); + const { data: strikes, isLoading: strikesLoading, error: strikesError } = useGetStrikes(traineeId); //NOTE: gets strikes and state from database traineeId + const [isConfirmationDialogOpen, setIsConfirmationDialogOpen] = useState(false); //NOTE: bool for confirmation dialog - const [idToDelete, setIdToDelete] = useState(''); + const [idToDelete, setIdToDelete] = useState(''); //TODO: how does this work const queryClient = useQueryClient(); const handleSuccess = () => { queryClient.invalidateQueries(['strikes', traineeId]); setIsModalOpen(false); }; - const getErrorMessage = (error: Error | unknown) => { + const getErrorMessage = (error: Error | unknown) => { //NOTE: gives the error message for the strikes list return (error as Error).message || 'Unknown error'; }; - const onClickEdit = (id: string) => { + const onClickEdit = (id: string) => { //NOTE: edits the id'ed strike const strike = strikes?.find((strike) => strike.id === id) || null; setStrikeToEdit(strike); setIsModalOpen(true); }; - const onConfirmAdd = async (strike: Strike) => { + const onConfirmAdd = async (strike: Strike) => { //NOTE: add strike when confirmed addStrike(strike, { onSuccess: handleSuccess, onError: (e) => { @@ -49,7 +49,7 @@ export const StrikesComponent = () => { }); }; - const onConfirmEdit = (strike: Strike) => { + const onConfirmEdit = (strike: Strike) => { //NOTE: push edit when confirmed editStrike(strike, { onSuccess: handleSuccess, onError: (e) => { @@ -58,7 +58,7 @@ export const StrikesComponent = () => { }); }; - const onClickDelete = (id: string) => { + const onClickDelete = (id: string) => { //NOTE: Shows confirmation button setIdToDelete(id); setIsConfirmationDialogOpen(true); }; @@ -66,7 +66,8 @@ export const StrikesComponent = () => { /** * Function to enable adding strikes. */ - const onClickAdd = () => { + const onClickAdd = () => { //TODO: Fix this issue + setStrikeToEdit(null); setIsModalOpen(true); }; From d8218eb6b57270d5741f03fd383d86da0e63a86b Mon Sep 17 00:00:00 2001 From: Abdul Aziz Hatkou Date: Tue, 28 Oct 2025 13:34:23 +0100 Subject: [PATCH 2/3] edited the margins around the strike comments --- client/src/components/education/StrikesList.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/client/src/components/education/StrikesList.tsx b/client/src/components/education/StrikesList.tsx index b7e55123..f1ef10e8 100644 --- a/client/src/components/education/StrikesList.tsx +++ b/client/src/components/education/StrikesList.tsx @@ -7,13 +7,13 @@ import { Strike } from '../../models'; import { formatDateForDisplay } from '../../helpers/dateHelper'; import MarkdownText from '../shared/MarkdownText'; -interface StrikesListProps { +interface StrikesListProps { //NOTE: seems to hold strikes list strikes: Strike[]; onClickEdit: (id: string) => void; onClickDelete: (id: string) => void; } -export const StrikesList: React.FC = ({ strikes, onClickEdit, onClickDelete }) => { +export const StrikesList: React.FC = ({ strikes, onClickEdit, onClickDelete }) => { //NOTE: so this is making sure that strikes list is a react functional component with strikeslist props /** * Formats the strike reason to a readable format * with the first letter capitalized @@ -21,16 +21,17 @@ export const StrikesList: React.FC = ({ strikes, onClickEdit, * @returns The formatted strike reason */ const formatStrikeReason = (reason: string): string => { - return reason.split('-').join(' ').charAt(0).toUpperCase() + reason.split('-').join(' ').slice(1).toLowerCase(); + return reason.split('-').join(' ').charAt(0).toUpperCase() + reason.split('-').join(' ').slice(1).toLowerCase(); //NOTE: formatter for the comment }; - const handleEdit = (id: string) => { + const handleEdit = (id: string) => { //NOTE: what to do for edit and delete which are on the side of each strike onClickEdit(id); }; const handleDelete = (id: string) => { onClickDelete(id); }; + //NOTE: render how the actions look and these are two buttons that call either edit or delete. const renderActions = (id: string) => { return ( @@ -44,6 +45,7 @@ export const StrikesList: React.FC = ({ strikes, onClickEdit, ); }; + //NOTE: the return of the component I assume that here is where the const render actions will be also called. return ( = ({ strikes, onClickEdit, scrollbarWidth: 'thin', }} > - {strikes.length === 0 ? ( + {strikes.length === 0 ? ( //NOTE: add all found elements in the list or none No strikes found ) : ( strikes.map((strike: Strike, index: number) => { - return ( + return ( //NOTE: the boxes are keyed so they are found again when needed @@ -95,7 +96,7 @@ export const StrikesList: React.FC = ({ strikes, onClickEdit, {formatDateForDisplay(strike.date)} } - secondary={{strike.comments}} + secondary={{strike.comments}} /> {renderActions(strike.id)} From 9c903fbc30f2617c6ea51b878e1ea8ed59db771d Mon Sep 17 00:00:00 2001 From: Abdul Aziz Hatkou Date: Tue, 28 Oct 2025 13:36:53 +0100 Subject: [PATCH 3/3] formatted and removed comments --- .../education/StrikeDetailsModal.tsx | 3 +- .../components/education/StrikesComponent.tsx | 28 +++++++++---------- .../src/components/education/StrikesList.tsx | 20 +++++++------ 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/client/src/components/education/StrikeDetailsModal.tsx b/client/src/components/education/StrikeDetailsModal.tsx index 82281ad4..9ac8cbca 100644 --- a/client/src/components/education/StrikeDetailsModal.tsx +++ b/client/src/components/education/StrikeDetailsModal.tsx @@ -56,8 +56,7 @@ export const StrikeDetailsModal = ({ setStrikeFields(strikeToEdit); setIsEditMode(true); return; - } - else { + } else { setIsEditMode(false); } resetForm(); diff --git a/client/src/components/education/StrikesComponent.tsx b/client/src/components/education/StrikesComponent.tsx index 8e215ff5..1e77ec99 100644 --- a/client/src/components/education/StrikesComponent.tsx +++ b/client/src/components/education/StrikesComponent.tsx @@ -11,36 +11,36 @@ import { useState } from 'react'; import { useTraineeProfileContext } from '../../hooks/useTraineeProfileContext'; export const StrikesComponent = () => { - const [isModalOpen, setIsModalOpen] = useState(false); //NOTE: bool for modal state + const [isModalOpen, setIsModalOpen] = useState(false); - const [modalError, setModalError] = useState(''); //NOTE: string for modal error - const [strikeToEdit, setStrikeToEdit] = useState(null); //NOTE: strike to edit state - const { traineeId } = useTraineeProfileContext(); //NOTE: collects id from context - const { mutate: addStrike, isLoading: addStrikeLoading } = useAddStrike(traineeId); //NOTE: how does mutate work? this is for the database + const [modalError, setModalError] = useState(''); + const [strikeToEdit, setStrikeToEdit] = useState(null); + const { traineeId } = useTraineeProfileContext(); + const { mutate: addStrike, isLoading: addStrikeLoading } = useAddStrike(traineeId); const { mutate: deleteStrike, isLoading: deleteStrikeLoading, error: deleteStrikeError } = useDeleteStrike(traineeId); const { mutate: editStrike, isLoading: editStrikeLoading } = useEditStrike(traineeId); - const { data: strikes, isLoading: strikesLoading, error: strikesError } = useGetStrikes(traineeId); //NOTE: gets strikes and state from database traineeId - const [isConfirmationDialogOpen, setIsConfirmationDialogOpen] = useState(false); //NOTE: bool for confirmation dialog + const { data: strikes, isLoading: strikesLoading, error: strikesError } = useGetStrikes(traineeId); + const [isConfirmationDialogOpen, setIsConfirmationDialogOpen] = useState(false); - const [idToDelete, setIdToDelete] = useState(''); //TODO: how does this work + const [idToDelete, setIdToDelete] = useState(''); const queryClient = useQueryClient(); const handleSuccess = () => { queryClient.invalidateQueries(['strikes', traineeId]); setIsModalOpen(false); }; - const getErrorMessage = (error: Error | unknown) => { //NOTE: gives the error message for the strikes list + const getErrorMessage = (error: Error | unknown) => { return (error as Error).message || 'Unknown error'; }; - const onClickEdit = (id: string) => { //NOTE: edits the id'ed strike + const onClickEdit = (id: string) => { const strike = strikes?.find((strike) => strike.id === id) || null; setStrikeToEdit(strike); setIsModalOpen(true); }; - const onConfirmAdd = async (strike: Strike) => { //NOTE: add strike when confirmed + const onConfirmAdd = async (strike: Strike) => { addStrike(strike, { onSuccess: handleSuccess, onError: (e) => { @@ -49,7 +49,7 @@ export const StrikesComponent = () => { }); }; - const onConfirmEdit = (strike: Strike) => { //NOTE: push edit when confirmed + const onConfirmEdit = (strike: Strike) => { editStrike(strike, { onSuccess: handleSuccess, onError: (e) => { @@ -58,7 +58,7 @@ export const StrikesComponent = () => { }); }; - const onClickDelete = (id: string) => { //NOTE: Shows confirmation button + const onClickDelete = (id: string) => { setIdToDelete(id); setIsConfirmationDialogOpen(true); }; @@ -66,7 +66,7 @@ export const StrikesComponent = () => { /** * Function to enable adding strikes. */ - const onClickAdd = () => { //TODO: Fix this issue + const onClickAdd = () => { setStrikeToEdit(null); setIsModalOpen(true); }; diff --git a/client/src/components/education/StrikesList.tsx b/client/src/components/education/StrikesList.tsx index f1ef10e8..c8cd5aa8 100644 --- a/client/src/components/education/StrikesList.tsx +++ b/client/src/components/education/StrikesList.tsx @@ -7,13 +7,13 @@ import { Strike } from '../../models'; import { formatDateForDisplay } from '../../helpers/dateHelper'; import MarkdownText from '../shared/MarkdownText'; -interface StrikesListProps { //NOTE: seems to hold strikes list +interface StrikesListProps { strikes: Strike[]; onClickEdit: (id: string) => void; onClickDelete: (id: string) => void; } -export const StrikesList: React.FC = ({ strikes, onClickEdit, onClickDelete }) => { //NOTE: so this is making sure that strikes list is a react functional component with strikeslist props +export const StrikesList: React.FC = ({ strikes, onClickEdit, onClickDelete }) => { /** * Formats the strike reason to a readable format * with the first letter capitalized @@ -21,17 +21,16 @@ export const StrikesList: React.FC = ({ strikes, onClickEdit, * @returns The formatted strike reason */ const formatStrikeReason = (reason: string): string => { - return reason.split('-').join(' ').charAt(0).toUpperCase() + reason.split('-').join(' ').slice(1).toLowerCase(); //NOTE: formatter for the comment + return reason.split('-').join(' ').charAt(0).toUpperCase() + reason.split('-').join(' ').slice(1).toLowerCase(); }; - const handleEdit = (id: string) => { //NOTE: what to do for edit and delete which are on the side of each strike + const handleEdit = (id: string) => { onClickEdit(id); }; const handleDelete = (id: string) => { onClickDelete(id); }; - //NOTE: render how the actions look and these are two buttons that call either edit or delete. const renderActions = (id: string) => { return ( @@ -45,7 +44,6 @@ export const StrikesList: React.FC = ({ strikes, onClickEdit, ); }; - //NOTE: the return of the component I assume that here is where the const render actions will be also called. return ( = ({ strikes, onClickEdit, scrollbarWidth: 'thin', }} > - {strikes.length === 0 ? ( //NOTE: add all found elements in the list or none + {strikes.length === 0 ? ( No strikes found ) : ( strikes.map((strike: Strike, index: number) => { - return ( //NOTE: the boxes are keyed so they are found again when needed + return ( = ({ strikes, onClickEdit, {formatDateForDisplay(strike.date)} } - secondary={{strike.comments}} + secondary={ + + {strike.comments} + + } /> {renderActions(strike.id)}