Skip to content

Commit

Permalink
Implement 'Add Filters' example for filter pattern (#4052)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
PixeledCode authored Sep 3, 2024
1 parent bc7d13f commit e4d5814
Show file tree
Hide file tree
Showing 20 changed files with 278 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ export const CustomDateFilter: React.FC<React.PropsWithChildren<FilterDateTimePr
const { search, type, range, customDate } = formData;
const { startDate, startTime, endDate, endTime } = customDate;

const filtered = data.filter(({ uniqueName, sid, roomType, dateCompleted }) => {
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)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export const DefaultFilter: React.FC<React.PropsWithChildren<FilterProps>> = ({
label: "Date range",
component: CustomFilter,
},
sid: {
roomSid: {
label: "Room SID",
component: RoomSidFilter,
},
Expand All @@ -123,6 +123,19 @@ export const DefaultFilter: React.FC<React.PropsWithChildren<FilterProps>> = ({
},
};

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;
Expand Down Expand Up @@ -220,8 +233,8 @@ export const DefaultFilter: React.FC<React.PropsWithChildren<FilterProps>> = ({

{addFiltersList && addFiltersList.length > 0 ? (
<AddFilters
onApply={(_: string, value) => {
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}
Expand All @@ -245,8 +258,16 @@ export const DefaultFilter: React.FC<React.PropsWithChildren<FilterProps>> = ({
) : null}
</FormPillGroup>

<Box display="flex" justifyContent="space-between" alignItems="center" columnGap="space30" marginTop="space50">
<Box display="flex" columnGap="space30">
<Box
display="flex"
flexWrap="wrap"
justifyContent="space-between"
alignItems="center"
columnGap="space30"
rowGap="space30"
marginTop="space50"
>
<Box display="flex" flexWrap="wrap" columnGap="space30" rowGap="space30">
<DetailText marginTop="space0">
<Text as="span" color="colorTextWeak" fontSize="fontSize30">
{filteredTableData.length} result{filteredTableData.length !== 1 && "s"}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const ExtendedDataGrid: React.FC<React.PropsWithChildren<ExtendedDataGrid
<DataGridBody>
{data.map(
({
sid,
roomSid,
uniqueName,
roomType,
participants,
Expand All @@ -47,8 +47,8 @@ export const ExtendedDataGrid: React.FC<React.PropsWithChildren<ExtendedDataGrid
platform,
tags,
}) => (
<DataGridRow key={sid}>
<DataGridCell>{sid}</DataGridCell>
<DataGridRow key={roomSid}>
<DataGridCell>{roomSid}</DataGridCell>
<DataGridCell>{uniqueName}</DataGridCell>
<DataGridCell>{roomType}</DataGridCell>
<DataGridCell>{participants}</DataGridCell>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ export const SampleDataGrid: React.FC<React.PropsWithChildren<SampleDataGridProp
</DataGridRow>
</DataGridHead>
<DataGridBody>
{data.map(({ sid, uniqueName, roomType, participants, dateCompleted }) => (
<DataGridRow key={sid}>
<DataGridCell>{sid}</DataGridCell>
{data.map(({ roomSid, uniqueName, roomType, participants, dateCompleted }) => (
<DataGridRow key={roomSid}>
<DataGridCell>{roomSid}</DataGridCell>
<DataGridCell>{uniqueName}</DataGridCell>
<DataGridCell>{roomType}</DataGridCell>
<DataGridCell>{participants}</DataGridCell>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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 (
<PopoverContainer state={popover}>
<PopoverButton
variant="secondary"
size="rounded_small"
// @ts-expect-error types are wrong
borderRadius="borderRadiusPill"
>
<PopoverButton variant="secondary" size="rounded_small">
<PlusIcon decorative />
<span>Add filters</span>

{value.length > 0 ? (
<Box marginLeft="space20">
<Badge variant="neutral_counter" as="span" size="small">
{value.length}
<Box textAlign="center" minWidth="12px">
{value.length}
</Box>
</Badge>
</Box>
) : null}
Expand All @@ -87,6 +75,7 @@ export const AddFilters: React.FC<{
<Box>
<MultiselectCombobox
state={state}
usePortal={false}
labelText="Search"
selectedItemsLabelText="Selected filters"
items={filteredItems.map((item) => filterMap[item].label)}
Expand All @@ -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 ? (
<Box marginTop="space70">
<CheckboxGroup name="rec-filters" legend="Filters" helpText="Info that helps a user with this field.">
<CheckboxGroup
name={`rec-filters-${useUID()}`}
legend="Filters"
helpText="Info that helps a user with this field."
>
{recommendedFiltersList.map((item) => {
const labelName = filterMap[item].label;
return (
<Checkbox
key={labelName}
id={labelName}
id={labelName + useUID()}
value={labelName}
checked={state.selectedItems.includes(labelName)}
onChange={(e) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,12 @@ export const CustomFilter: React.FC = ({
}
}

const uid = useUID();

return (
<Box>
<RadioGroup
name="custom"
name={`custom-${uid}`}
legend="Date range"
onChange={(value) => {
setSelectedDate(value);
Expand All @@ -79,7 +81,7 @@ export const CustomFilter: React.FC = ({
value={selectedDate}
>
{DATE_RANGES.map(({ name, value }) => (
<Radio key={value} id={value} value={value} name="custom" checked={selectedDate === value}>
<Radio key={value} id={value} value={value} name={`custom-${uid}`} checked={selectedDate === value}>
{name}
</Radio>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -25,12 +26,12 @@ export const DepartmentFilter: React.FC = ({

return (
<Box>
<CheckboxGroup name="department-list" legend="Department" helpText="Select one or more options">
<CheckboxGroup name={`department-list-${useUID()}`} legend="Department" helpText="Select one or more options">
{departmentList.map((item) => {
return (
<Checkbox
key={item}
id={item}
id={item + useUID()}
value={item}
checked={values.includes(item)}
onChange={(e) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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[] {
Expand Down Expand Up @@ -68,6 +69,7 @@ export const HostNameFilter: React.FC<HostNameFilterProps> = ({
<Box>
<MultiselectCombobox
state={state}
usePortal={false}
labelText={label}
selectedItemsLabelText="Selected Host name filters"
items={filteredItems}
Expand All @@ -82,12 +84,12 @@ export const HostNameFilter: React.FC<HostNameFilterProps> = ({
/>

<Box marginTop="space70">
<CheckboxGroup name="recently-used-hostName" legend="Recently used">
<CheckboxGroup name={`recently-used-hostName-${useUID()}`} legend="Recently used">
{(items as string[]).slice(0, 4).map((item) => {
return (
<Checkbox
key={item}
id={item}
id={item + useUID()}
value={item}
checked={state.selectedItems.includes(item)}
onChange={(e) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -25,12 +26,12 @@ export const PlatformFilter: React.FC = ({

return (
<Box>
<CheckboxGroup name="platform-list" legend="Platform" helpText="Select one or more options">
<CheckboxGroup name={`platform-list-${useUID()}`} legend="Platform" helpText="Select one or more options">
{platformList.map((item) => {
return (
<Checkbox
key={item}
id={item}
id={item + useUID()}
value={item}
checked={values.includes(item)}
onChange={(e) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -40,10 +41,12 @@ export const RoomSidFilter: React.FC = ({
onApply,
value,
popover,
onRemove,
}: {
onApply?: (type: string, value: Item[]) => void;
value?: string[];
popover?: ReturnType<typeof usePopoverState>;
onRemove?: () => void;
}) => {
const [inputValue, setInputValue] = React.useState("");

Expand All @@ -70,6 +73,7 @@ export const RoomSidFilter: React.FC = ({
<Box>
<MultiselectCombobox
state={state}
usePortal={false}
labelText="Add filter"
selectedItemsLabelText="Selected filters"
items={filteredItems}
Expand All @@ -87,12 +91,12 @@ export const RoomSidFilter: React.FC = ({
/>

<Box marginTop="space70">
<CheckboxGroup name="recently-used-filters" legend="Recently used">
<CheckboxGroup name={`recently-used-sid-filters-${useUID()}`} legend="Recently used">
{roomSidList.slice(0, 3).map((item) => {
return (
<Checkbox
key={item}
id={item}
id={item + useUID()}
value={item}
checked={state.selectedItems.includes(item)}
onChange={(e) => {
Expand All @@ -116,7 +120,7 @@ export const RoomSidFilter: React.FC = ({
<FilterAction
onApply={() => {
if (onApply && popover) {
onApply("sid", state.selectedItems);
onApply("roomSid", state.selectedItems);
popover.hide();
}
}}
Expand All @@ -128,6 +132,7 @@ export const RoomSidFilter: React.FC = ({
}
: null
}
onRemove={onRemove}
/>
</Box>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -21,17 +22,25 @@ export const RoomTypeFilter: React.FC = ({
setSelectedRoomType(value || "");
}, [value, popover?.visible]);

const uid = useUID();

return (
<Box>
<RadioGroup
name="roomType"
name={`roomType-${uid}`}
legend="Room type"
helpText="Select one option"
onChange={setSelectedRoomType}
value={selectedRoomType}
>
{roomTypes.map((roomType) => (
<Radio key={roomType} id={roomType} value={roomType} name="roomType" checked={selectedRoomType === roomType}>
<Radio
key={roomType}
id={roomType}
value={roomType}
name={`roomType-${uid}`}
checked={selectedRoomType === roomType}
>
{roomType}
</Radio>
))}
Expand Down
Loading

0 comments on commit e4d5814

Please sign in to comment.