chore: refactor format date in UI

This commit is contained in:
Abhishek Kumar 2026-07-23 17:38:13 +05:30
parent eae30b3b21
commit 9045dbca72
19 changed files with 155 additions and 98 deletions

View file

@ -21,12 +21,15 @@ import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Skeleton } from '@/components/ui/skeleton';
import { useAppConfig } from '@/context/AppConfigContext';
import { useOrganizationTimezone } from '@/hooks/useOrganizationTimezone';
import { useAuth } from '@/lib/auth';
import { formatDateTime } from '@/lib/dateTime';
import logger from '@/lib/logger';
export default function APIKeysPage() {
const { user, getAccessToken, redirectToLogin, loading } = useAuth();
const { config } = useAppConfig();
const organizationTimezone = useOrganizationTimezone();
const isOSS = config?.deploymentMode === 'oss';
logger.debug('[APIKeysPage] Component render', {
@ -292,13 +295,7 @@ export default function APIKeysPage() {
const formatDate = (dateString: string | null) => {
if (!dateString) return 'Never';
return new Date(dateString).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
return formatDateTime(dateString, organizationTimezone);
};
// Don't render content until auth is loaded

View file

@ -30,7 +30,9 @@ import {
TableRow,
} from "@/components/ui/table";
import { useAppConfig } from "@/context/AppConfigContext";
import { useOrganizationTimezone } from "@/hooks/useOrganizationTimezone";
import { useAuth } from "@/lib/auth";
import { formatDateTime } from "@/lib/dateTime";
const LEDGER_PAGE_SIZE = 50;
@ -52,16 +54,6 @@ const formatAmount = (amountMinor?: number | null, currency?: string | null) =>
}).format(amountMinor / 100);
};
const formatDate = (value: string) => (
new Date(value).toLocaleString(undefined, {
month: "short",
day: "numeric",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
})
);
const metricLabels: Record<string, string> = {
voice_minutes: "Voice usage",
platform_usage: "Platform usage",
@ -117,6 +109,7 @@ export default function BillingPage() {
const searchParams = useSearchParams();
const auth = useAuth();
const { config, loading: configLoading } = useAppConfig();
const organizationTimezone = useOrganizationTimezone();
const [credits, setCredits] = useState<MpsBillingCreditsResponse | null>(null);
const [loading, setLoading] = useState(true);
const [refreshing, setRefreshing] = useState(false);
@ -353,7 +346,9 @@ export default function BillingPage() {
const billableQuantity = formatBillableQuantity(entry);
return (
<TableRow key={entry.id}>
<TableCell>{formatDate(entry.created_at)}</TableCell>
<TableCell>
{formatDateTime(entry.created_at, organizationTimezone)}
</TableCell>
<TableCell>
<div className="flex flex-col gap-1">
<span className="font-medium">{getLedgerEntryLabel(entry)}</span>

View file

@ -27,10 +27,13 @@ import { Label } from '@/components/ui/label';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Separator } from '@/components/ui/separator';
import { CampaignRuns } from '@/components/workflow-runs';
import { useOrganizationTimezone } from '@/hooks/useOrganizationTimezone';
import { useAuth } from '@/lib/auth';
import { formatDate, formatDateTime } from '@/lib/dateTime';
export default function CampaignDetailPage() {
const { user, getAccessToken, redirectToLogin, loading } = useAuth();
const organizationTimezone = useOrganizationTimezone();
const router = useRouter();
const params = useParams();
const searchParams = useSearchParams();
@ -352,15 +355,6 @@ export default function CampaignDetailPage() {
}
};
// Format date for display
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString();
};
const formatDateTime = (dateString: string) => {
return new Date(dateString).toLocaleString();
};
// Get badge variant for state
const getStateBadgeVariant = (state: string) => {
switch (state) {
@ -410,7 +404,7 @@ export default function CampaignDetailPage() {
const formatLogTimestamp = (ts: string) => {
const d = new Date(ts);
if (isNaN(d.getTime())) return ts;
return d.toLocaleString();
return formatDateTime(d, organizationTimezone);
};
// Render action button based on state
@ -508,7 +502,7 @@ export default function CampaignDetailPage() {
{campaign.state}
</Badge>
<span className="text-muted-foreground">
Created {formatDate(campaign.created_at)}
Created {formatDate(campaign.created_at, organizationTimezone)}
</span>
</div>
</div>
@ -700,13 +694,17 @@ export default function CampaignDetailPage() {
{campaign.started_at && (
<div>
<dt className="text-sm font-medium">Started At</dt>
<dd className="mt-1">{formatDateTime(campaign.started_at)}</dd>
<dd className="mt-1">
{formatDateTime(campaign.started_at, organizationTimezone)}
</dd>
</div>
)}
{campaign.completed_at && (
<div>
<dt className="text-sm font-medium">Completed At</dt>
<dd className="mt-1">{formatDateTime(campaign.completed_at)}</dd>
<dd className="mt-1">
{formatDateTime(campaign.completed_at, organizationTimezone)}
</dd>
</div>
)}
</dl>

View file

@ -17,10 +17,13 @@ import {
TableHeader,
TableRow,
} from '@/components/ui/table';
import { useOrganizationTimezone } from '@/hooks/useOrganizationTimezone';
import { useAuth } from '@/lib/auth';
import { formatDate } from '@/lib/dateTime';
export default function CampaignsPage() {
const { user, getAccessToken, redirectToLogin, loading } = useAuth();
const organizationTimezone = useOrganizationTimezone();
const router = useRouter();
const [campaignsData, setCampaignsData] = useState<CampaignsResponse | null>(null);
@ -72,10 +75,6 @@ export default function CampaignsPage() {
router.push('/campaigns/new');
};
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString();
};
const getStateBadgeVariant = (state: string) => {
switch (state) {
case 'created':
@ -152,7 +151,9 @@ export default function CampaignsPage() {
<TableCell>
{campaign.executed_count} / {campaign.total_queued_count}
</TableCell>
<TableCell>{formatDate(campaign.created_at)}</TableCell>
<TableCell>
{formatDate(campaign.created_at, organizationTimezone)}
</TableCell>
<TableCell className="text-right">
<Button
variant="outline"

View file

@ -13,6 +13,8 @@ import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Skeleton } from '@/components/ui/skeleton';
import { useOrganizationTimezone } from '@/hooks/useOrganizationTimezone';
import { formatDateTime } from '@/lib/dateTime';
import logger from '@/lib/logger';
interface DocumentListProps {
@ -20,6 +22,7 @@ interface DocumentListProps {
}
export default function DocumentList({ refreshTrigger }: DocumentListProps) {
const organizationTimezone = useOrganizationTimezone();
const [documents, setDocuments] = useState<DocumentResponseSchema[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [searchQuery, setSearchQuery] = useState('');
@ -120,11 +123,6 @@ export default function DocumentList({ refreshTrigger }: DocumentListProps) {
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
};
const formatDate = (dateString: string): string => {
const date = new Date(dateString);
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
};
const filteredDocuments = documents.filter((doc) =>
doc.filename.toLowerCase().includes(searchQuery.toLowerCase())
);
@ -212,7 +210,7 @@ export default function DocumentList({ refreshTrigger }: DocumentListProps) {
{doc.processing_status === 'completed' && doc.retrieval_mode !== 'full_document' && (
<span>{doc.total_chunks} chunks</span>
)}
<span>{formatDate(doc.created_at)}</span>
<span>{formatDateTime(doc.created_at, organizationTimezone)}</span>
</div>
{doc.processing_error && (
<p className="text-xs text-destructive mt-1">

View file

@ -14,9 +14,12 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Skeleton } from "@/components/ui/skeleton";
import { useAudioPlayback } from "@/hooks/useAudioPlayback";
import { useOrganizationTimezone } from "@/hooks/useOrganizationTimezone";
import { formatDateTime } from "@/lib/dateTime";
import logger from "@/lib/logger";
export default function RecordingsList({ refreshKey }: { refreshKey?: number }) {
const organizationTimezone = useOrganizationTimezone();
const [recordings, setRecordings] = useState<RecordingResponseSchema[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [searchQuery, setSearchQuery] = useState("");
@ -130,11 +133,6 @@ export default function RecordingsList({ refreshKey }: { refreshKey?: number })
}
};
const formatDate = (dateString: string): string => {
const date = new Date(dateString);
return date.toLocaleDateString() + " " + date.toLocaleTimeString();
};
const filteredRecordings = recordings.filter((rec) => {
if (!searchQuery) return true;
const q = searchQuery.toLowerCase();
@ -288,7 +286,7 @@ export default function RecordingsList({ refreshKey }: { refreshKey?: number })
{rec.transcript}
</p>
<div className="flex items-center gap-3 text-xs text-muted-foreground flex-wrap">
<span>{formatDate(rec.created_at)}</span>
<span>{formatDateTime(rec.created_at, organizationTimezone)}</span>
</div>
</div>
</div>

View file

@ -21,6 +21,7 @@ import {
} from "@/components/ui/table";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { useAuth } from '@/lib/auth';
import { formatDateTime } from '@/lib/dateTime';
import{ superadminFilterAttributes } from "@/lib/filterAttributes";
import { decodeFiltersFromURL, encodeFiltersToURL } from '@/lib/filters';
import { impersonateAsSuperadmin } from '@/lib/utils';
@ -248,8 +249,6 @@ export default function RunsPage() {
* ----------------------------------------------------------------------------------
*/
const formatDate = (dateString: string) => new Date(dateString).toLocaleString();
const calculateDuration = (isCompleted: boolean, usageInfo?: Record<string, unknown>) => {
if (isCompleted && typeof usageInfo?.call_duration_seconds === 'number') {
return `${Number(usageInfo.call_duration_seconds).toFixed(2)}s`;
@ -472,7 +471,7 @@ export default function RunsPage() {
</div>
</TableCell>
<TableCell className="text-sm">
{formatDate(run.created_at)}
{formatDateTime(run.created_at)}
</TableCell>
<TableCell>
<div className="flex space-x-2">

View file

@ -57,8 +57,10 @@ import {
} from "@/components/ui/table";
import { useAppConfig } from "@/context/AppConfigContext";
import { useOrgConfig } from "@/context/OrgConfigContext";
import { useOrganizationTimezone } from "@/hooks/useOrganizationTimezone";
import { detailFromError } from "@/lib/apiError";
import { useAuth } from "@/lib/auth";
import { formatDateTime } from "@/lib/dateTime";
import { resolveWebhookBaseUrl } from "@/lib/webhookUrl";
const INBOUND_WEBHOOK_PATH = "/api/v1/telephony/inbound/run";
@ -71,6 +73,7 @@ export default function TelephonyConfigurationDetailPage() {
const { user, getAccessToken, loading: authLoading } = useAuth();
const { config: appConfig } = useAppConfig();
const { externalPbxIntegrationsEnabled } = useOrgConfig();
const organizationTimezone = useOrganizationTimezone();
const inboundWebhookUrl = `${resolveWebhookBaseUrl(appConfig?.tunnelUrl)}${INBOUND_WEBHOOK_PATH}`;
const [config, setConfig] = useState<TelephonyConfigurationDetail | null>(null);
const [phoneNumbers, setPhoneNumbers] = useState<PhoneNumberResponse[]>([]);
@ -220,7 +223,7 @@ export default function TelephonyConfigurationDetailPage() {
)}
</div>
<CardDescription>
Updated {new Date(config.updated_at).toLocaleString()}
Updated {formatDateTime(config.updated_at, organizationTimezone)}
</CardDescription>
<button
type="button"

View file

@ -26,13 +26,11 @@ import {
import { useUserConfig } from '@/context/UserConfigContext';
import { detailFromError } from '@/lib/apiError';
import { useAuth } from '@/lib/auth';
import { formatDateTime, getLocalTimezone } from '@/lib/dateTime';
import { usageFilterAttributes } from '@/lib/filterAttributes';
import { decodeFiltersFromURL, encodeFiltersToURL } from '@/lib/filters';
import type { ActiveFilter, DateRangeValue, FilterAttribute, NumberFilterOption } from '@/types/filters';
// Get local timezone
const getLocalTimezone = () => Intl.DateTimeFormat().resolvedOptions().timeZone;
const buildAgentFilterAttributes = (
agentOptions: NumberFilterOption[] | null,
isLoadingAgentOptions: boolean
@ -390,22 +388,8 @@ export default function UsagePage() {
router.push(`/workflow/${run.workflow_id}/run/${run.id}`);
};
// Format datetime for display with timezone support
const formatDateTime = (dateString: string) => {
const date = new Date(dateString);
const tzValue = typeof selectedTimezone === 'string' ? selectedTimezone : selectedTimezone.value;
// Use local timezone if none selected (during loading)
const effectiveTz = tzValue || localTimezone;
return date.toLocaleString('en-US', {
timeZone: effectiveTz,
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
hour12: true
});
};
const timezoneValue = typeof selectedTimezone === 'string' ? selectedTimezone : selectedTimezone.value;
const effectiveTimezone = timezoneValue || localTimezone;
// Format duration for display
const formatDuration = (seconds: number) => {
@ -602,7 +586,7 @@ export default function UsagePage() {
<span className="text-sm text-muted-foreground">-</span>
)}
</TableCell>
<TableCell>{formatDateTime(run.created_at)}</TableCell>
<TableCell>{formatDateTime(run.created_at, effectiveTimezone)}</TableCell>
<TableCell className="text-right">
{formatDuration(run.call_duration_seconds)}
</TableCell>

View file

@ -3,6 +3,7 @@
import {
Bot,
Check,
Clock,
Copy,
Download,
ExternalLink,
@ -31,12 +32,15 @@ import { Skeleton } from '@/components/ui/skeleton';
import { ConversationRailFrame, RealtimeFeedback, WorkflowRunLogs } from '@/components/workflow/conversation';
import { PostHogEvent } from '@/constants/posthog-events';
import { WORKFLOW_RUN_MODES } from '@/constants/workflowRunModes';
import { useOrganizationTimezone } from '@/hooks/useOrganizationTimezone';
import { useAuth } from '@/lib/auth';
import { formatDateTime } from '@/lib/dateTime';
import { downloadFile, getSignedUrl } from '@/lib/files';
import { cn } from '@/lib/utils';
interface WorkflowRunResponse {
mode: string;
created_at: string | null;
is_completed: boolean;
transcript_url: string | null;
recording_url: string | null;
@ -599,6 +603,7 @@ export default function WorkflowRunPage() {
const params = useParams();
const [isLoading, setIsLoading] = useState(true);
const auth = useAuth();
const organizationTimezone = useOrganizationTimezone();
const [workflowRun, setWorkflowRun] = useState<WorkflowRunResponse | null>(null);
const [workflowName, setWorkflowName] = useState<string | null>(null);
const customizeButtonRef = useRef<HTMLButtonElement>(null);
@ -639,6 +644,7 @@ export default function WorkflowRunPage() {
setWorkflowName(workflowResponse.data?.name ?? null);
const runData = {
mode: runResponse.data?.mode ?? '',
created_at: runResponse.data?.created_at ?? null,
is_completed: runResponse.data?.is_completed ?? false,
transcript_url: runResponse.data?.transcript_url ?? null,
recording_url: runResponse.data?.recording_url ?? null,
@ -739,6 +745,12 @@ export default function WorkflowRunPage() {
)}
</div>
</div>
{workflowRun?.created_at && (
<p className="flex items-center gap-1.5 text-sm text-muted-foreground">
<Clock className="h-4 w-4" />
Call time: {formatDateTime(workflowRun.created_at, organizationTimezone)}
</p>
)}
</div>
<div className="flex shrink-0 items-center gap-2">
<Link href={`/workflow/${params.workflowId}`}>

View file

@ -9,6 +9,7 @@ import {
TableHeader,
TableRow,
} from '@/components/ui/table';
import { formatCalendarDate } from '@/lib/dateTime';
interface DailyUsageTableProps {
data: DailyUsageBreakdownResponse | null;
@ -16,16 +17,6 @@ interface DailyUsageTableProps {
}
export function DailyUsageTable({ data, isLoading }: DailyUsageTableProps) {
// Format date for display
const formatDate = (dateString: string) => {
const date = new Date(dateString);
return date.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric'
});
};
if (isLoading) {
return (
<Card>
@ -79,7 +70,7 @@ export function DailyUsageTable({ data, isLoading }: DailyUsageTableProps) {
{data.breakdown.map((day) => (
<TableRow key={day.date}>
<TableCell className="font-medium">
{formatDate(day.date)}
{formatCalendarDate(day.date)}
</TableCell>
<TableCell className="text-right">
{day.minutes.toFixed(1)}

View file

@ -5,6 +5,7 @@ import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Label } from "@/components/ui/label";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { formatLocalDateTime } from "@/lib/dateTime";
import { getDatePresetValue } from "@/lib/filters";
import { cn } from "@/lib/utils";
import { DateRangeValue } from "@/types/filters";
@ -40,7 +41,7 @@ export const DateRangeFilter: React.FC<DateRangeFilterProps> = ({
const formatDate = (date: Date | null) => {
if (!date) return "Select date";
return date.toLocaleDateString() + " " + date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
return formatLocalDateTime(date);
};
const handlePresetClick = (preset: string) => {

View file

@ -18,6 +18,8 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table";
import { useOrganizationTimezone } from "@/hooks/useOrganizationTimezone";
import { formatDateTime } from "@/lib/dateTime";
import { ActiveFilter, FilterAttribute } from "@/types/filters";
export interface WorkflowRunsTableProps {
@ -85,12 +87,11 @@ export function WorkflowRunsTable({
emptyMessage = "No workflow runs found",
}: WorkflowRunsTableProps) {
const [selectedRowId, setSelectedRowId] = useState<number | null>(null);
const organizationTimezone = useOrganizationTimezone();
// Media preview dialog
const mediaPreview = MediaPreviewDialog();
const formatDate = (dateString: string) => new Date(dateString).toLocaleString();
const handleRowClick = (runId: number) => {
window.open(`/workflow/${workflowId}/run/${runId}`, '_blank');
};
@ -188,7 +189,9 @@ export function WorkflowRunsTable({
{run.is_completed ? "Completed" : "In Progress"}
</Badge>
</TableCell>
<TableCell className="text-sm">{formatDate(run.created_at)}</TableCell>
<TableCell className="text-sm">
{formatDateTime(run.created_at, organizationTimezone)}
</TableCell>
<TableCell>
<CallTypeCell mode={run.mode} callType={run.call_type} />
</TableCell>

View file

@ -2,6 +2,9 @@
import { useRouter } from 'next/navigation';
import { useOrganizationTimezone } from '@/hooks/useOrganizationTimezone';
import { formatDate } from '@/lib/dateTime';
interface WorkflowCardProps {
id: number;
name: string;
@ -10,6 +13,7 @@ interface WorkflowCardProps {
export function WorkflowCard({ id, name, createdAt }: WorkflowCardProps) {
const router = useRouter();
const organizationTimezone = useOrganizationTimezone();
const handleClick = () => {
router.push(`/workflow/${id}`);
@ -23,7 +27,7 @@ export function WorkflowCard({ id, name, createdAt }: WorkflowCardProps) {
<div>
<h3 className="text-lg font-semibold mb-2">{name}</h3>
<p className="text-gray-600 mb-2">
Created: {new Date(createdAt).toLocaleDateString()}
Created: {formatDate(createdAt, organizationTimezone)}
</p>
</div>
</div>

View file

@ -36,6 +36,9 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table";
import { useOrganizationTimezone } from '@/hooks/useOrganizationTimezone';
import { formatDate } from '@/lib/dateTime';
interface Workflow {
id: number;
name: string;
@ -64,6 +67,7 @@ export function WorkflowTable({
currentFolderId = null,
}: WorkflowTableProps) {
const router = useRouter();
const organizationTimezone = useOrganizationTimezone();
const [isPending, startTransition] = useTransition();
const [loadingWorkflowId, setLoadingWorkflowId] = useState<number | null>(null);
const [movingWorkflowId, setMovingWorkflowId] = useState<number | null>(null);
@ -152,11 +156,7 @@ export function WorkflowTable({
{workflow.name}
</TableCell>
<TableCell>
{new Date(workflow.created_at).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
})}
{formatDate(workflow.created_at, organizationTimezone)}
</TableCell>
<TableCell className="text-center">
<span className="inline-flex items-center justify-center min-w-[2rem] px-2 py-1 text-sm font-semibold bg-muted rounded-full">

View file

@ -0,0 +1,9 @@
'use client';
import { useOrgConfig } from '@/context/OrgConfigContext';
import { getLocalTimezone } from '@/lib/dateTime';
export function useOrganizationTimezone() {
const { organizationPreferences } = useOrgConfig();
return organizationPreferences?.timezone || getLocalTimezone();
}

View file

@ -0,0 +1,21 @@
import { describe, expect, it } from 'vitest';
import { formatCalendarDate, formatDate, formatDateTime } from '@/lib/dateTime';
describe('dateTime', () => {
it('formats an instant in the requested timezone', () => {
expect(formatDateTime('2026-07-23T10:00:00Z', 'Asia/Kolkata')).toBe(
'Jul 23, 2026, 03:30 PM',
);
});
it('formats the date represented in the requested timezone', () => {
expect(formatDate('2026-07-23T01:00:00Z', 'America/Los_Angeles')).toBe(
'Jul 22, 2026',
);
});
it('does not shift calendar-only dates across timezones', () => {
expect(formatCalendarDate('2026-07-23')).toBe('Jul 23, 2026');
});
});

46
ui/src/lib/dateTime.ts Normal file
View file

@ -0,0 +1,46 @@
export function getLocalTimezone() {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
}
type DateInput = Date | number | string;
export function formatDateTime(value: DateInput, timezone?: string | null) {
return new Date(value).toLocaleString('en-US', {
timeZone: timezone || getLocalTimezone(),
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
hour12: true,
});
}
export function formatDate(value: DateInput, timezone?: string | null) {
return new Date(value).toLocaleDateString('en-US', {
timeZone: timezone || getLocalTimezone(),
year: 'numeric',
month: 'short',
day: 'numeric',
});
}
export function formatCalendarDate(value: string) {
const calendarDate = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
if (!calendarDate) {
return formatDate(value, 'UTC');
}
const [, year, month, day] = calendarDate;
return formatDate(
Date.UTC(Number(year), Number(month) - 1, Number(day)),
'UTC',
);
}
export function formatLocalDateTime(value: Date) {
return `${value.toLocaleDateString()} ${value.toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
})}`;
}

View file

@ -1,3 +1,4 @@
import { formatLocalDateTime } from "@/lib/dateTime";
import { ActiveFilter, DateRangeValue, FilterAttribute, FilterValue, MultiSelectValue, NumberRangeValue, NumberValue, RadioValue, TextValue } from "@/types/filters";
// Get default value based on attribute type
@ -187,11 +188,7 @@ export const decodeFiltersFromURL = (
export const formatDateRange = (value: DateRangeValue): string => {
if (!value.from || !value.to) return "No date range selected";
const formatDate = (date: Date) => {
return date.toLocaleDateString() + " " + date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
};
return `${formatDate(value.from)} to ${formatDate(value.to)}`;
return `${formatLocalDateTime(value.from)} to ${formatLocalDateTime(value.to)}`;
};
// Format number range for display