fix(search): apply the date range to server results client-side

from_ts/to_ts are not Matrix filter fields; the server dropped them, so
the range only worked for the local encrypted-room search. Stop sending
them and post-filter server results by origin_server_ts with the same
inclusive predicate. Unit-tested; docs corrected.

Fixes #13

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
2026-09-12 14:48:35 -04:00
co-authored by Claude Opus 5
parent 6bd2903de1
commit 02592ed43c
4 changed files with 87 additions and 12 deletions
@@ -36,6 +36,7 @@ import { mDirectAtom } from '../../state/mDirectList';
import { getStateEvent } from '../../utils/room';
import { StateEvent } from '../../../types/matrix/room';
import {
filterGroupsByDateRange,
filterGroupsByMsgType,
filterGroupsByPinned,
MessageSearchParams,
@@ -316,12 +317,21 @@ export function MessageSearch({
getNextPageParam: (lastPage) => lastPage.nextToken,
});
// Shared client-side post-filter (msgtype + pinned) applied to BOTH the
// server results and the local/encrypted-cache results, so the filter chips
// narrow the whole UI consistently rather than only the server section.
// Shared client-side post-filter (date range + msgtype + pinned) applied to
// BOTH the server results and the local/encrypted-cache results, so the
// filter chips narrow the whole UI consistently rather than only the
// server section. The date range must be enforced here because the Matrix
// search API has no timestamp filter fields (see useMessageSearch.ts); the
// local/encrypted path already filters in-range before this runs, so this
// is a no-op there and only actually trims the server section.
const applyResultFilters = useCallback(
(allGroups: ResultGroup[]): ResultGroup[] => {
const byMsgType = filterGroupsByMsgType(allGroups, msgTypeFilters);
const inDateRange = filterGroupsByDateRange(
allGroups,
msgSearchParams.fromTs,
msgSearchParams.toTs,
);
const byMsgType = filterGroupsByMsgType(inDateRange, msgTypeFilters);
if (!pinnedOnly) return byMsgType;
// Build a per-room pinned-event lookup. Heavy Matrix reads stay here
// (where `mx` is available); the pure helper only consumes the predicate.
@@ -343,7 +353,7 @@ export function MessageSearch({
};
return filterGroupsByPinned(byMsgType, pinnedOnly, isPinned);
},
[msgTypeFilters, pinnedOnly, mx],
[msgSearchParams.fromTs, msgSearchParams.toTs, msgTypeFilters, pinnedOnly, mx],
);
const groups = useMemo(() => {