initial commit

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-03-23 08:46:51 +01:00
commit 4608494a3f
130 changed files with 40361 additions and 0 deletions

View File

@@ -0,0 +1,185 @@
import { forwardRef, useMemo } from 'react'
import DatePicker, { registerLocale } from 'react-datepicker'
import { cs } from 'date-fns/locale'
import { parse, format } from 'date-fns'
import 'react-datepicker/dist/react-datepicker.css'
registerLocale('cs', cs)
// Ensure portal root exists
if (typeof document !== 'undefined' && !document.getElementById('datepicker-portal')) {
const el = document.createElement('div')
el.id = 'datepicker-portal'
document.body.appendChild(el)
}
const isTouchDevice = () =>
typeof window !== 'undefined' && ('ontouchstart' in window || navigator.maxTouchPoints > 0)
interface CustomInputProps {
value?: string
onClick?: () => void
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
placeholder?: string
required?: boolean
readOnly?: boolean
disabled?: boolean
}
const CustomInput = forwardRef<HTMLInputElement, CustomInputProps>(
({ value, onClick, onChange, placeholder, required, readOnly, disabled }, ref) => (
<input
className="admin-form-input"
onClick={onClick}
onChange={onChange}
value={value}
placeholder={placeholder}
ref={ref}
required={required}
readOnly={readOnly}
disabled={disabled}
autoComplete="off"
/>
)
)
interface NativeInputProps {
mode: string
value: string
onChange: (value: string) => void
required?: boolean
minDate?: string
maxDate?: string
disabled?: boolean
}
const modeToInputType: Record<string, string> = { month: 'month', time: 'time' }
function NativeInput({ mode, value, onChange, required, minDate, maxDate, disabled }: NativeInputProps) {
const type = modeToInputType[mode] || 'date'
return (
<input
type={type}
lang="cs"
value={value || ''}
onChange={(e) => onChange(e.target.value)}
className="admin-form-input"
required={required}
disabled={disabled}
min={minDate || undefined}
max={maxDate || undefined}
/>
)
}
interface AdminDatePickerProps {
mode?: 'date' | 'month' | 'datetime' | 'time'
value: string
onChange: (value: string) => void
minDate?: string
maxDate?: string
disabled?: boolean
placeholder?: string
required?: boolean
}
export default function AdminDatePicker({
mode = 'date',
value,
onChange,
required,
minDate,
maxDate,
disabled,
placeholder,
}: AdminDatePickerProps) {
const useNative = useMemo(() => isTouchDevice(), [])
if (useNative) {
return (
<NativeInput
mode={mode}
value={value}
onChange={onChange}
required={required}
minDate={minDate}
maxDate={maxDate}
disabled={disabled}
/>
)
}
const toDate = (val: string | null | undefined): Date | null => {
if (!val) return null
try {
if (mode === 'date') return parse(val, 'yyyy-MM-dd', new Date())
if (mode === 'time') {
const [h, m] = val.split(':')
const d = new Date()
d.setHours(parseInt(h, 10), parseInt(m, 10), 0, 0)
return d
}
if (mode === 'month') return parse(val, 'yyyy-MM', new Date())
} catch { return null }
return null
}
const handleChange = (date: Date | null) => {
if (!date) { onChange(''); return }
if (mode === 'date') onChange(format(date, 'yyyy-MM-dd'))
else if (mode === 'time') onChange(format(date, 'HH:mm'))
else if (mode === 'month') onChange(format(date, 'yyyy-MM'))
}
const parseMinMax = (val: string | undefined): Date | undefined => {
if (!val) return undefined
try {
if (mode === 'date') return parse(val, 'yyyy-MM-dd', new Date())
if (mode === 'month') return parse(val, 'yyyy-MM', new Date())
} catch { return undefined }
return undefined
}
const commonProps = {
selected: toDate(value),
onChange: handleChange,
locale: 'cs',
customInput: <CustomInput required={required} placeholder={placeholder} disabled={disabled} />,
minDate: parseMinMax(minDate),
maxDate: parseMinMax(maxDate),
popperPlacement: 'bottom-start' as const,
portalId: 'datepicker-portal',
disabled,
}
if (mode === 'time') {
return (
<DatePicker
{...commonProps}
showTimeSelect
showTimeSelectOnly
timeIntervals={5}
timeCaption="Čas"
dateFormat="HH:mm"
timeFormat="HH:mm"
/>
)
}
if (mode === 'month') {
return (
<DatePicker
{...commonProps}
showMonthYearPicker
dateFormat="MM/yyyy"
/>
)
}
return (
<DatePicker
{...commonProps}
dateFormat="dd.MM.yyyy"
/>
)
}