| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- import { useState } from 'react';
- import { CalendarIcon } from 'lucide-react';
- import type { FunnelPeriod } from '../../../api/types';
- import { toSnapshotParam, yesterday } from '../period';
- import { Calendar } from '@/components/ui/calendar';
- import {
- Popover,
- PopoverContent,
- PopoverTrigger,
- } from '@/components/ui/popover';
- import { cn } from '@/lib/utils';
- interface Props {
- period: FunnelPeriod;
- /** Selected day for `period: 'day'`; `null` = latest available day. */
- snapshotDt: Date | null;
- /** Pick a historical day → switch to single-day mode. */
- onPickDate: (d: Date) => void;
- /** Reset single-day back to the latest available day. */
- onPickLatest: () => void;
- /** Pick a rolling window. */
- onPickRolling: (p: 'last_7d' | 'last_30d') => void;
- }
- // 统一 segmented:选中态由 React 状态直接驱动 mint 实色,不依赖 shadcn 变体。
- const SEG =
- 'h-8 px-3 inline-flex items-center gap-1.5 rounded-md text-sm font-medium transition-colors cursor-pointer';
- const ON = 'bg-primary text-primary-foreground shadow-sm';
- const OFF = 'text-muted-foreground hover:text-foreground hover:bg-background';
- /**
- * 时间选择 — 单日 / 近 7 天 / 近 30 天 三选一的 segmented 控件(docs/04)。
- * 「单日」段点开日历可选历史日(上限昨日,T+1);任一选中 = mint 高亮,
- * 给明确的"当前在此周期"反馈。
- */
- export function TimePeriodSelect({
- period,
- snapshotDt,
- onPickDate,
- onPickLatest,
- onPickRolling,
- }: Props) {
- const max = yesterday();
- const [open, setOpen] = useState(false);
- return (
- <div className="inline-flex items-center gap-1 rounded-lg border border-border bg-muted/60 p-1">
- {/* 单日 —— 日历 popover;未选具体日 = 最新可用日 */}
- <Popover open={open} onOpenChange={setOpen}>
- <PopoverTrigger asChild>
- <button
- type="button"
- aria-label="选择历史日期"
- aria-pressed={period === 'day'}
- className={cn(SEG, period === 'day' ? ON : OFF)}
- >
- <CalendarIcon className="size-4" />
- <span>单日</span>
- <span className="tabular-nums opacity-90">
- {snapshotDt ? toSnapshotParam(snapshotDt) : '最新'}
- </span>
- </button>
- </PopoverTrigger>
- <PopoverContent className="w-auto p-0" align="start">
- {/* 最新可用日快捷项:回到默认(后端取 MAX(dt)) */}
- <button
- type="button"
- onClick={() => {
- onPickLatest();
- setOpen(false);
- }}
- className={cn(
- 'w-full px-3 py-2 text-left text-sm border-b border-border transition-colors',
- !snapshotDt
- ? 'text-primary font-medium'
- : 'text-foreground hover:bg-muted',
- )}
- >
- 最新可用日
- </button>
- <Calendar
- mode="single"
- selected={snapshotDt ?? undefined}
- defaultMonth={snapshotDt ?? max}
- disabled={{ after: max }}
- onSelect={(d) => {
- if (d) {
- onPickDate(d);
- setOpen(false);
- }
- }}
- />
- </PopoverContent>
- </Popover>
- {/* 近 7 天 / 近 30 天 */}
- <button
- type="button"
- aria-pressed={period === 'last_7d'}
- onClick={() => onPickRolling('last_7d')}
- className={cn(SEG, period === 'last_7d' ? ON : OFF)}
- >
- 近 7 天
- </button>
- <button
- type="button"
- aria-pressed={period === 'last_30d'}
- onClick={() => onPickRolling('last_30d')}
- className={cn(SEG, period === 'last_30d' ? ON : OFF)}
- >
- 近 30 天
- </button>
- </div>
- );
- }
- export default TimePeriodSelect;
|