From e4d58142dfc0efa172e065e00f69760f190565ee Mon Sep 17 00:00:00 2001 From: Shoaib Ahmed Date: Tue, 3 Sep 2024 13:30:14 +0530 Subject: [PATCH] Implement 'Add Filters' example for filter pattern (#4052) * feat(filter-pattern): replace sid with roomSid * feat(filter-pattern): add usePortal={false} * feat(filter-pattern): add remove button to sid and unique name * feat(filter-pattern): handle state change on add filter item removal * feat(filter-pattern): add 'Add filter' section to website * feat(filter-pattern): improve responsiveness * feat(filter-pattern): add usePortal={false} to filter examples * feat(filter-pattern): add min width to add filter badge * feat(filter-pattern): add unique id to name for checkbox and radio * feat(filter-pattern): add unique id to ids and names for checkbox and radio --- .../components/CustomDateFilterGroup.tsx | 4 +- .../filter/components/DefaultFilter.tsx | 31 +++- .../filter/components/ExtendedDataGrid.tsx | 6 +- .../filter/components/FilterPill.tsx | 2 +- .../filter/components/SampleDataGrid.tsx | 6 +- .../filter/components/filters/AddFilters.tsx | 40 +++--- .../components/filters/CustomFilter.tsx | 6 +- .../components/filters/DepartmentFilter.tsx | 5 +- .../components/filters/HostNameFilter.tsx | 6 +- .../components/filters/PlatformFilter.tsx | 5 +- .../components/filters/RoomSidFilter.tsx | 11 +- .../components/filters/RoomTypeFilter.tsx | 13 +- .../components/filters/StatusFilter.tsx | 6 +- .../filter/components/filters/TagsFilter.tsx | 5 +- .../components/filters/UniqueNameFilter.tsx | 9 +- .../component-examples/filter/constants.ts | 42 +++--- .../src/component-examples/filter/helpers.ts | 20 ++- .../src/component-examples/filter/types.ts | 4 +- .../src/pages/patterns/filter/index.mdx | 134 +++++++++++++++++- .../paste-website/stories/Filter.stories.tsx | 28 ++-- 20 files changed, 278 insertions(+), 105 deletions(-) diff --git a/packages/paste-website/src/component-examples/filter/components/CustomDateFilterGroup.tsx b/packages/paste-website/src/component-examples/filter/components/CustomDateFilterGroup.tsx index cefb5c3adf..f048db78c8 100644 --- a/packages/paste-website/src/component-examples/filter/components/CustomDateFilterGroup.tsx +++ b/packages/paste-website/src/component-examples/filter/components/CustomDateFilterGroup.tsx @@ -80,9 +80,9 @@ export const CustomDateFilter: React.FC { + const filtered = data.filter(({ uniqueName, roomSid, roomType, dateCompleted }) => { return ( - filterBySearchString(uniqueName, sid, search) && + filterBySearchString(uniqueName, roomSid, search) && filterByRoomType(roomType, type) && filterByDateTimeRange(dateCompleted, range, startDate, startTime, endDate, endTime) ); diff --git a/packages/paste-website/src/component-examples/filter/components/DefaultFilter.tsx b/packages/paste-website/src/component-examples/filter/components/DefaultFilter.tsx index 10220e0444..3eb5fbb145 100644 --- a/packages/paste-website/src/component-examples/filter/components/DefaultFilter.tsx +++ b/packages/paste-website/src/component-examples/filter/components/DefaultFilter.tsx @@ -105,7 +105,7 @@ export const DefaultFilter: React.FC> = ({ label: "Date range", component: CustomFilter, }, - sid: { + roomSid: { label: "Room SID", component: RoomSidFilter, }, @@ -123,6 +123,19 @@ export const DefaultFilter: React.FC> = ({ }, }; + React.useEffect(() => { + const newFilters = { ...selectedFilters }; + for (const key in selectedFilters) { + const typedKey = key as FilterListType[0]; + if (!addedFilters.includes(typedKey) && addFiltersList?.includes(typedKey)) { + delete newFilters[key]; + } + } + + setSelectedFilters(newFilters); + handleApplyFilters(newFilters as selectedFilterProps); + }, [addedFilters, addFiltersList]); + function removeFilter(filter: string): void { const newFilters = { ...selectedFilters }; const { [filter]: _, ...rest } = newFilters; @@ -220,8 +233,8 @@ export const DefaultFilter: React.FC> = ({ {addFiltersList && addFiltersList.length > 0 ? ( { - const sluggedList = (value as FilterListType).map((item) => slugify(item)); + onApply={(_: string, addFilterSelectedList) => { + const sluggedList = (addFilterSelectedList as FilterListType).map((item) => slugify(item)); setAddedFilters(sluggedList as FilterListType); }} addFiltersList={addFiltersList} @@ -245,8 +258,16 @@ export const DefaultFilter: React.FC> = ({ ) : null} - - + + {filteredTableData.length} result{filteredTableData.length !== 1 && "s"} diff --git a/packages/paste-website/src/component-examples/filter/components/ExtendedDataGrid.tsx b/packages/paste-website/src/component-examples/filter/components/ExtendedDataGrid.tsx index 7aace71a84..5f09bfe12c 100644 --- a/packages/paste-website/src/component-examples/filter/components/ExtendedDataGrid.tsx +++ b/packages/paste-website/src/component-examples/filter/components/ExtendedDataGrid.tsx @@ -36,7 +36,7 @@ export const ExtendedDataGrid: React.FC {data.map( ({ - sid, + roomSid, uniqueName, roomType, participants, @@ -47,8 +47,8 @@ export const ExtendedDataGrid: React.FC ( - - {sid} + + {roomSid} {uniqueName} {roomType} {participants} diff --git a/packages/paste-website/src/component-examples/filter/components/FilterPill.tsx b/packages/paste-website/src/component-examples/filter/components/FilterPill.tsx index 2b46bd7198..43145d4f62 100644 --- a/packages/paste-website/src/component-examples/filter/components/FilterPill.tsx +++ b/packages/paste-website/src/component-examples/filter/components/FilterPill.tsx @@ -8,7 +8,7 @@ import React from "react"; import type { FilterMapType, ParticipantsType, selectedFilterProps } from "../types"; -const multipleSelectFilterList = new Set(["sid", "uniqueName", "hostName", "tags", "department", "platform"]); +const multipleSelectFilterList = new Set(["roomSid", "uniqueName", "hostName", "tags", "department", "platform"]); const FilterPillView: React.FC<{ label: string; diff --git a/packages/paste-website/src/component-examples/filter/components/SampleDataGrid.tsx b/packages/paste-website/src/component-examples/filter/components/SampleDataGrid.tsx index 01dce8f86d..7a145934b7 100644 --- a/packages/paste-website/src/component-examples/filter/components/SampleDataGrid.tsx +++ b/packages/paste-website/src/component-examples/filter/components/SampleDataGrid.tsx @@ -33,9 +33,9 @@ export const SampleDataGrid: React.FC - {data.map(({ sid, uniqueName, roomType, participants, dateCompleted }) => ( - - {sid} + {data.map(({ roomSid, uniqueName, roomType, participants, dateCompleted }) => ( + + {roomSid} {uniqueName} {roomType} {participants} diff --git a/packages/paste-website/src/component-examples/filter/components/filters/AddFilters.tsx b/packages/paste-website/src/component-examples/filter/components/filters/AddFilters.tsx index 929439bee5..8f5e4c5df2 100644 --- a/packages/paste-website/src/component-examples/filter/components/filters/AddFilters.tsx +++ b/packages/paste-website/src/component-examples/filter/components/filters/AddFilters.tsx @@ -7,9 +7,9 @@ import type { UseMultipleSelectionStateChange } from "@twilio-paste/dropdown-lib import { PlusIcon } from "@twilio-paste/icons/esm/PlusIcon"; import { Popover, PopoverButton, PopoverContainer, usePopoverState } from "@twilio-paste/popover"; import { Text } from "@twilio-paste/text"; +import { useUID } from "@twilio-paste/uid-library"; import React from "react"; -import { slugify } from "../../helpers"; import type { FilterListType, FilterMapType } from "../../types"; import { FilterAction } from "../FilterAction"; @@ -50,34 +50,22 @@ export const AddFilters: React.FC<{ onSelectedItemsChange, }); - /* - * this will be used to set the selected items when the popover is triggered, - * for it to work, we need to fix popover closing on multiselect click - */ - - /* - * React.useEffect(() => { - * if (popover.visible) { - * state.setSelectedItems(value.map((item) => filterMap[item].label)); - * } - * }, [popover.visible]); - */ + React.useEffect(() => { + state.setSelectedItems(value.map((item) => filterMap[item].label)); + }, [value, popover?.visible]); return ( - + Add filters {value.length > 0 ? ( - {value.length} + + {value.length} + ) : null} @@ -87,6 +75,7 @@ export const AddFilters: React.FC<{ filterMap[item].label)} @@ -97,21 +86,24 @@ export const AddFilters: React.FC<{ onSelectedItemsChange={(comboboxItems) => { const { selectedItems } = comboboxItems; if (selectedItems) { - const sluggedItems = selectedItems.map((item) => slugify(item as string)); - state.setSelectedItems(sluggedItems); + state.setSelectedItems(selectedItems); } }} /> {recommendedFiltersList ? ( - + {recommendedFiltersList.map((item) => { const labelName = filterMap[item].label; return ( { diff --git a/packages/paste-website/src/component-examples/filter/components/filters/CustomFilter.tsx b/packages/paste-website/src/component-examples/filter/components/filters/CustomFilter.tsx index 8745275c9c..9f82b3ed6d 100644 --- a/packages/paste-website/src/component-examples/filter/components/filters/CustomFilter.tsx +++ b/packages/paste-website/src/component-examples/filter/components/filters/CustomFilter.tsx @@ -67,10 +67,12 @@ export const CustomFilter: React.FC = ({ } } + const uid = useUID(); + return ( { setSelectedDate(value); @@ -79,7 +81,7 @@ export const CustomFilter: React.FC = ({ value={selectedDate} > {DATE_RANGES.map(({ name, value }) => ( - + {name} ))} diff --git a/packages/paste-website/src/component-examples/filter/components/filters/DepartmentFilter.tsx b/packages/paste-website/src/component-examples/filter/components/filters/DepartmentFilter.tsx index 0464e1566e..e2f93b5ac7 100644 --- a/packages/paste-website/src/component-examples/filter/components/filters/DepartmentFilter.tsx +++ b/packages/paste-website/src/component-examples/filter/components/filters/DepartmentFilter.tsx @@ -2,6 +2,7 @@ import { Box } from "@twilio-paste/box"; import { Checkbox, CheckboxGroup } from "@twilio-paste/checkbox"; import type { Item } from "@twilio-paste/combobox/dist/types"; import type { usePopoverState } from "@twilio-paste/popover"; +import { useUID } from "@twilio-paste/uid-library"; import React from "react"; import { FilterAction } from "../FilterAction"; @@ -25,12 +26,12 @@ export const DepartmentFilter: React.FC = ({ return ( - + {departmentList.map((item) => { return ( { diff --git a/packages/paste-website/src/component-examples/filter/components/filters/HostNameFilter.tsx b/packages/paste-website/src/component-examples/filter/components/filters/HostNameFilter.tsx index 0c7a5be552..e5fcbbec72 100644 --- a/packages/paste-website/src/component-examples/filter/components/filters/HostNameFilter.tsx +++ b/packages/paste-website/src/component-examples/filter/components/filters/HostNameFilter.tsx @@ -5,6 +5,7 @@ import { MultiselectCombobox, useMultiselectCombobox } from "@twilio-paste/combo import type { Item } from "@twilio-paste/combobox/dist/types"; import type { UseMultipleSelectionStateChange } from "@twilio-paste/dropdown-library"; import { Text } from "@twilio-paste/text"; +import { useUID } from "@twilio-paste/uid-library"; import React from "react"; function getFilteredItems(inputValue: string, addFiltersList: string[]): string[] { @@ -68,6 +69,7 @@ export const HostNameFilter: React.FC = ({ = ({ /> - + {(items as string[]).slice(0, 4).map((item) => { return ( { diff --git a/packages/paste-website/src/component-examples/filter/components/filters/PlatformFilter.tsx b/packages/paste-website/src/component-examples/filter/components/filters/PlatformFilter.tsx index 58e4f00c7f..a4b38c60e4 100644 --- a/packages/paste-website/src/component-examples/filter/components/filters/PlatformFilter.tsx +++ b/packages/paste-website/src/component-examples/filter/components/filters/PlatformFilter.tsx @@ -2,6 +2,7 @@ import { Box } from "@twilio-paste/box"; import { Checkbox, CheckboxGroup } from "@twilio-paste/checkbox"; import type { Item } from "@twilio-paste/combobox/dist/types"; import type { usePopoverState } from "@twilio-paste/popover"; +import { useUID } from "@twilio-paste/uid-library"; import React from "react"; import { FilterAction } from "../FilterAction"; @@ -25,12 +26,12 @@ export const PlatformFilter: React.FC = ({ return ( - + {platformList.map((item) => { return ( { diff --git a/packages/paste-website/src/component-examples/filter/components/filters/RoomSidFilter.tsx b/packages/paste-website/src/component-examples/filter/components/filters/RoomSidFilter.tsx index 7dcfc0ded6..564b50cf70 100644 --- a/packages/paste-website/src/component-examples/filter/components/filters/RoomSidFilter.tsx +++ b/packages/paste-website/src/component-examples/filter/components/filters/RoomSidFilter.tsx @@ -5,6 +5,7 @@ import type { Item } from "@twilio-paste/combobox/dist/types"; import type { UseMultipleSelectionStateChange } from "@twilio-paste/dropdown-library"; import type { usePopoverState } from "@twilio-paste/popover"; import { Text } from "@twilio-paste/text"; +import { useUID } from "@twilio-paste/uid-library"; import React from "react"; import { slugify } from "../../helpers"; @@ -40,10 +41,12 @@ export const RoomSidFilter: React.FC = ({ onApply, value, popover, + onRemove, }: { onApply?: (type: string, value: Item[]) => void; value?: string[]; popover?: ReturnType; + onRemove?: () => void; }) => { const [inputValue, setInputValue] = React.useState(""); @@ -70,6 +73,7 @@ export const RoomSidFilter: React.FC = ({ - + {roomSidList.slice(0, 3).map((item) => { return ( { @@ -116,7 +120,7 @@ export const RoomSidFilter: React.FC = ({ { if (onApply && popover) { - onApply("sid", state.selectedItems); + onApply("roomSid", state.selectedItems); popover.hide(); } }} @@ -128,6 +132,7 @@ export const RoomSidFilter: React.FC = ({ } : null } + onRemove={onRemove} /> ); diff --git a/packages/paste-website/src/component-examples/filter/components/filters/RoomTypeFilter.tsx b/packages/paste-website/src/component-examples/filter/components/filters/RoomTypeFilter.tsx index 101cb1f0fb..4cd97cc3e1 100644 --- a/packages/paste-website/src/component-examples/filter/components/filters/RoomTypeFilter.tsx +++ b/packages/paste-website/src/component-examples/filter/components/filters/RoomTypeFilter.tsx @@ -1,6 +1,7 @@ import { Box } from "@twilio-paste/box"; import type { usePopoverState } from "@twilio-paste/popover"; import { Radio, RadioGroup } from "@twilio-paste/radio-group"; +import { useUID } from "@twilio-paste/uid-library"; import React from "react"; import { FilterAction } from "../FilterAction"; @@ -21,17 +22,25 @@ export const RoomTypeFilter: React.FC = ({ setSelectedRoomType(value || ""); }, [value, popover?.visible]); + const uid = useUID(); + return ( {roomTypes.map((roomType) => ( - + {roomType} ))} diff --git a/packages/paste-website/src/component-examples/filter/components/filters/StatusFilter.tsx b/packages/paste-website/src/component-examples/filter/components/filters/StatusFilter.tsx index a668468f99..5caffcab66 100644 --- a/packages/paste-website/src/component-examples/filter/components/filters/StatusFilter.tsx +++ b/packages/paste-website/src/component-examples/filter/components/filters/StatusFilter.tsx @@ -1,6 +1,7 @@ import { Box } from "@twilio-paste/box"; import { Button } from "@twilio-paste/button"; import { Radio, RadioGroup } from "@twilio-paste/radio-group"; +import { useUID } from "@twilio-paste/uid-library"; import React from "react"; export const StatusFilter: React.FC<{ @@ -18,10 +19,11 @@ export const StatusFilter: React.FC<{ setValue(selectedMoreFilters ? (selectedMoreFilters.status as string) || "" : ""); }, [selectedMoreFilters]); + const uid = useUID(); return ( { @@ -36,7 +38,7 @@ export const StatusFilter: React.FC<{ }} > {items.map((item) => ( - + {item} ))} diff --git a/packages/paste-website/src/component-examples/filter/components/filters/TagsFilter.tsx b/packages/paste-website/src/component-examples/filter/components/filters/TagsFilter.tsx index eaa5280054..6dace38415 100644 --- a/packages/paste-website/src/component-examples/filter/components/filters/TagsFilter.tsx +++ b/packages/paste-website/src/component-examples/filter/components/filters/TagsFilter.tsx @@ -1,6 +1,7 @@ import { Box } from "@twilio-paste/box"; import { Button } from "@twilio-paste/button"; import { Checkbox, CheckboxGroup } from "@twilio-paste/checkbox"; +import { useUID } from "@twilio-paste/uid-library"; import React from "react"; export const TagsFilter: React.FC<{ @@ -20,12 +21,12 @@ export const TagsFilter: React.FC<{ return ( - + {(items as string[]).map((item) => { return ( { diff --git a/packages/paste-website/src/component-examples/filter/components/filters/UniqueNameFilter.tsx b/packages/paste-website/src/component-examples/filter/components/filters/UniqueNameFilter.tsx index 4a15184c78..59e176f312 100644 --- a/packages/paste-website/src/component-examples/filter/components/filters/UniqueNameFilter.tsx +++ b/packages/paste-website/src/component-examples/filter/components/filters/UniqueNameFilter.tsx @@ -5,6 +5,7 @@ import type { Item } from "@twilio-paste/combobox/dist/types"; import type { UseMultipleSelectionStateChange } from "@twilio-paste/dropdown-library"; import type { usePopoverState } from "@twilio-paste/popover"; import { Text } from "@twilio-paste/text"; +import { useUID } from "@twilio-paste/uid-library"; import React from "react"; import { slugify } from "../../helpers"; @@ -40,10 +41,12 @@ export const UniqueNameFilter: React.FC = ({ onApply, value, popover, + onRemove, }: { onApply?: (type: string, value: Item[]) => void; value?: string[]; popover?: ReturnType; + onRemove?: () => void; }) => { const [inputValue, setInputValue] = React.useState(""); @@ -70,6 +73,7 @@ export const UniqueNameFilter: React.FC = ({ - + {uniqueNameList.slice(0, 3).map((item) => { return ( { @@ -128,6 +132,7 @@ export const UniqueNameFilter: React.FC = ({ } : null } + onRemove={onRemove} /> ); diff --git a/packages/paste-website/src/component-examples/filter/constants.ts b/packages/paste-website/src/component-examples/filter/constants.ts index f8ec0a6633..cfc6ae587e 100644 --- a/packages/paste-website/src/component-examples/filter/constants.ts +++ b/packages/paste-website/src/component-examples/filter/constants.ts @@ -57,49 +57,49 @@ export const FORM_DEFAULT_VALUES: DateTimeFormValues = { export const TABLE_DATA: TableDataRow[] = [ { - sid: "RM76426b3e9986878d6316a22bf02d6fc3", + roomSid: "RM76426b3e9986878d6316a22bf02d6fc3", uniqueName: "Test Room", roomType: "Group", participants: 50, dateCompleted: today, }, { - sid: "RMmg889qwslt6bijmzfjxleq4fn3eyxwdj6", + roomSid: "RMmg889qwslt6bijmzfjxleq4fn3eyxwdj6", uniqueName: "Quick Sync", roomType: "Peer to Peer", participants: 3, dateCompleted: fourWeeksAgo, }, { - sid: "RM8fcu56sr0tz6cf9a2phf5zo8vv5m65697", + roomSid: "RM8fcu56sr0tz6cf9a2phf5zo8vv5m65697", uniqueName: "My 1:1", roomType: "WebRTC Go", participants: 2, dateCompleted: today, }, { - sid: "RM1z17xfzcjdgwf254jk3k0gtu3r7xzxo0l", + roomSid: "RM1z17xfzcjdgwf254jk3k0gtu3r7xzxo0l", uniqueName: "Team Meeting", roomType: "Group", participants: 23, dateCompleted: oneWeekAgo, }, { - sid: "RMx2fw108pgls48zzf4oh6uzl4ly4s4j6b8", + roomSid: "RMx2fw108pgls48zzf4oh6uzl4ly4s4j6b8", uniqueName: "All Hands", roomType: "Group", participants: 41, dateCompleted: twoWeeksAgo, }, { - sid: "RMwwxh0rskqqy2wzg7t7f3ha4haavymbnqt", + roomSid: "RMwwxh0rskqqy2wzg7t7f3ha4haavymbnqt", uniqueName: "Project Meeting", roomType: "Group", participants: 6, dateCompleted: twoWeeksAgo, }, { - sid: "RMi2or733rf2vd6lziwe8g66smzykqkoplf", + roomSid: "RMi2or733rf2vd6lziwe8g66smzykqkoplf", uniqueName: "Test Room 2", roomType: "WebRTC Go", participants: 1, @@ -109,49 +109,49 @@ export const TABLE_DATA: TableDataRow[] = [ export const STATIC_TABLE_DATA: TableDataRow[] = [ { - sid: "RM76426b3e9986878d6316a22bf02d6fc3", + roomSid: "RM76426b3e9986878d6316a22bf02d6fc3", uniqueName: "Test Room", roomType: "Group", participants: 50, dateCompleted: new Date(2024, 6, 1, 8, 39, 25), }, { - sid: "RMmg889qwslt6bijmzfjxleq4fn3eyxwdj6", + roomSid: "RMmg889qwslt6bijmzfjxleq4fn3eyxwdj6", uniqueName: "Quick Sync", roomType: "Peer to Peer", participants: 3, dateCompleted: new Date(2024, 6, 1, 18, 39, 25), }, { - sid: "RM8fcu56sr0tz6cf9a2phf5zo8vv5m65697", + roomSid: "RM8fcu56sr0tz6cf9a2phf5zo8vv5m65697", uniqueName: "My 1:1", roomType: "WebRTC Go", participants: 2, dateCompleted: new Date(2024, 7, 1, 8, 39, 25), }, { - sid: "RM1z17xfzcjdgwf254jk3k0gtu3r7xzxo0l", + roomSid: "RM1z17xfzcjdgwf254jk3k0gtu3r7xzxo0l", uniqueName: "Team Meeting", roomType: "Group", participants: 23, dateCompleted: new Date(2024, 6, 22, 8, 39, 25), }, { - sid: "RMx2fw108pgls48zzf4oh6uzl4ly4s4j6b8", + roomSid: "RMx2fw108pgls48zzf4oh6uzl4ly4s4j6b8", uniqueName: "All Hands", roomType: "Group", participants: 41, dateCompleted: new Date(2024, 6, 15, 8, 39, 25), }, { - sid: "RMwwxh0rskqqy2wzg7t7f3ha4haavymbnqt", + roomSid: "RMwwxh0rskqqy2wzg7t7f3ha4haavymbnqt", uniqueName: "Project Meeting", roomType: "Group", participants: 6, dateCompleted: new Date(2024, 6, 15, 8, 39, 25), }, { - sid: "RMi2or733rf2vd6lziwe8g66smzykqkoplf", + roomSid: "RMi2or733rf2vd6lziwe8g66smzykqkoplf", uniqueName: "Test Room 2", roomType: "WebRTC Go", participants: 1, @@ -161,7 +161,7 @@ export const STATIC_TABLE_DATA: TableDataRow[] = [ export const EXTENDED_STATIC_TABLE_DATA: ExtendedTableDataRow[] = [ { - sid: "RM76426b3e9986878d6316a22bf02d6fc3", + roomSid: "RM76426b3e9986878d6316a22bf02d6fc3", uniqueName: "Test Room", roomType: "Group", participants: 50, @@ -173,7 +173,7 @@ export const EXTENDED_STATIC_TABLE_DATA: ExtendedTableDataRow[] = [ tags: "Training", }, { - sid: "RMmg889qwslt6bijmzfjxleq4fn3eyxwdj6", + roomSid: "RMmg889qwslt6bijmzfjxleq4fn3eyxwdj6", uniqueName: "Quick Sync", roomType: "Peer to Peer", participants: 3, @@ -185,7 +185,7 @@ export const EXTENDED_STATIC_TABLE_DATA: ExtendedTableDataRow[] = [ tags: "Meeting", }, { - sid: "RM8fcu56sr0tz6cf9a2phf5zo8vv5m65697", + roomSid: "RM8fcu56sr0tz6cf9a2phf5zo8vv5m65697", uniqueName: "My 1:1", roomType: "WebRTC Go", participants: 2, @@ -197,7 +197,7 @@ export const EXTENDED_STATIC_TABLE_DATA: ExtendedTableDataRow[] = [ tags: "Support", }, { - sid: "RM1z17xfzcjdgwf254jk3k0gtu3r7xzxo0l", + roomSid: "RM1z17xfzcjdgwf254jk3k0gtu3r7xzxo0l", uniqueName: "Team Meeting", roomType: "Group", participants: 23, @@ -209,7 +209,7 @@ export const EXTENDED_STATIC_TABLE_DATA: ExtendedTableDataRow[] = [ tags: "External", }, { - sid: "RMx2fw108pgls48zzf4oh6uzl4ly4s4j6b8", + roomSid: "RMx2fw108pgls48zzf4oh6uzl4ly4s4j6b8", uniqueName: "All Hands", roomType: "Group", participants: 41, @@ -221,7 +221,7 @@ export const EXTENDED_STATIC_TABLE_DATA: ExtendedTableDataRow[] = [ tags: "Urgent", }, { - sid: "RMwwxh0rskqqy2wzg7t7f3ha4haavymbnqt", + roomSid: "RMwwxh0rskqqy2wzg7t7f3ha4haavymbnqt", uniqueName: "Project Meeting", roomType: "Group", participants: 6, @@ -233,7 +233,7 @@ export const EXTENDED_STATIC_TABLE_DATA: ExtendedTableDataRow[] = [ tags: "Recurring", }, { - sid: "RMi2or733rf2vd6lziwe8g66smzykqkoplf", + roomSid: "RMi2or733rf2vd6lziwe8g66smzykqkoplf", uniqueName: "Test Room 2", roomType: "WebRTC Go", participants: 1, diff --git a/packages/paste-website/src/component-examples/filter/helpers.ts b/packages/paste-website/src/component-examples/filter/helpers.ts index 95ce426d88..a8f9ff1e1a 100644 --- a/packages/paste-website/src/component-examples/filter/helpers.ts +++ b/packages/paste-website/src/component-examples/filter/helpers.ts @@ -16,9 +16,9 @@ import type { export const formatDate = (date: Date): string => format(date, "yyyy-MM-dd"); export const formatDateTime = (date: Date): string => format(date, "HH:mm:ss 'UTC' yyyy-MM-dd"); -export const filterBySearchString = (uniqueName: string, sid: string, searchValue: string): boolean => { +export const filterBySearchString = (uniqueName: string, roomSid: string, searchValue: string): boolean => { const lowerCaseName = uniqueName.toLocaleLowerCase(); - const lowerCaseSid = sid.toLocaleLowerCase(); + const lowerCaseSid = roomSid.toLocaleLowerCase(); return lowerCaseName.includes(searchValue) || lowerCaseSid.includes(searchValue); }; @@ -89,7 +89,7 @@ export const isValueEmpty = (type: string, value: selectedFilterProps): boolean return Object.values(value)?.includes(""); } - if (["sid", "uniqueName", "hostName", "tags", "department", "platform"].includes(type)) { + if (["roomSid", "uniqueName", "hostName", "tags", "department", "platform"].includes(type)) { return (value as string[])?.length === 0; } @@ -129,19 +129,19 @@ export const applyFilters = (filters: selectedFilterProps, data: ExtendedTableDa const search = value as string; filteredData = filteredData.filter((item) => { - const { uniqueName, roomType, participants, dateCompleted, sid } = item; + const { uniqueName, roomType, participants, dateCompleted, roomSid } = item; return ( uniqueName.toLowerCase().includes(search.toLowerCase()) || roomType.toLowerCase().includes(search.toLowerCase()) || participants.toString().includes(search) || dateCompleted.toString().includes(search) || - sid.toLowerCase().includes(search.toLowerCase()) + roomSid.toLowerCase().includes(search.toLowerCase()) ); }); } - if (["sid", "uniqueName", "hostName", "tags", "department", "platform"].includes(type)) { + if (["roomSid", "uniqueName", "hostName", "tags", "department", "platform"].includes(type)) { const search = value as unknown as string[]; if (search.length > 0) { @@ -158,5 +158,11 @@ export const applyFilters = (filters: selectedFilterProps, data: ExtendedTableDa }; export const slugify = (text: string): string => { - return text.toString().toLowerCase().replace(/\s+/g, "-").replace(/[^\w-]+/g, ""); + return text + .toString() + .toLowerCase() + .split(/\s+/) + .map((word, index) => (index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1))) + .join("") + .replace(/\W+/g, ""); }; diff --git a/packages/paste-website/src/component-examples/filter/types.ts b/packages/paste-website/src/component-examples/filter/types.ts index b34291aeae..21c995bd62 100644 --- a/packages/paste-website/src/component-examples/filter/types.ts +++ b/packages/paste-website/src/component-examples/filter/types.ts @@ -42,7 +42,7 @@ export interface DateTimePopoverProps { errors: DateTimeFormErrors; } export interface TableDataRow { - sid: string; + roomSid: string; uniqueName: string; roomType: RoomTypes; participants: number; @@ -94,7 +94,7 @@ export type FilterListType = Array< | "roomType" | "participants" | "dateCompleted" - | "sid" + | "roomSid" | "uniqueName" | "hostName" | "status" diff --git a/packages/paste-website/src/pages/patterns/filter/index.mdx b/packages/paste-website/src/pages/patterns/filter/index.mdx index 4d1bb77872..2468ba3197 100644 --- a/packages/paste-website/src/pages/patterns/filter/index.mdx +++ b/packages/paste-website/src/pages/patterns/filter/index.mdx @@ -334,9 +334,137 @@ export const MoreFilterPatternExample = ({data, filterList}): React.ReactNode => An "Add filters" Popover allows users to add a filter value from a predefined list of filter options. Use it in scenarios where the list of filters may not be relevant to all users, or the user would benefit from creating their own filters set. - - Demo coming soon! - + { + const [selectedFilters, setSelectedFilters] = React.useState({}); + const pillState = useFormPillState(); + const [filteredTableData, setFilteredTableData] = React.useState(data); + React.useEffect(() => { + const newFilters = { ...selectedFilters }; + for (const key in selectedFilters) { + const typedKey = key as FilterListType[0]; + if (!addedFilters.includes(typedKey) && addFiltersList?.includes(typedKey)) { + delete newFilters[key]; + } + } + setSelectedFilters(newFilters); + handleApplyFilters(newFilters as selectedFilterProps); + }, [addedFilters, addFiltersList]); + function removeFilter(filter: string): void { + const newFilters = { ...selectedFilters }; + const { [filter]: _, ...rest } = newFilters; + setSelectedFilters(rest); + handleApplyFilters(rest as selectedFilterProps); + } + return ( + <> + Filter + + {filterList.map((pill) => { + return ( + + + + {!isSelected ? : null} + + + + + // Create different filter components + + + ); + })} + {addedFilters.length > 0 + ? addedFilters.map((pill: string) => { + return ( + { + removeFilter(pill); + }} + onApply={(type: string, value) => { + if (!value || (Array.isArray(value) && value.length === 0)) { + removeFilter(type); + return; + } + addFilter(type, value); + }} + onRemove={() => { + const newFilters = addedFilters.filter((item) => item !== pill); + setAddedFilters(newFilters); + removeFilter(pill); + }} + /> + ); + }) + : null} + {addFiltersList && addFiltersList.length > 0 ? ( + { + const sluggedList = (addFilterSelectedList as FilterListType).map((item) => slugify(item)); + setAddedFilters(sluggedList as FilterListType); + }} + addFiltersList={addFiltersList} + filterMap={filterMap} + recommendedFiltersList={recommendedFiltersList} + value={addedFilters} + /> + ) : null} + + + + + + {filteredTableData.length} result{filteredTableData.length !== 1 && "s"} + + + {filteredTableData.length !== data.length ? ( + + ) : null} + + + + + ) +}`} +/> + +#### Surfacing results + + Selected filters will be added to the filter bar where they will become functional. + + Added filters behave as a normal filter with the only difference being they can be removed. + + Added filters can be removed through the “Add filters” Popover or through the specific filter’s Popover. + + + + + + + + ## Composition diff --git a/packages/paste-website/stories/Filter.stories.tsx b/packages/paste-website/stories/Filter.stories.tsx index c43b8c4ea6..29b51acd4d 100644 --- a/packages/paste-website/stories/Filter.stories.tsx +++ b/packages/paste-website/stories/Filter.stories.tsx @@ -35,21 +35,19 @@ ConditionalFilterExample.parameters = { padding: false, }; -/* - * export const AddFilterExample = (): JSX.Element => { - * const addFilterList: FilterListType = ["roomType", "participants"]; - * const addFiltersList: FilterListType = ["sid", "uniqueName", "participants"]; - * const recommendedFiltersList: FilterListType = ["uniqueName", "participants"]; - * return ( - * - * ); - * }; - */ +export const AddFilterExample = (): JSX.Element => { + const addFilterList: FilterListType = ["roomType", "dateCompleted"]; + const addFiltersList: FilterListType = ["roomSid", "uniqueName", "participants"]; + const recommendedFiltersList: FilterListType = ["uniqueName", "participants"]; + return ( + + ); +}; export const MoreFilterExample = (): JSX.Element => { return ;