From 0686c529b1f91e9d6ec7bfe66624a914e07b4b81 Mon Sep 17 00:00:00 2001 From: Wayne Date: Tue, 26 Mar 2024 22:13:30 +0900 Subject: [PATCH] Add toggle for task groups --- src/app/api/projects/index.ts | 27 ---------- .../TransferList/MultiSelectList.tsx | 51 ++++++++++++++++--- src/components/TransferList/TransferList.tsx | 43 +++++++++++++++- 3 files changed, 85 insertions(+), 36 deletions(-) diff --git a/src/app/api/projects/index.ts b/src/app/api/projects/index.ts index 7664ecb..82440a9 100644 --- a/src/app/api/projects/index.ts +++ b/src/app/api/projects/index.ts @@ -65,30 +65,3 @@ export const fetchProjectCategories = cache(async () => { }, ); }); - -const mockProjects: ProjectResult[] = [ - { - id: 1, - code: "M1001", - name: "Consultancy Project A", - category: "Confirmed Project", - team: "TW", - client: "Client A", - }, - { - id: 2, - code: "M1002", - name: "Consultancy Project B", - category: "Project to be bidded", - team: "WY", - client: "Client B", - }, - { - id: 3, - code: "S1001", - name: "Consultancy Project C", - category: "Confirmed Project", - team: "WY", - client: "Client C", - }, -]; diff --git a/src/components/TransferList/MultiSelectList.tsx b/src/components/TransferList/MultiSelectList.tsx index 1c8825a..6406d86 100644 --- a/src/components/TransferList/MultiSelectList.tsx +++ b/src/components/TransferList/MultiSelectList.tsx @@ -20,6 +20,9 @@ import { LabelGroup, LabelWithId, TransferListProps } from "./TransferList"; import { useTranslation } from "react-i18next"; import uniqBy from "lodash/uniqBy"; import groupBy from "lodash/groupBy"; +import intersectionBy from "lodash/intersectionBy"; +import union from "lodash/union"; +import differenceBy from "lodash/differenceBy"; export const MultiSelectList: React.FC = ({ allItems, @@ -53,15 +56,28 @@ export const MultiSelectList: React.FC = ({ [allItems, onChange], ); - const handleToggleAll = useCallback( - () => () => { - if (selectedItems.length === allItems.length) { - onChange([]); + const handleToggleAll = useCallback(() => { + if (selectedItems.length === allItems.length) { + onChange([]); + } else { + onChange(allItems); + } + }, [allItems, onChange, selectedItems.length]); + + const handleToggleAllInGroup = useCallback( + (groupItems: LabelWithId[]) => () => { + const selectedGroupItems = intersectionBy( + selectedItems, + groupItems, + "id", + ); + if (selectedGroupItems.length !== groupItems.length) { + onChange(union(selectedItems, groupItems)); } else { - onChange(allItems); + onChange(differenceBy(selectedItems, groupItems, "id")); } }, - [allItems, onChange, selectedItems.length], + [onChange, selectedItems], ); const { t } = useTranslation(); @@ -117,7 +133,7 @@ export const MultiSelectList: React.FC = ({ direction="row" paddingY={1} paddingX={3} - onClick={handleToggleAll()} + onClick={handleToggleAll} > = ({ {groups.flatMap((group) => { const groupItems = groupedItems[group.id]; + const selectedGroupItems = intersectionBy( + selectedItems, + groupItems, + "id", + ); if (!groupItems) return null; return [ - {group.name} + + + {group.name} + , ...groupItems.map((item) => { return ( diff --git a/src/components/TransferList/TransferList.tsx b/src/components/TransferList/TransferList.tsx index b7c5985..84cd468 100644 --- a/src/components/TransferList/TransferList.tsx +++ b/src/components/TransferList/TransferList.tsx @@ -19,6 +19,8 @@ import ListSubheader from "@mui/material/ListSubheader"; import groupBy from "lodash/groupBy"; import uniqBy from "lodash/uniqBy"; import { useTranslation } from "react-i18next"; +import union from "lodash/union"; +import intersectionBy from "lodash/intersectionBy"; export interface LabelGroup { id: number; @@ -47,6 +49,10 @@ interface ItemListProps { items: LabelWithId[], checkedItems: LabelWithId[], ) => React.MouseEventHandler; + handleToggleAllInGroup: ( + groupItems: LabelWithId[], + checkedItems: LabelWithId[], + ) => React.MouseEventHandler; handleToggle: (item: LabelWithId) => React.MouseEventHandler; } @@ -56,6 +62,7 @@ const ItemList: React.FC = ({ label, handleToggle, handleToggleAll, + handleToggleAllInGroup, }) => { const { t } = useTranslation(); const groups: LabelGroup[] = uniqBy( @@ -111,14 +118,34 @@ const ItemList: React.FC = ({ > {groups.map((group) => { const groupItems = groupedItems[group.id]; + const selectedGroupItems = intersectionBy( + checkedItems, + groupItems, + "id", + ); if (!groupItems) return null; return ( + + + {group.name} {groupItems.map((item) => { @@ -210,6 +237,18 @@ const TransferList: React.FC = ({ setCheckedList(differenceBy(checkedList, rightListChecked, "id")); }; + const handleToggleAllInGroup = React.useCallback( + (groupItems: LabelWithId[], checkedItems: LabelWithId[]) => () => { + const selectedGroupItems = intersectionBy(checkedItems, groupItems, "id"); + if (selectedGroupItems.length !== groupItems.length) { + setCheckedList(union(checkedList, groupItems)); + } else { + setCheckedList(differenceBy(checkedList, groupItems, "id")); + } + }, + [checkedList], + ); + return ( = ({ label={allItemsLabel} handleToggleAll={handleToggleAll} handleToggle={handleToggle} + handleToggleAllInGroup={handleToggleAllInGroup} /> = ({ label={selectedItemsLabel} handleToggleAll={handleToggleAll} handleToggle={handleToggle} + handleToggleAllInGroup={handleToggleAllInGroup} />