Skip to content

Commit de4108e

Browse files
committed
udpate store only if filter number is changed
1 parent 464b332 commit de4108e

File tree

4 files changed

+54
-42
lines changed

4 files changed

+54
-42
lines changed

apps/react-starter/e2e/devices.spec.ts renamed to apps/react-starter/e2e/devices.e2e.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ test("filter for specific deviceName", async ({ page }) => {
2121
await filterDevicePageByDeviceName(page, "s71200");
2222

2323
const aggrid = page.locator(".ag-root-wrapper");
24-
const rows = aggrid.locator(".ag-row");
24+
const rows = aggrid.locator(".ag-center-cols-container .ag-row");
2525

2626
await expect(rows).toHaveCount(1, {
2727
// AG-Grid takes some time to filter the rows

apps/react-starter/playwright.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { defineConfig, devices } from "@playwright/test";
1414
export default defineConfig({
1515
/* Directory to search for tests */
1616
testDir: "./e2e",
17+
testMatch: "**/*.e2e.ts",
1718
/* Run tests in files in parallel */
1819
fullyParallel: true,
1920
/* Fail the build on CI if you accidentally left test.only in the source code. */

apps/react-starter/src/pages/devices/index.tsx

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* LICENSE file in the root directory of this source tree.
88
*/
99

10-
import { useEffect, useState } from "react";
10+
import { useCallback, useEffect, useState } from "react";
1111
import {
1212
IxButton,
1313
IxCategoryFilter,
@@ -23,48 +23,64 @@ import Overview from "./components/overview";
2323
import show from "./components/modal/index.tsx";
2424
import { useDataStore, useFilterStore } from "../store/device-store.ts";
2525
import { MockData } from "../../types";
26+
import { FilterState } from "@siemens/ix";
2627

27-
const DevicesPage = () => {
28+
type Categories = Record<
29+
string,
30+
{
31+
label: string;
32+
options: string[];
33+
}
34+
>;
35+
36+
function createUniqueValueArray(devices: MockData[], key: string) {
37+
return Array.from(new Set(devices.map<string>((device) => device[key as keyof MockData] ?? "")));
38+
}
39+
40+
const useCategories = () => {
2841
const { devices } = useDataStore();
29-
const { filter, setFilter } = useFilterStore();
30-
const [categories, setCategories] = useState({});
31-
const [expanded, setExpanded] = useState(true);
42+
const [categories, setCategories] = useState<Categories>({});
3243

3344
useEffect(() => {
3445
if (devices.length > 0) {
35-
const newCategories: Record<string, { label: string; options: (string | undefined)[] }> = {};
46+
const newCategories: Categories = {};
3647
const keys = Object.keys(devices[0]);
37-
3848
keys.forEach((key) => {
39-
const uniqueValues = Array.from(
40-
new Set(devices.map((device) => device[key as keyof MockData])),
41-
);
49+
const uniqueValues = createUniqueValueArray(devices, key);
4250
newCategories[key] = {
4351
label: key,
4452
options: uniqueValues,
4553
};
4654
});
47-
4855
setCategories(newCategories);
4956
}
5057
}, [devices]);
5158

52-
function deepEqual(obj1: any, obj2: any): boolean {
53-
if (obj1 === obj2) return true;
54-
55-
const keys1: string[] = Object.keys(obj1);
56-
const keys2: string[] = Object.keys(obj2);
57-
58-
if (keys1.length !== keys2.length) return false;
59+
return categories;
60+
};
5961

60-
for (const key of keys1) {
61-
if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {
62-
return false;
63-
}
64-
}
62+
function DeviceFilter() {
63+
const { filter, setFilter } = useFilterStore();
64+
const categories = useCategories();
65+
const onFilterChanged = useCallback(
66+
(event: CustomEvent<FilterState>) => setFilter(event.detail.categories),
67+
[setFilter],
68+
);
69+
return (
70+
<IxCategoryFilter
71+
aria-label="Filter by"
72+
placeholder="Filter by"
73+
onFilterChanged={onFilterChanged}
74+
filterState={{ tokens: [], categories: filter }}
75+
categories={categories}
76+
className="mb-4"
77+
repeatCategories={false}
78+
></IxCategoryFilter>
79+
);
80+
}
6581

66-
return true;
67-
}
82+
const DevicesPage = () => {
83+
const [expanded, setExpanded] = useState(true);
6884

6985
return (
7086
<>
@@ -77,20 +93,7 @@ const DevicesPage = () => {
7793
Add device
7894
</IxButton>
7995
</IxContentHeader>
80-
<IxCategoryFilter
81-
aria-label="Filter by"
82-
placeholder="Filter by"
83-
onFilterChanged={(e) => {
84-
const newCategories = e.detail.categories;
85-
if (!deepEqual(filter, newCategories)) {
86-
setFilter(newCategories.length > 0 ? newCategories : []);
87-
}
88-
}}
89-
filterState={{ tokens: [], categories: filter }}
90-
categories={categories}
91-
className="mb-4"
92-
repeatCategories={false}
93-
></IxCategoryFilter>
96+
<DeviceFilter />
9497
<AgGridTable />
9598
</div>
9699
<IxPane

apps/react-starter/src/pages/store/device-store.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export const useOverviewPaneStore = create<OverviewPaneStore>((set) => ({
6666
setSelectedData: (selectedData: MockData) => set({ selectedData }),
6767
}));
6868

69-
interface Filter {
69+
export interface Filter {
7070
id: string;
7171
value: string;
7272
operator: LogicalFilterOperator;
@@ -80,6 +80,14 @@ interface FilterStore {
8080

8181
export const useFilterStore = create<FilterStore>((set) => ({
8282
filter: [],
83-
setFilter: (filter: Filter[]) => set({ filter }),
83+
setFilter: (filter: Filter[]) => {
84+
set((state) => {
85+
if (filter.length !== state.filter.length) {
86+
return { filter };
87+
}
88+
89+
return state;
90+
});
91+
},
8492
resetFilter: () => set({ filter: [] }),
8593
}));

0 commit comments

Comments
 (0)