Skip to content

Commit 6810dce

Browse files
committed
fix sorting for nested properties in tables and simplify a bit
1 parent 6ca6d5e commit 6810dce

File tree

1 file changed

+95
-55
lines changed

1 file changed

+95
-55
lines changed

src/components/CippTable/CippDataTable.js

Lines changed: 95 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,55 @@ import { Box } from "@mui/system";
2626
import { useSettings } from "../../hooks/use-settings";
2727
import { isEqual } from "lodash"; // Import lodash for deep comparison
2828

29+
// Resolve dot-delimited property paths against arbitrary data objects.
30+
const getNestedValue = (source, path) => {
31+
if (!source) {
32+
return undefined;
33+
}
34+
if (!path) {
35+
return source;
36+
}
37+
38+
return path.split(".").reduce((acc, key) => {
39+
if (acc === undefined || acc === null) {
40+
return undefined;
41+
}
42+
if (typeof acc !== "object") {
43+
return undefined;
44+
}
45+
return acc[key];
46+
}, source);
47+
};
48+
49+
// Resolve dot-delimited column ids against the original row data so nested fields can sort/filter properly.
50+
const getRowValueByColumnId = (row, columnId) => {
51+
if (!row?.original || !columnId) {
52+
return undefined;
53+
}
54+
55+
if (columnId.includes("@odata")) {
56+
return row.original[columnId];
57+
}
58+
59+
return getNestedValue(row.original, columnId);
60+
};
61+
62+
const compareNullable = (aVal, bVal) => {
63+
if (aVal === null && bVal === null) {
64+
return 0;
65+
}
66+
if (aVal === null) {
67+
return 1;
68+
}
69+
if (bVal === null) {
70+
return -1;
71+
}
72+
if (aVal === bVal) {
73+
return 0;
74+
}
75+
return aVal > bVal ? 1 : -1;
76+
};
77+
2978
export const CippDataTable = (props) => {
3079
const {
3180
queryKey,
@@ -107,22 +156,6 @@ export const CippDataTable = (props) => {
107156
useEffect(() => {
108157
if (getRequestData.isSuccess) {
109158
const allPages = getRequestData.data.pages;
110-
const getNestedValue = (obj, path) => {
111-
if (!path) {
112-
return obj;
113-
}
114-
115-
const keys = path.split(".");
116-
let result = obj;
117-
for (const key of keys) {
118-
if (result && typeof result === "object" && key in result) {
119-
result = result[key];
120-
} else {
121-
return undefined;
122-
}
123-
}
124-
return result;
125-
};
126159

127160
const combinedResults = allPages.flatMap((page) => {
128161
const nestedData = getNestedValue(page, api.dataKey);
@@ -448,49 +481,56 @@ export const CippDataTable = (props) => {
448481
},
449482
sortingFns: {
450483
dateTimeNullsLast: (a, b, id) => {
451-
const aVal = a?.original?.[id] ?? null;
452-
const bVal = b?.original?.[id] ?? null;
453-
if (aVal === null && bVal === null) {
454-
return 0;
455-
}
456-
if (aVal === null) {
457-
return 1;
458-
}
459-
if (bVal === null) {
460-
return -1;
461-
}
462-
return aVal > bVal ? 1 : -1;
484+
const aRaw = getRowValueByColumnId(a, id);
485+
const bRaw = getRowValueByColumnId(b, id);
486+
const aDate = aRaw ? new Date(aRaw) : null;
487+
const bDate = bRaw ? new Date(bRaw) : null;
488+
const aTime = aDate && !Number.isNaN(aDate.getTime()) ? aDate.getTime() : null;
489+
const bTime = bDate && !Number.isNaN(bDate.getTime()) ? bDate.getTime() : null;
490+
491+
return compareNullable(aTime, bTime);
463492
},
464493
number: (a, b, id) => {
465-
const aVal = a?.original?.[id] ?? null;
466-
const bVal = b?.original?.[id] ?? null;
467-
if (aVal === null && bVal === null) {
468-
return 0;
469-
}
470-
if (aVal === null) {
471-
return 1;
472-
}
473-
if (bVal === null) {
474-
return -1;
475-
}
476-
return aVal - bVal;
494+
const aRaw = getRowValueByColumnId(a, id);
495+
const bRaw = getRowValueByColumnId(b, id);
496+
const aNum = typeof aRaw === "number" ? aRaw : Number(aRaw);
497+
const bNum = typeof bRaw === "number" ? bRaw : Number(bRaw);
498+
const aVal = Number.isNaN(aNum) ? null : aNum;
499+
const bVal = Number.isNaN(bNum) ? null : bNum;
500+
501+
return compareNullable(aVal, bVal);
477502
},
478503
boolean: (a, b, id) => {
479-
const aVal = a?.original?.[id] ?? null;
480-
const bVal = b?.original?.[id] ?? null;
481-
if (aVal === null && bVal === null) {
482-
return 0;
483-
}
484-
if (aVal === null) {
485-
return 1;
486-
}
487-
if (bVal === null) {
488-
return -1;
489-
}
490-
// Convert to numbers: true = 1, false = 0
491-
const aNum = aVal === true ? 1 : 0;
492-
const bNum = bVal === true ? 1 : 0;
493-
return aNum - bNum;
504+
const aRaw = getRowValueByColumnId(a, id);
505+
const bRaw = getRowValueByColumnId(b, id);
506+
const toBool = (value) => {
507+
if (value === null || value === undefined) {
508+
return null;
509+
}
510+
if (typeof value === "boolean") {
511+
return value;
512+
}
513+
if (typeof value === "string") {
514+
const lower = value.toLowerCase();
515+
if (lower === "true" || lower === "yes") {
516+
return true;
517+
}
518+
if (lower === "false" || lower === "no") {
519+
return false;
520+
}
521+
}
522+
if (typeof value === "number") {
523+
return value !== 0;
524+
}
525+
return null;
526+
};
527+
528+
const aBool = toBool(aRaw);
529+
const bBool = toBool(bRaw);
530+
const aNumeric = aBool === null ? null : aBool ? 1 : 0;
531+
const bNumeric = bBool === null ? null : bBool ? 1 : 0;
532+
533+
return compareNullable(aNumeric, bNumeric);
494534
},
495535
},
496536
filterFns: {

0 commit comments

Comments
 (0)