langfuse

Форк
0
/
date-picker.tsx 
207 строк · 6.1 Кб
1
"use client";
2

3
import * as React from "react";
4
import { Calendar as CalendarIcon, X } from "lucide-react";
5
import { Button } from "@/src/components/ui/button";
6
import { Calendar } from "@/src/components/ui/calendar";
7
import {
8
  Popover,
9
  PopoverContent,
10
  PopoverTrigger,
11
} from "@/src/components/ui/popover";
12
import { cn } from "@/src/utils/tailwind";
13
import { type DateRange } from "react-day-picker";
14
import { addMinutes, format } from "date-fns";
15
import {
16
  Select,
17
  SelectContent,
18
  SelectItem,
19
  SelectTrigger,
20
  SelectValue,
21
} from "@/src/components/ui/select";
22
import { useEffect, useState } from "react";
23
import {
24
  type DateTimeAggregationOption,
25
  dateTimeAggregationSettings,
26
  dateTimeAggregationOptions,
27
} from "@/src/features/dashboard/lib/timeseries-aggregation";
28
import { useMediaQuery } from "react-responsive";
29
import { type DashboardDateRange } from "@/src/pages/project/[projectId]";
30
import { isValidOption } from "@/src/utils/types";
31
import { setBeginningOfDay, setEndOfDay } from "@/src/utils/dates";
32

33
export const DEFAULT_DATE_RANGE_SELECTION = "Date range" as const;
34
export type AvailableDateRangeSelections =
35
  | typeof DEFAULT_DATE_RANGE_SELECTION
36
  | DateTimeAggregationOption;
37

38
export function DatePicker({
39
  date,
40
  onChange,
41
  clearable = false,
42
  className,
43
}: {
44
  date?: Date | undefined;
45
  onChange: (date: Date | undefined) => void;
46
  clearable?: boolean;
47
  className?: string;
48
}) {
49
  return (
50
    <div className="flex flex-row gap-2 align-middle">
51
      <Popover>
52
        <PopoverTrigger asChild>
53
          <Button
54
            variant={"outline"}
55
            className={cn(
56
              "justify-start text-left font-normal",
57
              !date && "text-muted-foreground",
58
              className,
59
            )}
60
          >
61
            <CalendarIcon className="mr-2 h-4 w-4" />
62
            {date ? format(date, "PPP") : <span>Pick a date</span>}
63
          </Button>
64
        </PopoverTrigger>
65
        <PopoverContent className="w-auto p-0">
66
          <Calendar
67
            mode="single"
68
            selected={date}
69
            onSelect={(d) => onChange(d)}
70
            initialFocus
71
          />
72
        </PopoverContent>
73
      </Popover>
74
      {date && clearable && (
75
        <Button
76
          variant="ghost"
77
          size="icon"
78
          onClick={() => onChange(undefined)}
79
          title="reset date"
80
        >
81
          <X size={14} />
82
        </Button>
83
      )}
84
    </div>
85
  );
86
}
87

88
export type DatePickerWithRangeProps = {
89
  dateRange?: DashboardDateRange;
90
  className?: string;
91
  selectedOption: AvailableDateRangeSelections;
92
  setDateRangeAndOption: (
93
    option: AvailableDateRangeSelections,
94
    date?: DashboardDateRange,
95
  ) => void;
96
};
97

98
export function DatePickerWithRange({
99
  className,
100
  dateRange,
101
  selectedOption,
102
  setDateRangeAndOption,
103
}: DatePickerWithRangeProps) {
104
  const [internalDateRange, setInternalDateRange] = useState<
105
    DateRange | undefined
106
  >(dateRange);
107

108
  useEffect(() => {
109
    setInternalDateRange(dateRange);
110
  }, [dateRange]);
111

112
  const onDropDownSelection = (value: string) => {
113
    if (isValidOption(value)) {
114
      const setting = dateTimeAggregationSettings[value];
115
      const fromDate = addMinutes(new Date(), -1 * setting.minutes);
116

117
      setDateRangeAndOption(value, {
118
        from: fromDate,
119
        to: new Date(),
120
      });
121
      setInternalDateRange({ from: fromDate, to: new Date() });
122
    } else {
123
      setDateRangeAndOption(DEFAULT_DATE_RANGE_SELECTION, undefined);
124
    }
125
  };
126

127
  const onCalendarSelection = (range?: DateRange) => {
128
    const newRange = range
129
      ? {
130
          from: range.from ? setBeginningOfDay(range.from) : undefined,
131
          to: range.to ? setEndOfDay(range.to) : undefined,
132
        }
133
      : undefined;
134

135
    setInternalDateRange(newRange);
136
    if (newRange && newRange.from && newRange.to) {
137
      const dashboardDateRange: DashboardDateRange = {
138
        from: newRange.from,
139
        to: newRange.to,
140
      };
141
      setDateRangeAndOption(DEFAULT_DATE_RANGE_SELECTION, dashboardDateRange);
142
    }
143
  };
144

145
  const isSmallScreen = useMediaQuery({ query: "(max-width: 640px)" });
146

147
  return (
148
    <div
149
      className={cn("my-3 flex flex-col-reverse gap-2 md:flex-row", className)}
150
    >
151
      <Popover>
152
        <PopoverTrigger asChild>
153
          <Button
154
            id="date"
155
            variant={"outline"}
156
            className={cn(
157
              "w-[330px] justify-start text-left font-normal",
158
              !internalDateRange && "text-muted-foreground",
159
            )}
160
          >
161
            <CalendarIcon className="mr-2 h-4 w-4" />
162
            {internalDateRange?.from ? (
163
              internalDateRange.to ? (
164
                <>
165
                  {format(internalDateRange.from, "LLL dd, yy : HH:mm")} -{" "}
166
                  {format(internalDateRange.to, "LLL dd, yy : HH:mm")}
167
                </>
168
              ) : (
169
                format(internalDateRange.from, "LLL dd, y")
170
              )
171
            ) : (
172
              <span>Pick a date</span>
173
            )}
174
          </Button>
175
        </PopoverTrigger>
176
        <PopoverContent className="w-auto p-0" align="start">
177
          <Calendar
178
            initialFocus={true}
179
            mode="range"
180
            defaultMonth={internalDateRange?.from}
181
            selected={internalDateRange}
182
            onSelect={onCalendarSelection}
183
            numberOfMonths={isSmallScreen ? 1 : 2} // TODO: make this configurable to screen size
184
          />
185
        </PopoverContent>
186
      </Popover>
187
      <Select value={selectedOption} onValueChange={onDropDownSelection}>
188
        <SelectTrigger className="w-[120px]  hover:bg-accent hover:text-accent-foreground focus:ring-0 focus:ring-offset-0">
189
          <SelectValue placeholder="Select" />
190
        </SelectTrigger>
191
        <SelectContent position="popper" defaultValue={60}>
192
          <SelectItem
193
            key={DEFAULT_DATE_RANGE_SELECTION}
194
            value={DEFAULT_DATE_RANGE_SELECTION}
195
          >
196
            {DEFAULT_DATE_RANGE_SELECTION}
197
          </SelectItem>
198
          {dateTimeAggregationOptions.toReversed().map((item) => (
199
            <SelectItem key={item} value={item}>
200
              {item}
201
            </SelectItem>
202
          ))}
203
        </SelectContent>
204
      </Select>
205
    </div>
206
  );
207
}
208

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.