From 597d6cc529a78a4f8306ffff4c709b9330476407 Mon Sep 17 00:00:00 2001 From: Darren Walker Date: Tue, 26 Nov 2024 12:44:12 +0000 Subject: [PATCH] add 'delete proposal' button to the Overview Panel, add an "export" common button, some layout and style changes, include hack to rerender the app on proposal deletion --- src/main/webui/src/App2.tsx | 28 ++- .../ProposalEditorView/proposal/Overview.tsx | 183 ++++++++++++------ src/main/webui/src/commonButtons/delete.tsx | 2 +- src/main/webui/src/commonButtons/export.tsx | 25 +++ src/main/webui/src/commonButtons/save.tsx | 18 +- 5 files changed, 178 insertions(+), 78 deletions(-) create mode 100644 src/main/webui/src/commonButtons/export.tsx diff --git a/src/main/webui/src/App2.tsx b/src/main/webui/src/App2.tsx index 380c2257..3cea15b9 100644 --- a/src/main/webui/src/App2.tsx +++ b/src/main/webui/src/App2.tsx @@ -3,7 +3,7 @@ import { useContext, ReactElement, SyntheticEvent, - Context, StrictMode + Context, StrictMode, useReducer } from 'react'; import { QueryClient, @@ -134,13 +134,17 @@ function App2(): ReactElement { const GRAY = theme.colors.gray[6]; + // hack to force the left-hand navbar to update after proposal deletion in Overview panel + // more precisely, when called, "forceUpdate" will make the entire App rerender - use sparingly!! + const [,forceUpdate] = useReducer(x => x + 1, 0); + // the paths to route to. const router = createBrowserRouter( [ { path: "/manager", element: , - errorElement: , + errorElement: , children: [ {index: true, element: }, { @@ -203,7 +207,7 @@ function App2(): ReactElement { { path: "/", element: , - errorElement: , + errorElement: , children: [ {index: true, element: } , { @@ -218,7 +222,8 @@ function App2(): ReactElement { }, { path: "proposal/:selectedProposalCode", - element: , + //'forceUpdate' is called following a proposal deletion in Overview panel + element: , errorElement: , }, { @@ -429,15 +434,18 @@ function App2(): ReactElement { - {(props) => } - + {(props) => + + } + void}): ReactElement { const { selectedProposalCode } = useParams(); + const navigate = useNavigate(); + const {data} = useSupportingDocumentResourceGetSupportingDocuments( {pathParams: {proposalCode: Number(selectedProposalCode)},}, @@ -245,36 +253,6 @@ function OverviewPanel(): ReactElement { ); } - /** - * generates the overview pdf and saves it to the users disk. - * - * code extracted from: https://www.robinwieruch.de/react-component-to-pdf/ - * @return {Promise} promise that the pdf will be saved at some point. - */ - const handleDownloadPdf = (): void => { - // get the overview page to print as well as the proposal data. - const element = printRef.current; - - // ensure there is a rendered overview. - if(element !== null && proposalsData !== undefined && - selectedProposalCode !== undefined && data !== undefined) { - downloadProposal( - element, proposalsData, data, selectedProposalCode).then(); - } else { - // something failed in the rendering of the overview react element or - // extracting the proposal data. - if (element === null) { - console.error( - 'Tried to download a Overview that had not formed ' + - 'correctly.'); - } else { - console.error( - 'Tried to download the proposal data and that had not ' + - 'formed correctly.'); - } - } - }; - /** * handles the title display panel. * @return {ReactElement} the html for the title display panel. @@ -534,48 +512,137 @@ function OverviewPanel(): ReactElement { ) } + + /** + * generates the overview pdf and saves it to the users disk. + * + * code extracted from: https://www.robinwieruch.de/react-component-to-pdf/ + * @return {Promise} promise that the pdf will be saved at some point. + */ + const handleDownloadPdf = (): void => { + // get the overview page to print as well as the proposal data. + const element = printRef.current; + + // ensure there is a rendered overview. + if(element !== null && proposalsData !== undefined && + selectedProposalCode !== undefined && data !== undefined) { + downloadProposal( + element, proposalsData, data, selectedProposalCode).then(); + } else { + // something failed in the rendering of the overview react element or + // extracting the proposal data. + if (element === null) { + console.error( + 'Tried to download a Overview that had not formed ' + + 'correctly.'); + } else { + console.error( + 'Tried to download the proposal data and that had not ' + + 'formed correctly.'); + } + } + }; + + /** * add download button for the proposal to be extracted as a tar ball. * * @return {ReactElement} the html which contains the download button. * @constructor */ - const DownloadButton = (): ReactElement => { - return SaveButton( + const ExportProposal = (): ReactElement => { + return ExportButton( { toolTipLabel: `Export to a file for download`, disabled: false, onClick: handleDownloadPdf, - label: "Export", + label: "Export Proposal", + variant: "filled", + toolTipLabelPosition: "top" }); } + const DeleteProposal = () : ReactElement => { + return DeleteButton( + { + toolTipLabel: "Removes this proposal permanently", + disabled: false, + onClick: confirmDeleteProposal, + label: "Delete Proposal", + variant: "outline" + } + ) + } + + + const confirmDeleteProposal = () : void => { + modals.openConfirmModal({ + title: "Confirm Proposal Deletion", + centered: true, + children: ( + + + Are you sure you want to permanently remove the proposal '{proposalsData?.title!}'? + + + This action cannot be undone. + + + + ), + labels: {confirm: "Yes, delete this proposal", cancel: "No, do not delete!"}, + confirmProps: {color: "red"}, + onConfirm: () => handleDeleteProposal() + }) + } + + + const handleDeleteProposal = () => { + fetchProposalResourceDeleteObservingProposal({ + pathParams: {proposalCode: Number(selectedProposalCode)} + }) + .then(()=> notifySuccess( + "Deletion successful", + "Proposal: '" + proposalsData?.title! + "' has been removed")) + .then(()=> navigate("/")) + .then(() => props.forceUpdate()) + .catch(error => notifyError("Deletion failed", getErrorMessage(error))) + } /** * returns the HTML structure for the overview page. */ return ( - <> - { - proposalsIsLoading ? 'Loading...' : - - -
- - - - - - - - - - -
-
- } - + + + + +
+ + + + +
+
+
+ + + + + + + + + +
+
+
+
); } diff --git a/src/main/webui/src/commonButtons/delete.tsx b/src/main/webui/src/commonButtons/delete.tsx index c1a5fd67..942f8368 100644 --- a/src/main/webui/src/commonButtons/delete.tsx +++ b/src/main/webui/src/commonButtons/delete.tsx @@ -25,7 +25,7 @@ function DeleteButton(props: ClickButtonInterfaceProps): ReactElement { > + + ) +} \ No newline at end of file diff --git a/src/main/webui/src/commonButtons/save.tsx b/src/main/webui/src/commonButtons/save.tsx index 61b8ad94..0f1b4a9b 100644 --- a/src/main/webui/src/commonButtons/save.tsx +++ b/src/main/webui/src/commonButtons/save.tsx @@ -92,17 +92,17 @@ function SubmitButton(props: BasicButtonInterfaceProps): ReactElement { */ export function SaveButton(props: ClickButtonInterfaceProps): ReactElement { return ( - -