import { useCallback, useEffect, useMemo, useState, type ReactNode } from "react"; import { App, Button, DatePicker, Drawer, Form, Input, Modal, Select, Tabs, Tag, Tooltip } from "antd"; import type { ColumnsType } from "antd/es/table"; import dayjs, { type Dayjs } from "dayjs"; import { AlertTriangle, BarChart3, CircleDollarSign, Clock3, Gauge, Pencil, Plus, RefreshCw, Settings2, Trash2, UsersRound, Workflow } from "lucide-react"; import { Area, CartesianGrid, ComposedChart, Legend, Line, ResponsiveContainer, Tooltip as ChartTooltip, XAxis, YAxis } from "recharts"; import { useSearchParams } from "react-router"; import { ListToolbar, PaginationBar } from "@/components/layout/workspace-page"; import { createAdminModelPricing, deleteAdminModelPricing, exportAdminAnalytics, getAdminAnalytics, listAdminUsers, listAdminModelPricings, updateAdminModelPricing, type AdminReferenceData, type AdminAnalytics, type AnalyticsFilters, type ModelPricing, } from "@/services/api/auth"; import { AdminDataTable, AdminExportButton, AdminFilterChip, AdminRowActions, AdminStatusBadge, AdminTableEmpty, type AdminStatusTone } from "./admin-ui"; type Props = { users: AdminReferenceData["users"]; channels: AdminReferenceData["channels"]; }; type PricingFormValues = { channelId?: string; model: string; capability: ModelPricing["capability"]; currency: string; inputPerMillion?: string; outputPerMillion?: string; cachedPerMillion?: string; perRequest?: string; perMedia?: string; perVideoSecond?: string; }; type TrendMetric = "volume" | "quality" | "activity"; type AnalysisTab = "models" | "users" | "failures"; type RangePreset = "7d" | "30d" | "60d"; const capabilityOptions = [ { label: "文本", value: "text" }, { label: "图片", value: "image" }, { label: "视频", value: "video" }, { label: "音频", value: "audio" }, ]; export default function AnalyticsPanel({ users, channels }: Props) { const { message } = App.useApp(); const [searchParams, setSearchParams] = useSearchParams(); const [rangePreset, setRangePreset] = useState(() => initialRangePreset(searchParams)); const [range, setRange] = useState<[Dayjs, Dayjs]>(() => initialAnalyticsRange(searchParams, rangePreset)); const [userId, setUserId] = useState(searchParams.get("userId") || undefined); const [model, setModel] = useState(searchParams.get("model") || undefined); const [channelId, setChannelId] = useState(searchParams.get("channelId") || undefined); const [capability, setCapability] = useState(searchParams.get("capability") || undefined); const [data, setData] = useState(null); const [pricings, setPricings] = useState([]); const [loading, setLoading] = useState(false); const [pricingModalOpen, setPricingModalOpen] = useState(false); const [editingPricing, setEditingPricing] = useState(null); const [savingPricing, setSavingPricing] = useState(false); const [userOptions, setUserOptions] = useState(users); const [searchingUsers, setSearchingUsers] = useState(false); const [modelPage, setModelPage] = useState(1); const [userPage, setUserPage] = useState(1); const [failurePage, setFailurePage] = useState(1); const [pricingPage, setPricingPage] = useState(1); const [trendMetric, setTrendMetric] = useState("volume"); const [analysisTab, setAnalysisTab] = useState("models"); const [pricingWorkspaceOpen, setPricingWorkspaceOpen] = useState(false); const [pendingPricing, setPendingPricing] = useState(undefined); const [form] = Form.useForm(); const pricingChannelId = Form.useWatch("channelId", form); const analyticsPageSize = 20; const filters = useMemo( () => ({ from: range[0].format("YYYY-MM-DD"), to: range[1].format("YYYY-MM-DD"), userId, model, channelId, capability, }), [capability, channelId, model, range, userId], ); const reload = useCallback(async () => { setLoading(true); try { const [analytics, pricingData] = await Promise.all([getAdminAnalytics(filters), listAdminModelPricings()]); setData(analytics); setPricings(pricingData.pricings); } catch (error) { message.error(error instanceof Error ? error.message : "读取统计数据失败"); } finally { setLoading(false); } }, [filters, message]); useEffect(() => { const next = new URLSearchParams(searchParams); for (const [key, value] of Object.entries(filters)) { if (value) next.set(key, value); else next.delete(key); } if (rangePreset) next.set("rangePreset", rangePreset); else next.delete("rangePreset"); setSearchParams(next, { replace: true }); void reload(); }, [filters, rangePreset]); useEffect(() => { setModelPage(1); setUserPage(1); setFailurePage(1); setPricingPage(1); }, [filters]); useEffect(() => { setUserOptions(users); }, [users]); const searchUsers = async (keyword: string) => { setSearchingUsers(true); try { const result = await listAdminUsers({ keyword: keyword.trim() || undefined, page: 1, limit: 50 }); setUserOptions(result.users); } catch (error) { message.error(error instanceof Error ? error.message : "搜索用户失败"); } finally { setSearchingUsers(false); } }; const modelOptions = useMemo(() => { const names = new Set(); channels.forEach((channel) => channel.models?.forEach((name) => names.add(name))); data?.models.forEach((item) => item.model !== "未识别" && names.add(item.model)); return [...names].sort().map((name) => ({ label: name, value: name })); }, [channels, data?.models]); const pricingModelOptions = useMemo(() => { const names = new Set(); const sourceChannels = channels.filter((channel) => channel.enabled !== false && (!pricingChannelId || channel.id === pricingChannelId)); sourceChannels.forEach((channel) => channel.models?.forEach((name) => names.add(name))); if (editingPricing?.model && (!pricingChannelId || editingPricing.channelId === pricingChannelId)) { names.add(editingPricing.model); } return [...names].sort().map((name) => ({ label: name, value: name })); }, [channels, editingPricing?.channelId, editingPricing?.model, pricingChannelId]); const preparePricingForm = (pricing: ModelPricing | null) => { setEditingPricing(pricing); form.resetFields(); form.setFieldsValue( pricing ? { channelId: pricing.channelId || undefined, model: pricing.model, capability: pricing.capability, currency: pricing.currency, inputPerMillion: formatPriceInput(pricing.inputPerMillionMicros), outputPerMillion: formatPriceInput(pricing.outputPerMillionMicros), cachedPerMillion: formatPriceInput(pricing.cachedPerMillionMicros), perRequest: formatPriceInput(pricing.perRequestMicros), perMedia: formatPriceInput(pricing.perMediaMicros), perVideoSecond: formatPriceInput(pricing.perVideoSecondMicros), } : { channelId: undefined, model: "", capability: "text", currency: "USD", inputPerMillion: "", outputPerMillion: "", cachedPerMillion: "", perRequest: "", perMedia: "", perVideoSecond: "" }, ); setPricingModalOpen(true); }; const openPricing = (pricing?: ModelPricing) => { const nextPricing = pricing || null; if (pricingWorkspaceOpen) { setPendingPricing(nextPricing); setPricingWorkspaceOpen(false); } else { preparePricingForm(nextPricing); } }; const handlePricingValuesChange = (changedValues: Partial, values: PricingFormValues) => { if (Object.prototype.hasOwnProperty.call(changedValues, "channelId")) { const nextModels = channels.filter((channel) => channel.enabled !== false && (!values.channelId || channel.id === values.channelId)).flatMap((channel) => channel.models || []); if (values.model && !nextModels.includes(values.model)) form.setFieldValue("model", undefined); return; } if (!Object.prototype.hasOwnProperty.call(changedValues, "model") || !values.model) return; const matchingChannels = channels.filter((channel) => channel.enabled !== false && channel.models?.includes(values.model)); if (values.channelId && matchingChannels.some((channel) => channel.id === values.channelId)) return; if (matchingChannels.length) form.setFieldValue("channelId", matchingChannels[0].id); }; const handlePricingModelChange = (modelName: string) => { const currentChannelId = form.getFieldValue("channelId") as string | undefined; const matchingChannels = channels.filter((channel) => channel.enabled !== false && channel.models?.includes(modelName)); const matchingChannel = matchingChannels.find((channel) => channel.id === currentChannelId) || matchingChannels[0]; form.setFieldsValue({ model: modelName, channelId: matchingChannel?.id || currentChannelId }); }; const savePricing = async () => { const values = await form.validateFields(); const payload = { channelId: values.channelId || "", model: values.model.trim(), capability: values.capability, currency: values.currency.trim().toUpperCase(), inputPerMillionMicros: toMicros(values.inputPerMillion), outputPerMillionMicros: toMicros(values.outputPerMillion), cachedPerMillionMicros: toMicros(values.cachedPerMillion), perRequestMicros: toMicros(values.perRequest), perMediaMicros: toMicros(values.perMedia), perVideoSecondMicros: toMicros(values.perVideoSecond), }; setSavingPricing(true); try { const result = editingPricing ? await updateAdminModelPricing(editingPricing.id, payload) : await createAdminModelPricing(payload); setPricings((items) => (editingPricing ? items.map((item) => (item.id === result.pricing.id ? result.pricing : item)) : [...items, result.pricing])); setPricingModalOpen(false); message.success("模型价格已保存,后续调用将按新价格记录费用快照"); } catch (error) { message.error(error instanceof Error ? error.message : "保存价格失败"); } finally { setSavingPricing(false); } }; const removePricing = async (id: string) => { try { await deleteAdminModelPricing(id); setPricings((items) => items.filter((item) => item.id !== id)); message.success("价格配置已删除"); } catch (error) { message.error(error instanceof Error ? error.message : "删除价格失败"); } }; const modelColumns: ColumnsType = [ { title: "模型", dataIndex: "model", fixed: "left", width: 210, render: (value, row) => (
{value}
{capabilityLabel(row.capability)}
), }, { title: "任务 / 请求", width: 120, render: (_, row) => `${row.tasks} / ${row.requests}` }, { title: "用户", dataIndex: "uniqueUsers", width: 80 }, { title: "任务成功率", dataIndex: "taskSuccessRate", width: 110, render: percent }, { title: "请求成功率", dataIndex: "requestSuccessRate", width: 110, render: percent }, { title: "P50 / P95", width: 145, render: (_, row) => `${formatDuration(row.p50DurationMs)} / ${formatDuration(row.p95DurationMs)}` }, { title: "Token(入 / 出 / 缓存)", width: 190, render: (_, row) => (row.usageAvailable ? `${formatNumber(row.inputTokens)} / ${formatNumber(row.outputTokens)} / ${formatNumber(row.cachedTokens)}` : "--") }, { title: "媒体 / 视频秒", width: 125, render: (_, row) => `${row.mediaCount} / ${row.videoSeconds}` }, { title: "估算费用", width: 120, render: (_, row) => formatCost(row.estimatedCostMicros, row.currency, row.costAvailable) }, ]; const userColumns: ColumnsType = [ { title: "用户", dataIndex: "name", width: 180, render: (name, row) => (
{name}
{row.userId}
), }, { title: "活跃天数", dataIndex: "activeDays", width: 95 }, { title: "任务", dataIndex: "tasks", width: 80 }, { title: "Agent 消息", dataIndex: "agentMessages", width: 105 }, { title: "画布活跃天数", dataIndex: "canvasDays", width: 120 }, { title: "素材 / 资源", width: 110, render: (_, row) => `${row.assets} / ${row.resources}` }, { title: "常用模型", dataIndex: "commonModel", ellipsis: true, render: (value) => value || "--" }, ]; const failureColumns: ColumnsType = [ { title: "错误类型", dataIndex: "type", width: 120, render: (value) => }, { title: "模型", dataIndex: "model", width: 220 }, { title: "次数", dataIndex: "count", width: 90 }, { title: "最近错误", dataIndex: "lastError", ellipsis: true, render: (value) => {value || "--"} }, { title: "最近发生", dataIndex: "lastSeenAt", width: 170, render: (value) => dayjs(value).format("YYYY-MM-DD HH:mm") }, ]; const pricingColumns: ColumnsType = [ { title: "模型", dataIndex: "model", width: 210, render: (value, row) => (
{value}
{row.channelId ? channels.find((channel) => channel.id === row.channelId)?.name || row.channelId : "全部渠道"}
), }, { title: "能力", dataIndex: "capability", width: 90, render: capabilityLabel }, { title: "输入 / 输出 / 缓存(每百万 Token)", width: 250, render: (_, row) => `${formatMoney(fromMicros(row.inputPerMillionMicros), row.currency)} / ${formatMoney(fromMicros(row.outputPerMillionMicros), row.currency)} / ${formatMoney(fromMicros(row.cachedPerMillionMicros), row.currency)}`, }, { title: "每请求 / 每媒体 / 每视频秒", width: 220, render: (_, row) => `${formatMoney(fromMicros(row.perRequestMicros), row.currency)} / ${formatMoney(fromMicros(row.perMediaMicros), row.currency)} / ${formatMoney(fromMicros(row.perVideoSecondMicros), row.currency)}`, }, { title: "操作", width: 170, render: (_, row) => ( , onClick: () => openPricing(row) }} actions={[ { key: "delete", label: "删除", icon: , danger: true, confirm: { title: "删除价格配置?", description: "删除后新的调用不再使用这条价格配置,历史费用不受影响。", okText: "确认删除" }, onClick: () => removePricing(row.id), }, ]} /> ), }, ]; const trend = data?.trend || []; const currentTrend = trend[trend.length - 1]; const previousTrend = trend[trend.length - 2]; const modelRows = data?.models || []; const userRows = data?.users || []; const failureRows = data?.failures || []; const pricingRows = pricings; const failureTotal = failureRows.reduce((sum, item) => sum + item.count, 0); const topFailure = failureRows.reduce((current, item) => (!current || item.count > current.count ? item : current), undefined); const pricedModelCount = modelRows.filter((item) => item.costAvailable).length; const trendHasData = trendMetric === "volume" ? trend.some((item) => item.tasks > 0 || item.requests > 0) : trendMetric === "quality" ? trend.some((item) => item.requests > 0) : trend.some((item) => item.activeUsers > 0); const trendTitle = trendMetric === "volume" ? "任务与请求趋势" : trendMetric === "quality" ? "请求质量趋势" : "用户活跃趋势"; const pageRows = (rows: T[], page: number) => rows.slice((page - 1) * analyticsPageSize, page * analyticsPageSize); const applyRangePreset = (preset: RangePreset) => { const end = dayjs(); const start = preset === "7d" ? end.subtract(6, "day") : preset === "30d" ? end.subtract(29, "day") : end.subtract(59, "day"); setRangePreset(preset); setRange([start, end]); }; const openAnalysis = (tab: AnalysisTab) => { setAnalysisTab(tab); window.requestAnimationFrame(() => document.getElementById("admin-analytics-analysis")?.scrollIntoView({ behavior: window.matchMedia("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth", block: "start" })); }; return (
{userId ? user.id === userId)?.displayName || userId}`} onRemove={() => setUserId(undefined)} /> : null} {model ? setModel(undefined)} /> : null} {channelId ? channel.id === channelId)?.name || channelId}`} onRemove={() => setChannelId(undefined)} /> : null} {capability ? setCapability(undefined)} /> : null} } onReset={() => { setUserId(undefined); setModel(undefined); setChannelId(undefined); setCapability(undefined); }} trailing={ <>
时间范围 { if (value?.[0] && value?.[1]) { setRangePreset(undefined); setRange([value[0], value[1]]); } }} />
exportAdminAnalytics(filters)} fileName={() => `usage-${filters.from}-${filters.to}.csv`} label="导出 CSV" /> } filters={ <> ({ label: user.displayName || user.username, value: user.id }))} filterOption={false} loading={searchingUsers} onSearch={(value) => void searchUsers(value)} /> ({ label: channel.name, value: channel.id }))} /> } >
{( [ ["7d", "7 天"], ["30d", "30 天"], ["60d", "60 天"], ] as const ).map(([value, label]) => ( ))}
} label="活跃用户" value={data ? formatNumber(data.kpi.activeUsers) : "--"} trend={formatCountDelta(currentTrend?.activeUsers, previousTrend?.activeUsers)} detail={data ? `DAU ${formatNumber(data.kpi.dau)} · WAU ${formatNumber(data.kpi.wau)} · MAU ${formatNumber(data.kpi.mau)}` : undefined} /> } label="生成任务" value={data ? formatNumber(data.kpi.generationTasks) : "--"} trend={formatCountDelta(currentTrend?.tasks, previousTrend?.tasks)} detail={data ? `上游请求 ${formatNumber(data.kpi.upstreamRequests)} · 队列 ${formatNumber(data.kpi.currentQueuedTasks)}` : undefined} /> } label="服务质量" value={data ? percent(data.kpi.successRate) : "--"} trend={formatRateDelta(currentTrend?.requestSuccessRate, previousTrend?.requestSuccessRate)} detail={data ? `P95 ${formatDuration(data.kpi.p95DurationMs)}` : undefined} tone={data && data.kpi.successRate < 90 ? "warning" : "success"} /> } label="估算费用" value={data ? (data.kpi.costAvailable ? formatCost(data.kpi.estimatedCostMicros, data.kpi.currency, true) : "待配置") : "--"} detail={data ? (data.kpi.costAvailable ? `${pricedModelCount}/${modelRows.length} 个模型可估算` : "价格未完整配置,暂不能汇总") : undefined} tone={data?.kpi.costAvailable ? "neutral" : "warning"} />

{trendTitle}

{trendMetric === "volume" ? "生成任务与真实上游请求分开统计。" : trendMetric === "quality" ? "成功率按真实上游请求计算。" : "活跃用户按自然日去重统计。"}

{( [ ["volume", "用量"], ["quality", "质量"], ["activity", "活跃"], ] as const ).map(([value, label]) => ( ))}
{trendHasData ? (
value.slice(5)} tick={{ fontSize: 11 }} /> {trendMetric === "quality" ? `${value}%`} tick={{ fontSize: 11 }} /> : } `日期 ${value}`} /> {trendMetric === "volume" ? : null} {trendMetric === "volume" ? ( <> ) : null} {trendMetric === "quality" ? : null} {trendMetric === "activity" ? : null}
) : (
当前范围暂无{trendMetric === "quality" ? "质量" : trendMetric === "activity" ? "活跃" : "使用"}数据

可以调整时间范围或筛选条件后重新查看。

)}

深度分析

按模型、用户或异常类型继续核对当前统计范围。

setAnalysisTab(key as AnalysisTab)} className="admin-analytics-tabs" items={[ { key: "models", label: "模型分析", children: ( `${row.model}:${row.capability}`, size: "small", loading, columns: modelColumns, dataSource: pageRows(modelRows, modelPage), pagination: false, scroll: { x: 1250 } }} empty={} skeletonColumns={9} footer={ setModelPage(page)} pageSizeOptions={[analyticsPageSize]} />} /> ), }, { key: "users", label: "用户活动", children: ( } skeletonColumns={7} footer={ setUserPage(page)} pageSizeOptions={[analyticsPageSize]} />} /> ), }, { key: "failures", label: `异常定位${data?.failures.length ? ` (${data.failures.reduce((sum, item) => sum + item.count, 0)})` : ""}`, children: ( `${row.type}:${row.model}`, size: "small", loading, columns: failureColumns, dataSource: pageRows(failureRows, failurePage), pagination: false, scroll: { x: 900 } }} empty={} skeletonColumns={5} footer={ setFailurePage(page)} pageSizeOptions={[analyticsPageSize]} />} /> ), }, ]} />
setPricingWorkspaceOpen(false)} afterOpenChange={(open) => { if (open || pendingPricing === undefined) return; const nextPricing = pendingPricing; setPendingPricing(undefined); preparePricingForm(nextPricing); }} extra={ } >

价格只影响后续调用的费用快照,历史统计不会被重新计算。

} skeletonColumns={5} footer={ setPricingPage(page)} pageSizeOptions={[analyticsPageSize]} />} />
setPricingModalOpen(false)} onOk={() => void savePricing()} confirmLoading={savingPricing} okText="保存" cancelText="取消" width={760} zIndex={1200} destroyOnHidden >
channel.enabled !== false).map((channel) => ({ label: channel.name, value: channel.id }))} />
); } function AnalyticsHealthCard({ icon, label, value, trend, detail, tone = "neutral" }: { icon: ReactNode; label: string; value: ReactNode; trend?: { value: string; tone?: AdminStatusTone }; detail?: string; tone?: AdminStatusTone }) { return (
{label}
{value}
{trend ? : null} {detail ? {detail} : null}
); } function AnalyticsAttentionItem({ icon, label, value, description, tone = "neutral", onClick }: { icon: ReactNode; label: string; value: ReactNode; description: string; tone?: AdminStatusTone; onClick?: () => void }) { const content = ( <> {label} {description} {value} ); return onClick ? ( ) : (
{content}
); } function FilterSelect({ label, value, onChange, options, width = 150, filterOption = true, loading, onSearch, }: { label: string; value?: string; onChange: (value?: string) => void; options: Array<{ label: string; value: string }>; width?: number; filterOption?: boolean; loading?: boolean; onSearch?: (value: string) => void; }) { return (
{label}
); } function validatePriceInput(_: unknown, value?: string) { const normalized = value?.trim() || ""; if (!normalized || /^(?:\d+(?:\.\d{0,6})?|\.\d{1,6})$/.test(normalized)) return Promise.resolve(); return Promise.reject(new Error("请输入非负价格,最多 6 位小数")); } function capabilityLabel(value: string) { return capabilityOptions.find((item) => item.value === value)?.label || "未分类"; } function percent(value: number) { return `${Number(value || 0).toFixed(1)}%`; } function formatDuration(value: number) { if (!value) return "--"; return value >= 1000 ? `${(value / 1000).toFixed(1)}s` : `${value}ms`; } function formatNumber(value: number) { return new Intl.NumberFormat("zh-CN", { notation: value >= 100000 ? "compact" : "standard", maximumFractionDigits: 1 }).format(value); } function formatCountDelta(current?: number, previous?: number) { if (current === undefined || previous === undefined) return undefined; const delta = current - previous; const direction = delta > 0 ? "↑" : delta < 0 ? "↓" : "→"; const value = previous === 0 ? formatNumber(Math.abs(delta)) : `${Math.abs((delta / previous) * 100).toFixed(1)}%`; return { value: `较前一日 ${direction} ${value}`, tone: delta >= 0 ? ("success" as const) : ("warning" as const) }; } function formatRateDelta(current?: number, previous?: number) { if (current === undefined || previous === undefined) return undefined; const delta = current - previous; const direction = delta > 0 ? "↑" : delta < 0 ? "↓" : "→"; return { value: `较前一日 ${direction} ${Math.abs(delta).toFixed(1)}pp`, tone: delta >= 0 ? ("success" as const) : ("warning" as const) }; } function formatCost(micros: number, currency?: string, available?: boolean) { return available ? formatMoney(fromMicros(micros), currency || "USD") : "--"; } function formatMoney(value: number, currency = "USD") { if (currency === "MIXED") return `${value.toFixed(6)}(混合币种)`; try { return new Intl.NumberFormat("zh-CN", { style: "currency", currency, minimumFractionDigits: 2, maximumFractionDigits: 6 }).format(value); } catch { return `${currency} ${value.toFixed(6)}`; } } function fromMicros(value: number) { return value / 1_000_000; } function formatPriceInput(micros: number) { return fromMicros(micros).toFixed(6); } function toMicros(value?: string | number) { const parsed = typeof value === "number" ? value : Number(value?.trim() || 0); return Number.isFinite(parsed) && parsed >= 0 ? Math.round(parsed * 1_000_000) : 0; } function filterDate(value: string | null, fallback: Dayjs) { if (!value) return fallback; const parsed = dayjs(value); return parsed.isValid() ? parsed : fallback; } function resolveRangePreset(range: [Dayjs, Dayjs]): RangePreset | undefined { const end = dayjs(); if (!range[1].isSame(end, "day")) return undefined; if (range[0].isSame(end.subtract(6, "day"), "day")) return "7d"; if (range[0].isSame(end.subtract(29, "day"), "day")) return "30d"; if (range[0].isSame(end.subtract(59, "day"), "day")) return "60d"; return undefined; } function parseRangePreset(value: string | null): RangePreset | undefined { return value === "7d" || value === "30d" || value === "60d" ? value : undefined; } function initialRangePreset(searchParams: URLSearchParams): RangePreset | undefined { const explicit = parseRangePreset(searchParams.get("rangePreset")); if (explicit) return explicit; if (searchParams.has("from") || searchParams.has("to")) return resolveRangePresetFromQuery(searchParams.get("from"), searchParams.get("to")); return "30d"; } function initialAnalyticsRange(searchParams: URLSearchParams, preset: RangePreset | undefined): [Dayjs, Dayjs] { const end = dayjs(); if (preset) { const days = preset === "7d" ? 6 : preset === "30d" ? 29 : 59; return [end.subtract(days, "day"), end]; } return [filterDate(searchParams.get("from"), end.subtract(29, "day")), filterDate(searchParams.get("to"), end)]; } function resolveRangePresetFromQuery(from: string | null, to: string | null): RangePreset | undefined { const start = from ? dayjs(from) : null; const end = to ? dayjs(to) : null; if (!start?.isValid() || !end?.isValid()) return undefined; return resolveRangePreset([start, end]); }