Выбор периода

Сделай выбор даты отчёта: календарь на месяц и над ним ряд быстрых вариантов «Сегодня», «Вчера», «Неделя назад», при нажатии на которые дата подставляется в календарь. Выбранная дата отдаётся наружу через колбэк onChange.

date-range__none__claude-code__claude-opus-5__1 · 23.09.2026, 19:54:16 мск

Есть проблемы
Без контекста · claude-opus-5 · Claude Code
Контекст до задачи~154
Токенов на прогон10 952
Цена$0.065
Ошибок компилятора6

Первый вызов модели получил 8 596 токенов входа, включая системный промпт Claude Code. Контекст до задачи — оценка по длине текста, для русского текста она занижает число токенов в полтора-два раза.

Компилятор

  • Строка 2 · TS2724
    '"@jinx-ui/react"' has no exported member named 'Button'. Did you mean 'JxButton'?
  • Строка 2 · TS2305
    Module '"@jinx-ui/react"' has no exported member 'ButtonGroup'.
  • Строка 2 · TS2724
    '"@jinx-ui/react"' has no exported member named 'Calendar'. Did you mean 'JxCalendar'?
  • Строка 2 · TS2305
    Module '"@jinx-ui/react"' has no exported member 'Card'.
  • Строка 2 · TS2305
    Module '"@jinx-ui/react"' has no exported member 'Stack'.
  • Строка 2 · TS2305
    Module '"@jinx-ui/react"' has no exported member 'Text'.
Выдуманные компоненты
ButtonButtonGroupCalendarCardStackText

Линтер и покрытие

  • inline-styleСтрока 67
    Инлайновые стили вместо классов и токенов библиотеки
Компоненты библиотеки

Ни одного: код написан без библиотеки, поэтому прогон не засчитан

Ожидались JxCalendar, JxChip · покрытие 0%

Контекст

Только формулировка задачи

Вход 2 · выход 2 356 · из кэша 8 233 · в кэш 361 · 27 с

Рендер

Код компонента

tsx95 строк
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { useCallback, useMemo, useState } from 'react';
import { Button, ButtonGroup, Calendar, Card, Stack, Text } from '@jinx-ui/react';

// Предполагаемый контракт Calendar из @jinx-ui/react:
// value/onChange для выбранной даты и month/onMonthChange для видимого месяца.
type ReportDatePickerProps = {
  value?: Date;
  defaultValue?: Date;
  onChange: (date: Date) => void;
};

function startOfDay(date: Date): Date {
  const result = new Date(date);
  result.setHours(0, 0, 0, 0);
  return result;
}

function addDays(date: Date, days: number): Date {
  const result = startOfDay(date);
  result.setDate(result.getDate() + days);
  return result;
}

function isSameDay(a: Date, b: Date): boolean {
  return (
    a.getFullYear() === b.getFullYear() &&
    a.getMonth() === b.getMonth() &&
    a.getDate() === b.getDate()
  );
}

function startOfMonth(date: Date): Date {
  const result = startOfDay(date);
  result.setDate(1);
  return result;
}

export default function ReportDatePicker({ value, defaultValue, onChange }: ReportDatePickerProps) {
  const [internalDate, setInternalDate] = useState<Date>(() =>
    startOfDay(defaultValue ?? new Date()),
  );
  const selected = value ? startOfDay(value) : internalDate;

  const [visibleMonth, setVisibleMonth] = useState<Date>(() => startOfMonth(selected));

  const presets = useMemo(() => {
    const today = startOfDay(new Date());
    return [
      { id: 'today', label: 'Сегодня', date: today },
      { id: 'yesterday', label: 'Вчера', date: addDays(today, -1) },
      { id: 'week-ago', label: 'Неделя назад', date: addDays(today, -7) },
    ];
  }, []);

  const selectDate = useCallback(
    (next: Date) => {
      const normalized = startOfDay(next);
      setInternalDate(normalized);
      setVisibleMonth(startOfMonth(normalized));
      onChange(normalized);
    },
    [onChange],
  );

  return (
    <Card>
      <Stack direction="vertical" style={{ gap: 'var(--jx-space-3)' }}>
        <Text as="label" variant="caption">
          Дата отчёта
        </Text>

        <ButtonGroup aria-label="Быстрый выбор даты">
          {presets.map((preset) => (
            <Button
              key={preset.id}
              type="button"
              variant={isSameDay(preset.date, selected) ? 'primary' : 'secondary'}
              aria-pressed={isSameDay(preset.date, selected)}
              onClick={() => selectDate(preset.date)}
            >
              {preset.label}
            </Button>
          ))}
        </ButtonGroup>

        <Calendar
          value={selected}
          month={visibleMonth}
          onMonthChange={(month: Date) => setVisibleMonth(startOfMonth(month))}
          onChange={selectDate}
        />
      </Stack>
    </Card>
  );
}