From 4f70739749c2a8fcfc36c10a6374329ea0a81b85 Mon Sep 17 00:00:00 2001 From: Sven van de Scheur Date: Fri, 11 Oct 2024 15:20:48 +0200 Subject: [PATCH 1/4] :bug: #393 - fix: prevent API calls from being made when selecting zaken and improve review flow selection behaviour --- .../destructionlist/abstract/BaseListView.tsx | 8 ++++++-- .../destructionlist/hooks/useZaakSelection.ts | 6 ------ .../review/DestructionListReview.tsx | 14 ++++++++++++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/frontend/src/pages/destructionlist/abstract/BaseListView.tsx b/frontend/src/pages/destructionlist/abstract/BaseListView.tsx index 8ab8a3e7..86200060 100644 --- a/frontend/src/pages/destructionlist/abstract/BaseListView.tsx +++ b/frontend/src/pages/destructionlist/abstract/BaseListView.tsx @@ -51,7 +51,8 @@ export type BaseListViewProps = React.PropsWithChildren<{ dataGridProps?: Partial; - onClearZaakSelection?: () => void; // FIXME: REMOVE? + onClearZaakSelection?: () => void; + onSelectionChange?: (rows: AttributeData[]) => void; }>; export function BaseListView({ @@ -78,6 +79,7 @@ export function BaseListView({ children, onClearZaakSelection, + onSelectionChange, }: BaseListViewProps) { const { state } = useNavigation(); const [page, setPage] = usePage(); @@ -182,7 +184,8 @@ export function BaseListView({ allowSelectAllPages, allPagesSelected, count: paginatedZaken.count, - equalityChecker: (a, b) => a.uuid === b.uuid || a.url === b.url, + equalityChecker: (a, b) => + a && b && (a.uuid === b.uuid || a.url === b.url), fields, filterTransform, loading: state === "loading", @@ -199,6 +202,7 @@ export function BaseListView({ onPageChange: setPage, onSelect: handleSelect, onSelectAllPages: handleSelectAllPages, + onSelectionChange: onSelectionChange, onSort: setSort, ...dataGridProps, diff --git a/frontend/src/pages/destructionlist/hooks/useZaakSelection.ts b/frontend/src/pages/destructionlist/hooks/useZaakSelection.ts index 97a953fd..299e38ea 100644 --- a/frontend/src/pages/destructionlist/hooks/useZaakSelection.ts +++ b/frontend/src/pages/destructionlist/hooks/useZaakSelection.ts @@ -1,6 +1,5 @@ import { AttributeData } from "@maykin-ui/admin-ui"; import { useEffect, useMemo, useState } from "react"; -import { useRevalidator } from "react-router-dom"; import { ZaakSelection, @@ -61,8 +60,6 @@ export function useZaakSelection( clearZaakSelection: ZaakSelectionClearer; }, ] { - const revalidator = useRevalidator(); - // All pages selected. const [allPagesSelectedState, setAllPagesSelectedState] = useState(); @@ -255,7 +252,6 @@ export function useZaakSelection( await _updatePageSpecificZaakSelectionState(); await _updateSelectionSizeState(); - revalidator.revalidate(); }; /** @@ -270,7 +266,6 @@ export function useZaakSelection( _updatePageSpecificZaakSelectionState(); await _updateAllPagesSelectedState(selected); - revalidator.revalidate(); }; /** @@ -280,7 +275,6 @@ export function useZaakSelection( await libClearZaakSelection(storageKey); await _updateAllPagesSelectedState(false); setZaakSelectionState({}); - revalidator.revalidate(); }; return [ diff --git a/frontend/src/pages/destructionlist/review/DestructionListReview.tsx b/frontend/src/pages/destructionlist/review/DestructionListReview.tsx index b6e24990..f0d5f4d6 100644 --- a/frontend/src/pages/destructionlist/review/DestructionListReview.tsx +++ b/frontend/src/pages/destructionlist/review/DestructionListReview.tsx @@ -8,7 +8,7 @@ import { usePrompt, } from "@maykin-ui/admin-ui"; import React, { useMemo } from "react"; -import { useLoaderData } from "react-router-dom"; +import { useLoaderData, useRevalidator } from "react-router-dom"; import { useSubmitAction } from "../../../hooks"; import { ZaakReview } from "../../../lib/api/review"; @@ -28,6 +28,7 @@ export const getDestructionListReviewKey = (id: string) => */ export function DestructionListReviewPage() { const prompt = usePrompt(); + const revalidator = useRevalidator(); // rows: AttributeData[], selected: boolean const { @@ -48,7 +49,6 @@ export function DestructionListReviewPage() { // The object list of the current page with review actions appended. const objectList = useMemo(() => { - // console.log("objectList"); return paginatedZaken.results.map((zaak) => { const badge = zaakReviewStatusBadges[zaak.url as string].badge; const actions = getActionsToolbarForZaak(zaak); @@ -282,6 +282,14 @@ export function DestructionListReviewPage() { return { approved }; }; + /** + * Gets called when the selection changes outside of the per-zaak toolbar. + * Revalidates the loader so the selection is up2date. + */ + const handleSelectionChange = () => { + revalidator.revalidate(); + }; + return ( ); } From 19caf8d77acc81720b8b91e041e3e71f4ac48b46 Mon Sep 17 00:00:00 2001 From: Sven van de Scheur Date: Fri, 11 Oct 2024 15:30:43 +0200 Subject: [PATCH 2/4] :arrow_up: - chore: update @maykin-ui/admin-ui --- frontend/package-lock.json | 107 ++++++++++++++++++++++++++++++++----- frontend/package.json | 2 +- 2 files changed, 94 insertions(+), 15 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 23741a60..578509cb 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,7 +8,7 @@ "name": "frontend", "version": "0.1.0", "dependencies": { - "@maykin-ui/admin-ui": "^0.0.35", + "@maykin-ui/admin-ui": "^0.0.36", "@storybook/test-runner": "^0.18.2", "@testing-library/jest-dom": "^5.17.0", "@testing-library/user-event": "^13.5.0", @@ -54,6 +54,75 @@ "webpack": "^5.91.0" } }, + "../../maykin-ui": { + "name": "@maykin-ui/admin-ui", + "version": "0.0.36", + "extraneous": true, + "license": "MIT", + "dependencies": { + "@floating-ui/react": "^0.26.6", + "@heroicons/react": "^2.1.1", + "clsx": "^2.1.0", + "react-datepicker": "^6.9.0" + }, + "devDependencies": { + "@chromatic-com/storybook": "^1.6.0", + "@commitlint/cli": "^19.0.0", + "@commitlint/config-conventional": "^19.0.0", + "@formatjs/cli": "^6.2.7", + "@formatjs/ts-transformer": "^3.13.12", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-terser": "^0.4.4", + "@storybook/addon-essentials": "^8.1.11", + "@storybook/addon-interactions": "^8.1.11", + "@storybook/addon-links": "^8.1.11", + "@storybook/addon-onboarding": "^8.1.11", + "@storybook/addon-themes": "^8.1.11", + "@storybook/addon-webpack5-compiler-swc": "^1.0.4", + "@storybook/blocks": "^8.1.11", + "@storybook/react": "^8.1.11", + "@storybook/react-webpack5": "^8.1.11", + "@storybook/test": "^8.1.11", + "@storybook/test-runner": "^0.19.0", + "@trivago/prettier-plugin-sort-imports": "^4.3.0", + "@types/react": "^18.0.0", + "@types/react-datepicker": "^6.2.0", + "@types/react-dom": "^18.0.0", + "@typescript-eslint/eslint-plugin": "^6.17.0", + "@typescript-eslint/parser": "^6.17.0", + "commitlint": "^19.0.0", + "concurrently": "^8.2.2", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.2", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-storybook": "^0.8.0", + "formik": "^2.4.5", + "http-server": "^14.1.1", + "husky": "^8.0.3", + "lint-staged": "^15.2.0", + "postcss-url": "^10.1.3", + "prettier": "^3.1.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "rollup": "^4.9.2", + "rollup-plugin-dts": "^6.1.0", + "rollup-plugin-peer-deps-external": "^2.2.4", + "rollup-plugin-styler": "^1.8.0", + "rollup-plugin-typescript2": "^0.36.0", + "sass": "^1.69.7", + "sass-loader": "^13.3.3", + "storybook": "^8.1.11", + "ts-loader": "^9.5.1", + "tslib": "^2.6.2", + "typescript": "^5.3.3" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, "node_modules/@adobe/css-tools": { "version": "4.3.3", "license": "MIT" @@ -2314,14 +2383,16 @@ }, "node_modules/@floating-ui/core": { "version": "1.6.8", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", "dependencies": { "@floating-ui/utils": "^0.2.8" } }, "node_modules/@floating-ui/dom": { "version": "1.6.11", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz", + "integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==", "dependencies": { "@floating-ui/core": "^1.6.0", "@floating-ui/utils": "^0.2.8" @@ -2329,7 +2400,8 @@ }, "node_modules/@floating-ui/react": { "version": "0.26.24", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.24.tgz", + "integrity": "sha512-2ly0pCkZIGEQUq5H8bBK0XJmc1xIK/RM3tvVzY3GBER7IOD1UgmC2Y2tjj4AuS+TC+vTE1KJv2053290jua0Sw==", "dependencies": { "@floating-ui/react-dom": "^2.1.2", "@floating-ui/utils": "^0.2.8", @@ -2342,7 +2414,8 @@ }, "node_modules/@floating-ui/react-dom": { "version": "2.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", "dependencies": { "@floating-ui/dom": "^1.0.0" }, @@ -2353,7 +2426,8 @@ }, "node_modules/@floating-ui/utils": { "version": "0.2.8", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" }, "node_modules/@hapi/hoek": { "version": "9.3.0", @@ -2368,7 +2442,8 @@ }, "node_modules/@heroicons/react": { "version": "2.1.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.1.5.tgz", + "integrity": "sha512-FuzFN+BsHa+7OxbvAERtgBTNeZpUjgM/MIizfVkSCL2/edriN0Hx/DWRCR//aPYwO5QX/YlgLGXk+E3PcfZwjA==", "peerDependencies": { "react": ">= 16" } @@ -3559,9 +3634,9 @@ "license": "MIT" }, "node_modules/@maykin-ui/admin-ui": { - "version": "0.0.35", - "resolved": "https://registry.npmjs.org/@maykin-ui/admin-ui/-/admin-ui-0.0.35.tgz", - "integrity": "sha512-AH4+YJnJhAF0vqd1Z/TyEM2QyzulvawMRZNdsUIa2OkUfHwtiz6lSKh5Hf6+S4aYFkPfwGKrSX6YW/LX1bueOg==", + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@maykin-ui/admin-ui/-/admin-ui-0.0.36.tgz", + "integrity": "sha512-mHnvLVZKnlBFeSBdknIWSdiVvkRLjNzI9WE6AT0EbLPDRN7zxiAu2vTXHRItDx5kPKULIndZr0EwZBOGFXpI9Q==", "dependencies": { "@floating-ui/react": "^0.26.6", "@heroicons/react": "^2.1.1", @@ -10962,7 +11037,8 @@ }, "node_modules/clsx": { "version": "2.1.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "engines": { "node": ">=6" } @@ -21657,7 +21733,8 @@ }, "node_modules/react-datepicker": { "version": "6.9.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-6.9.0.tgz", + "integrity": "sha512-QTxuzeem7BUfVFWv+g5WuvzT0c5BPo+XTCNbMTZKSZQLU+cMMwSUHwspaxuIcDlwNcOH0tiJ+bh1fJ2yxOGYWA==", "dependencies": { "@floating-ui/react": "^0.26.2", "clsx": "^2.1.0", @@ -21923,7 +22000,8 @@ }, "node_modules/react-onclickoutside": { "version": "6.13.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.1.tgz", + "integrity": "sha512-LdrrxK/Yh9zbBQdFbMTXPp3dTSN9B+9YJQucdDu3JNKRrbdU+H+/TVONJoWtOwy4II8Sqf1y/DTI6w/vGPYW0w==", "funding": { "type": "individual", "url": "https://github.com/Pomax/react-onclickoutside/blob/master/FUNDING.md" @@ -23879,7 +23957,8 @@ }, "node_modules/tabbable": { "version": "6.2.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" }, "node_modules/tailwindcss": { "version": "3.4.3", diff --git a/frontend/package.json b/frontend/package.json index 7fe70ddf..bca2a91a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { - "@maykin-ui/admin-ui": "^0.0.35", + "@maykin-ui/admin-ui": "^0.0.36", "@storybook/test-runner": "^0.18.2", "@testing-library/jest-dom": "^5.17.0", "@testing-library/user-event": "^13.5.0", From 81047c2571719ba6ef5b4aeaadeb7b8350f705f0 Mon Sep 17 00:00:00 2001 From: Sven van de Scheur Date: Fri, 11 Oct 2024 15:31:18 +0200 Subject: [PATCH 3/4] :style: #393 - style: alter styling of destruction list create modal form --- .../src/pages/destructionlist/create/DestructionListCreate.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/pages/destructionlist/create/DestructionListCreate.tsx b/frontend/src/pages/destructionlist/create/DestructionListCreate.tsx index 1264f5c1..28e60e4e 100644 --- a/frontend/src/pages/destructionlist/create/DestructionListCreate.tsx +++ b/frontend/src/pages/destructionlist/create/DestructionListCreate.tsx @@ -131,6 +131,7 @@ export function DestructionListCreatePage() {
Date: Fri, 11 Oct 2024 16:08:01 +0200 Subject: [PATCH 4/4] :bug: #393 - fix: various UI issues related to the selection state --- .../destructionlist/abstract/BaseListView.tsx | 39 +++++++++++-------- .../create/DestructionListCreate.tsx | 2 - .../DestructionListEdit.tsx | 1 + .../DestructionListProcessReview.tsx | 4 -- .../destructionlist/hooks/useZaakSelection.ts | 13 +------ 5 files changed, 24 insertions(+), 35 deletions(-) diff --git a/frontend/src/pages/destructionlist/abstract/BaseListView.tsx b/frontend/src/pages/destructionlist/abstract/BaseListView.tsx index 86200060..0de14dc8 100644 --- a/frontend/src/pages/destructionlist/abstract/BaseListView.tsx +++ b/frontend/src/pages/destructionlist/abstract/BaseListView.tsx @@ -144,23 +144,28 @@ export function BaseListView({ // Selection actions. const getSelectionActions = useCallback(() => { - const fixedItems = - selectable && hasSelection - ? ([ - { - children: ( - <> - - Huidige selectie wissen - - ), - variant: "warning", - wrap: false, - onClick: handleClearZaakSelection, - }, - ] as ButtonProps[]) - : []; - return [...(selectionActions || []), ...fixedItems]; + const disabled = selectable && hasSelection; + const dynamicItems = (selectionActions || []).map((props) => + Object.hasOwn(props, "disabled") + ? props + : { ...props, disabled: selectable && !hasSelection }, + ); + const fixedItems = disabled + ? ([ + { + children: ( + <> + + Huidige selectie wissen + + ), + variant: "warning", + wrap: false, + onClick: handleClearZaakSelection, + }, + ] as ButtonProps[]) + : []; + return [...dynamicItems, ...fixedItems]; }, [selectable, hasSelection, selectedZakenOnPage, selectionActions]); return ( diff --git a/frontend/src/pages/destructionlist/create/DestructionListCreate.tsx b/frontend/src/pages/destructionlist/create/DestructionListCreate.tsx index 28e60e4e..cadd6e3e 100644 --- a/frontend/src/pages/destructionlist/create/DestructionListCreate.tsx +++ b/frontend/src/pages/destructionlist/create/DestructionListCreate.tsx @@ -113,8 +113,6 @@ export function DestructionListCreatePage() { Vernietigingslijst opstellen ), - disabled: !allPagesSelected && !hasSelection, - variant: "primary", wrap: false, onClick: handleClick, diff --git a/frontend/src/pages/destructionlist/detail/components/DestructionListEdit/DestructionListEdit.tsx b/frontend/src/pages/destructionlist/detail/components/DestructionListEdit/DestructionListEdit.tsx index 87ee9bf9..73f3f6f9 100644 --- a/frontend/src/pages/destructionlist/detail/components/DestructionListEdit/DestructionListEdit.tsx +++ b/frontend/src/pages/destructionlist/detail/components/DestructionListEdit/DestructionListEdit.tsx @@ -109,6 +109,7 @@ export function DestructionListEdit() { Annuleren ), + disabled: false, // Set explicitly to prevent automatic value based on selection presence. wrap: false, onClick: () => handleSetEditing(false), }, diff --git a/frontend/src/pages/destructionlist/detail/components/DestructionListProcessReview/DestructionListProcessReview.tsx b/frontend/src/pages/destructionlist/detail/components/DestructionListProcessReview/DestructionListProcessReview.tsx index fcd93094..b11ce219 100644 --- a/frontend/src/pages/destructionlist/detail/components/DestructionListProcessReview/DestructionListProcessReview.tsx +++ b/frontend/src/pages/destructionlist/detail/components/DestructionListProcessReview/DestructionListProcessReview.tsx @@ -142,9 +142,6 @@ export function DestructionListProcessReview() { }; }, [reviewItems, objectList]); - // Selection actions based on `editingState`. - const selectionActions: ButtonProps[] = useMemo(() => [], []); - /** * Gets called when te selection is cleared. */ @@ -227,7 +224,6 @@ export function DestructionListProcessReview() { paginatedZaken={paginatedZaken} secondaryNavigationItems={secondaryNavigationItems} selectable="visible" - selectionActions={selectionActions} storageKey={storageKey} onClearZaakSelection={handleClearSelection} > diff --git a/frontend/src/pages/destructionlist/hooks/useZaakSelection.ts b/frontend/src/pages/destructionlist/hooks/useZaakSelection.ts index 299e38ea..5690ffe8 100644 --- a/frontend/src/pages/destructionlist/hooks/useZaakSelection.ts +++ b/frontend/src/pages/destructionlist/hooks/useZaakSelection.ts @@ -5,7 +5,6 @@ import { ZaakSelection, addToZaakSelection, getAllZakenSelected, - getFilteredZaakSelection, getZaakSelectionItem, getZaakSelectionSize, clearZaakSelection as libClearZaakSelection, @@ -63,9 +62,6 @@ export function useZaakSelection( // All pages selected. const [allPagesSelectedState, setAllPagesSelectedState] = useState(); - // Has selection items. - const [hasSelectionState, setHasSelectionState] = useState(); - // Selection count const [selectionSizeState, setSelectionSizeState] = useState(0); @@ -82,13 +78,6 @@ export function useZaakSelection( } }); - getFilteredZaakSelection(storageKey).then((zs) => { - const hasSelection = Object.keys(zs).length > 0; - if (hasSelection !== hasSelectionState) { - setHasSelectionState(hasSelection); - } - }); - getZaakSelectionSize(storageKey).then((size) => { if (size !== selectionSizeState) { setSelectionSizeState(size); @@ -281,7 +270,7 @@ export function useZaakSelection( selectedZakenOnPage, onSelect, { - hasSelection: Boolean(hasSelectionState || allPagesSelectedState), + hasSelection: Boolean(selectionSizeState || allPagesSelectedState), allPagesSelected: Boolean(allPagesSelectedState), selectionSize: selectionSizeState, deSelectedZakenOnPage,