mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
feat(tables): share column-sort state across the value lists
Lift the byte-identical sortBy/sortDir/toggleSort triple the measurement and mood lists each carried inline into a shared useTableSort hook. Both lists now compose their page-reset and selection-clear side effects around the hook's toggle rather than re-implementing the direction math, and the date columns keep their descending-first default via descColumns.
This commit is contained in:
1 parent
bc617adc2c
commit
9c748382b9
3 files changed
+88
-16
No files matched your search
@@ -52,6 +52,7 @@ import {
|
||||
MoreHorizontal,
|
||||
} from "lucide-react";
|
||||
import { Fragment, useCallback, useId, useState } from "react";
|
||||
import { useTableSort } from "@/hooks/use-table-sort";
|
||||
import { createPortal } from "react-dom";
|
||||
import { toast } from "sonner";
|
||||
import { formatDateOrRelative, formatDateTime } from "@/lib/format";
|
||||
@@ -105,6 +106,10 @@ import {
|
||||
*/
|
||||
const CUMULATIVE_TYPES = new Set<string>(CUMULATIVE_DAY_SUM_TYPES);
|
||||
|
||||
// Columns that open descending when first selected. The date column reads
|
||||
// newest-first by default; every other column opens ascending.
|
||||
const MEASUREMENT_DESC_COLUMNS: ReadonlySet<string> = new Set(["measuredAt"]);
|
||||
|
||||
interface Measurement {
|
||||
id: string;
|
||||
type: string;
|
||||
@@ -313,8 +318,16 @@ export function MeasurementList({
|
||||
const [valueMinInput, setValueMinInputRaw] = useState<string>("");
|
||||
const [valueMaxInput, setValueMaxInputRaw] = useState<string>("");
|
||||
const [page, setPage] = useState(1);
|
||||
const [sortBy, setSortBy] = useState<string>("measuredAt");
|
||||
const [sortDir, setSortDir] = useState<"asc" | "desc">("desc");
|
||||
// Shared column-sort state (measuredAt opens descending).
|
||||
const {
|
||||
sortBy,
|
||||
sortDir,
|
||||
toggleSort: applySort,
|
||||
} = useTableSort({
|
||||
defaultColumn: "measuredAt",
|
||||
defaultDir: "desc",
|
||||
descColumns: MEASUREMENT_DESC_COLUMNS,
|
||||
});
|
||||
|
||||
// v1.15.13 — page-scoped multi-select. Holds the ids selected on the
|
||||
// CURRENT page; cleared on any page / filter / sort change (per the
|
||||
@@ -399,13 +412,11 @@ export function MeasurementList({
|
||||
clearSelection();
|
||||
};
|
||||
|
||||
// Compose the page-reset + selection-clear side effects around the
|
||||
// shared sort toggle (the rows the selection referred to are about to
|
||||
// re-order and the list snaps back to page 1).
|
||||
function toggleSort(column: string) {
|
||||
if (sortBy === column) {
|
||||
setSortDir((d) => (d === "asc" ? "desc" : "asc"));
|
||||
} else {
|
||||
setSortBy(column);
|
||||
setSortDir(column === "measuredAt" ? "desc" : "asc");
|
||||
}
|
||||
applySort(column);
|
||||
setPage(1);
|
||||
clearSelection();
|
||||
}
|
||||
|
||||
@@ -51,6 +51,11 @@ import {
|
||||
} from "lucide-react";
|
||||
import { useCallback, useEffect, useId, useRef, useState } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { useTableSort } from "@/hooks/use-table-sort";
|
||||
|
||||
// Columns that open descending when first selected. The logged-at column
|
||||
// reads newest-first by default; every other column opens ascending.
|
||||
const MOOD_DESC_COLUMNS: ReadonlySet<string> = new Set(["moodLoggedAt"]);
|
||||
import { toast } from "sonner";
|
||||
import { formatDateTime } from "@/lib/format";
|
||||
import { useTranslations, useFormatters } from "@/lib/i18n/context";
|
||||
@@ -128,8 +133,16 @@ export function MoodList({ onAddFirst }: MoodListProps = {}) {
|
||||
const [fromDay, setFromDayRaw] = useState<string>("");
|
||||
const [toDay, setToDayRaw] = useState<string>("");
|
||||
const [page, setPage] = useState(1);
|
||||
const [sortBy, setSortBy] = useState<string>("moodLoggedAt");
|
||||
const [sortDir, setSortDir] = useState<"asc" | "desc">("desc");
|
||||
// Shared column-sort state (moodLoggedAt opens descending).
|
||||
const {
|
||||
sortBy,
|
||||
sortDir,
|
||||
toggleSort: applySort,
|
||||
} = useTableSort({
|
||||
defaultColumn: "moodLoggedAt",
|
||||
defaultDir: "desc",
|
||||
descColumns: MOOD_DESC_COLUMNS,
|
||||
});
|
||||
|
||||
// v1.15.13 — page-scoped multi-select selection (current page ids only).
|
||||
const [selectedIds, setSelectedIds] = useState<Set<string>>(() => new Set());
|
||||
@@ -201,13 +214,10 @@ export function MoodList({ onAddFirst }: MoodListProps = {}) {
|
||||
clearSelection();
|
||||
};
|
||||
|
||||
// Compose the page-reset + selection-clear side effects around the
|
||||
// shared sort toggle.
|
||||
function toggleSort(column: string) {
|
||||
if (sortBy === column) {
|
||||
setSortDir((d) => (d === "asc" ? "desc" : "asc"));
|
||||
} else {
|
||||
setSortBy(column);
|
||||
setSortDir(column === "moodLoggedAt" ? "desc" : "asc");
|
||||
}
|
||||
applySort(column);
|
||||
setPage(1);
|
||||
clearSelection();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export type SortDirection = "asc" | "desc";
|
||||
|
||||
/**
|
||||
* Shared column-sort state for the data-management tables (measurements,
|
||||
* mood, lab history). Lifted from the byte-identical `sortBy` / `sortDir` /
|
||||
* `toggleSort` triple the measurement + mood lists each carried inline.
|
||||
*
|
||||
* `toggleSort(column)` flips the direction when the active column is tapped
|
||||
* again, otherwise switches to the new column with its default direction:
|
||||
* a column listed in `descColumns` (typically the date column) opens
|
||||
* descending, every other column ascending. Callers that need extra side
|
||||
* effects on a sort change (reset the page, clear a selection) compose them
|
||||
* around the returned `toggleSort` rather than re-implementing the math.
|
||||
*/
|
||||
export function useTableSort({
|
||||
defaultColumn,
|
||||
defaultDir = "desc",
|
||||
descColumns,
|
||||
}: {
|
||||
/** Column the table sorts by on first render. */
|
||||
defaultColumn: string;
|
||||
/** Direction for the initial column. */
|
||||
defaultDir?: SortDirection;
|
||||
/** Columns that open descending when first selected (e.g. the date column). */
|
||||
descColumns?: ReadonlySet<string>;
|
||||
}): {
|
||||
sortBy: string;
|
||||
sortDir: SortDirection;
|
||||
toggleSort: (column: string) => void;
|
||||
} {
|
||||
const [sortBy, setSortBy] = useState<string>(defaultColumn);
|
||||
const [sortDir, setSortDir] = useState<SortDirection>(defaultDir);
|
||||
|
||||
const toggleSort = useCallback(
|
||||
(column: string) => {
|
||||
if (sortBy === column) {
|
||||
setSortDir((d) => (d === "asc" ? "desc" : "asc"));
|
||||
} else {
|
||||
setSortBy(column);
|
||||
setSortDir(descColumns?.has(column) ? "desc" : "asc");
|
||||
}
|
||||
},
|
||||
[sortBy, descColumns],
|
||||
);
|
||||
|
||||
return { sortBy, sortDir, toggleSort };
|
||||
}
|
||||
Reference in new issue
Block a user