feat(ui): searchable MultiSelect (cmdk) + DateRangePicker (react-day-picker)

This commit is contained in:
Александр Зимин
2026-05-12 13:55:35 +00:00
parent 9073229c0e
commit 21d95613fc
11 changed files with 533 additions and 92 deletions
+24 -29
View File
@@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'
import {
Badge,
Button,
DatePicker,
DateRangePicker,
EmptyState,
IconButton,
LoadingBlock,
@@ -380,34 +380,29 @@ function FilterPanel({
onChange={(e) => set('businessKey', e.target.value || undefined)}
onKeyDown={handleEnter}
/>
<DatePicker
label={t('audit.filter.from')}
value={fromDate}
onChange={(d) =>
set(
'from',
d
? `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(
d.getDate(),
).padStart(2, '0')}T00:00:00${localTzOffset(d)}`
: undefined,
)
}
/>
<DatePicker
label={t('audit.filter.to')}
value={toDate}
onChange={(d) =>
set(
'to',
d
? `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(
d.getDate(),
).padStart(2, '0')}T23:59:59${localTzOffset(d)}`
: undefined,
)
}
/>
{/* DateRangePicker заменяет пару отдельных DatePicker'ов — один
* popover с двумя месяцами, выбор start/end в одном UI. ISO sтроки
* c local TZ offset формируются здесь, чтобы backend получал
* правильный bounds (T00:00:00 для from, T23:59:59 для to). */}
<div className="md:col-span-2">
<DateRangePicker
label={t('audit.filter.range', { defaultValue: 'Период' })}
value={{ from: fromDate ?? undefined, to: toDate ?? undefined }}
onChange={({ from, to }) => {
const fromIso = from
? `${from.getFullYear()}-${String(from.getMonth() + 1).padStart(2, '0')}-${String(
from.getDate(),
).padStart(2, '0')}T00:00:00${localTzOffset(from)}`
: undefined
const toIso = to
? `${to.getFullYear()}-${String(to.getMonth() + 1).padStart(2, '0')}-${String(
to.getDate(),
).padStart(2, '0')}T23:59:59${localTzOffset(to)}`
: undefined
onChange({ ...filters, from: fromIso, to: toIso })
}}
/>
</div>
</div>
<div className="flex justify-end gap-2 pt-2 border-t border-line">
<Button type="button" variant="secondary" onClick={onReset}>