Выбор периода
Сделай выбор даты отчёта: календарь на месяц и над ним ряд быстрых вариантов «Сегодня», «Вчера», «Неделя назад», при нажатии на которые дата подставляется в календарь. Выбранная дата отдаётся наружу через колбэк onChange.
date-range__mcp__claude-code__claude-opus-5__1 · 24.09.2026, 13:30:20 мск
Первый вызов модели получил 12 483 токена входа, включая системный промпт Claude Code; вызовов модели 2, каждый отправлял разговор заново, и самый большой получил 16 315 токенов. Контекст до задачи — оценка по длине текста, для русского текста она занижает число токенов в полтора-два раза.
Компилятор
Ошибок нет: все компоненты и пропсы существуют.
Линтер и покрытие
- inline-styleСтроки 43, 44, 71Инлайновые стили вместо классов и токенов библиотеки
JxCalendar, JxChip
Ожидались JxCalendar, JxChip · покрытие 100%
- get_rules({"task":"ui"}) → ~1247 токенов
- get_component_api({"name":"JxCalendar","detail":"full"}) → ~516 токенов
- get_component_api({"name":"JxChip","detail":"full"}) → ~360 токенов
Инструменты (search_components,get_component_api,get_component_examples,list_design_tokens,get_docs,get_rules, ~1213)
Вход 4 · выход 1 467 · из кэша 24 496 · в кэш 4 298 · 16 с
Рендер
Код компонента
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
import { useCallback, useState } from 'react';
import { JxCalendar, JxChip } from '@jinx-ui/react';
type ReportDatePickerProps = {
value?: Date | null;
defaultValue?: Date | null;
onChange?: (value: Date | null) => void;
};
const DAY_MS = 24 * 60 * 60 * 1000;
function startOfDay(date: Date): Date {
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}
function shiftDays(days: number): Date {
return startOfDay(new Date(Date.now() - days * DAY_MS));
}
const presets: { id: string; label: string; resolve: () => Date }[] = [
{ id: 'today', label: 'Сегодня', resolve: () => shiftDays(0) },
{ id: 'yesterday', label: 'Вчера', resolve: () => shiftDays(1) },
{ id: 'week-ago', label: 'Неделя назад', resolve: () => shiftDays(7) },
];
function isSameDay(a: Date | null | undefined, b: Date): boolean {
return !!a && startOfDay(a).getTime() === b.getTime();
}
export default function ReportDatePicker({ value, defaultValue = null, onChange }: ReportDatePickerProps) {
const [internal, setInternal] = useState<Date | null>(defaultValue);
const current = value !== undefined ? value : internal;
const commit = useCallback(
(next: Date | null) => {
if (value === undefined) setInternal(next);
onChange?.(next);
},
[onChange, value],
);
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px', maxWidth: '320px' }}>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }} role="group" aria-label="Быстрый выбор даты отчёта">
{presets.map((preset) => {
const presetDate = preset.resolve();
return (
<JxChip
key={preset.id}
role="button"
tabIndex={0}
aria-pressed={isSameDay(current, presetDate)}
active={isSameDay(current, presetDate)}
onClick={() => commit(presetDate)}
onKeyDown={(event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
commit(presetDate);
}
}}
>
{preset.label}
</JxChip>
);
})}
</div>
<JxCalendar locale="ru-RU" value={current} onValueChange={commit} aria-label="Дата отчёта" />
<p
style={{
margin: 0,
font: 'inherit',
fontFamily: 'var(--jx-font-sans)',
color: current ? 'var(--jx-text)' : 'var(--jx-text-2)',
}}
aria-live="polite"
>
{current
? `Отчёт за ${current.toLocaleDateString('ru-RU', { day: 'numeric', month: 'long', year: 'numeric' })}`
: 'Дата не выбрана — выберите день в календаре или быстрый вариант выше.'}
</p>
</div>
);
}