feat(freight-backoffice): add DateRangePicker, replace ad-hoc from/to date filters

Adds a shadcn Popover+Calendar range picker with presets (Today, Last 7/30
days, this/last month, YTD) and Apply/Cancel. Swaps it into every shadcn-family
from-to date filter: activity log, sector reports, incoming records (EN
branch), CombinedFilterBar (13 consumers), user records, audit log — also
fixes an uncontrolled-input bug on the audit log date fields.

Mantine-based ListControls/ReportFilters left untouched (different UI kit).
This commit is contained in:
Nathnael
2026-08-13 08:33:59 +00:00
parent 29913259f6
commit 6f14cf8bbf
8 changed files with 252 additions and 214 deletions

View File

@@ -14,6 +14,7 @@ import {
SelectTrigger,
SelectValue,
} from "@/shared/common/ui/select";
import { DateRangePicker, parseDay, formatDay } from "@/shared/common/ui/date-range-picker";
export interface ReportFilterOption {
id: string;
@@ -167,33 +168,18 @@ export function SectorReportFilters({
</Select>
</label>
<label className="space-y-1.5 text-xs font-medium">
<label className="space-y-1.5 text-xs font-medium sm:col-span-2">
<span className="flex items-center gap-2">
<CalendarDays className="size-4 text-primary" />
From date
Date range
</span>
<input
type="date"
value={fromDate}
max={toDate || undefined}
<DateRangePicker
value={{ from: parseDay(fromDate), to: parseDay(toDate) }}
onChange={(range) => {
onFromDateChange(formatDay(range.from));
onToDateChange(formatDay(range.to));
}}
disabled={!unitId || loading}
onChange={(event) => onFromDateChange(event.target.value)}
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
/>
</label>
<label className="space-y-1.5 text-xs font-medium">
<span className="flex items-center gap-2">
<CalendarDays className="size-4 text-primary" />
To date
</span>
<input
type="date"
value={toDate}
min={fromDate || undefined}
disabled={!unitId || loading}
onChange={(event) => onToDateChange(event.target.value)}
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
/>
</label>

View File

@@ -2,6 +2,7 @@ import { useState, useEffect, useMemo, useCallback } from "react";
import { DataTable } from "@/record-management/common/DataTable";
import { Button } from "@/shared/common/ui/button";
import { Input } from "@/shared/common/ui/input";
import { DateRangePicker, parseDay, formatDay } from "@/shared/common/ui/date-range-picker";
import {
Select,
SelectContent,
@@ -383,23 +384,13 @@ const ExternalIncomingRecords = () => {
) : (
<div className="flex flex-col sm:flex-row gap-2">
{lang.startsWith("en") ? (
<>
<label className="mt-2">From: </label>
<Input
type="date"
value={fromDispatchedDate}
onChange={(e) => setFromDispatchedDate(e.target.value)}
className="w-[150px]"
/>
<label className="mt-2">To: </label>
<Input
type="date"
value={toDispatchedDate}
onChange={(e) => setToDispatchedDate(e.target.value)}
min={fromDispatchedDate}
className="w-[150px]"
/>
</>
<DateRangePicker
value={{ from: parseDay(fromDispatchedDate), to: parseDay(toDispatchedDate) }}
onChange={(range) => {
setFromDispatchedDate(formatDay(range.from));
setToDispatchedDate(formatDay(range.to));
}}
/>
) : (
<div className="flex flex-wrap items-center gap-3">
{/* From Date */}

View File

@@ -2,6 +2,7 @@ import { useState, useEffect, useMemo, useCallback } from "react";
import { DataTable } from "@/record-management/common/DataTable";
import { Button } from "@/shared/common/ui/button";
import { Input } from "@/shared/common/ui/input";
import { DateRangePicker, parseDay, formatDay } from "@/shared/common/ui/date-range-picker";
import {
Select,
SelectContent,
@@ -326,23 +327,13 @@ const InternalIncomingRecordsV2 = () => {
) : (
<div className="flex flex-col sm:flex-row gap-2">
{lang.startsWith("en") ? (
<>
<label className="mt-2">From: </label>
<Input
type="date"
value={fromDispatchedDate}
onChange={(e) => setFromDispatchedDate(e.target.value)}
className="w-[150px]"
/>
<label className="mt-2">To: </label>
<Input
type="date"
value={toDispatchedDate}
onChange={(e) => setToDispatchedDate(e.target.value)}
min={fromDispatchedDate}
className="w-[150px]"
/>
</>
<DateRangePicker
value={{ from: parseDay(fromDispatchedDate), to: parseDay(toDispatchedDate) }}
onChange={(range) => {
setFromDispatchedDate(formatDay(range.from));
setToDispatchedDate(formatDay(range.to));
}}
/>
) : (
<div className="flex flex-wrap items-center gap-3">
{/* From Date */}

View File

@@ -17,6 +17,7 @@ import {
} from "@/shared/common/ui/select";
import { Input } from "@/shared/common/ui/input";
import { Button } from "@/shared/common/ui/button";
import { DateRangePicker, parseDay, formatDay } from "@/shared/common/ui/date-range-picker";
import { Badge } from "@/shared/common/ui/badge";
import { AdvancedTable } from "@/shared/common/ui/table/AdvancedTable";
import { useLocalizedName } from "@/shared/common/localizedName";
@@ -521,29 +522,13 @@ const UserRecords = () => {
{selectedFilter?.type === "dateRange" ? (
<div className="flex flex-col sm:flex-row gap-2">
{lang.startsWith("en") ? (
<>
<label className="mt-2">From: </label>
<Input
type="date"
value={fromDate}
onChange={(e) => setFromDate(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") handleAddFilter();
}}
className="w-[150px]"
/>
<label className="mt-2">To: </label>
<Input
type="date"
value={toDate}
onChange={(e) => setToDate(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") handleAddFilter();
}}
min={fromDate}
className="w-[150px]"
/>
</>
<DateRangePicker
value={{ from: parseDay(fromDate), to: parseDay(toDate) }}
onChange={(range) => {
setFromDate(formatDay(range.from));
setToDate(formatDay(range.to));
}}
/>
) : (
<div className="flex flex-wrap items-center gap-3">
<div className="relative">