frontend: date range picker on Incidents and Archive; fix Archive paging
Incidents and Archive get a from/to date range (native date inputs, local-day bounds). Incidents filters in the Firestore query; Archive passes date_from/date_to to GET /calls/search, which applies them as a started_at range — both ride the existing org_id/started_at index. Also fixes /calls/search and /calls/eval-queue paging: the cursor went to Firestore as a raw ISO string against a timestamp field, which compares by type rather than time, so "Load more" re-read the first page. Cursor and range bounds are now parsed to datetimes (400 on garbage). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c043298902
commit
6479174022
@@ -0,0 +1,57 @@
|
||||
"use client";
|
||||
|
||||
// A from/to pair of native date inputs. Values are the inputs' own
|
||||
// "YYYY-MM-DD" strings; dayStart/dayEnd turn them into the local-midnight
|
||||
// bounds a started_at range query needs, so "to" includes the whole day.
|
||||
|
||||
export function dayStart(ymd: string): Date | undefined {
|
||||
if (!ymd) return undefined;
|
||||
const [y, m, d] = ymd.split("-").map(Number);
|
||||
return new Date(y, m - 1, d, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
export function dayEnd(ymd: string): Date | undefined {
|
||||
if (!ymd) return undefined;
|
||||
const [y, m, d] = ymd.split("-").map(Number);
|
||||
return new Date(y, m - 1, d, 23, 59, 59, 999);
|
||||
}
|
||||
|
||||
const inputClass =
|
||||
"bg-surface border border-line rounded-lg px-2 py-1.5 text-sm text-ink-2 focus:outline-none focus:border-accent";
|
||||
|
||||
export function DateRange({
|
||||
from,
|
||||
to,
|
||||
onChange,
|
||||
}: {
|
||||
from: string;
|
||||
to: string;
|
||||
onChange: (from: string, to: string) => void;
|
||||
}) {
|
||||
return (
|
||||
<div className="flex items-center gap-2 text-xs text-ink-muted">
|
||||
<input
|
||||
type="date"
|
||||
aria-label="From date"
|
||||
value={from}
|
||||
max={to || undefined}
|
||||
onChange={(e) => onChange(e.target.value, to)}
|
||||
className={inputClass}
|
||||
/>
|
||||
<span>to</span>
|
||||
<input
|
||||
type="date"
|
||||
aria-label="To date"
|
||||
value={to}
|
||||
min={from || undefined}
|
||||
onChange={(e) => onChange(from, e.target.value)}
|
||||
className={inputClass}
|
||||
/>
|
||||
{(from || to) && (
|
||||
<button onClick={() => onChange("", "")} className="text-ink-muted hover:text-ink-2">
|
||||
clear
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user