feat: implement hide app name feature with toggle in admin settings and update branding context
Some checks failed
Build & Push Docker Image / build (push) Has been cancelled
Some checks failed
Build & Push Docker Image / build (push) Has been cancelled
This commit is contained in:
126
src/components/DateTimePicker.jsx
Normal file
126
src/components/DateTimePicker.jsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import ReactDatePicker from 'react-datepicker';
|
||||
import { de } from 'date-fns/locale';
|
||||
import { Calendar as CalendarIcon, Clock, X } from 'lucide-react';
|
||||
import { forwardRef } from 'react';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
|
||||
/**
|
||||
* Custom DateTimePicker that reads the app's CSS variables and
|
||||
* fully matches whatever theme is active.
|
||||
*
|
||||
* Props:
|
||||
* value – ISO datetime string (or '')
|
||||
* onChange – (isoString) => void
|
||||
* label – string
|
||||
* required – bool
|
||||
* minDate – Date | null
|
||||
* icon – 'calendar' (default) | 'clock'
|
||||
*/
|
||||
export default function DateTimePicker({
|
||||
value,
|
||||
onChange,
|
||||
label,
|
||||
required = false,
|
||||
minDate = null,
|
||||
icon = 'calendar',
|
||||
}) {
|
||||
const selected = value ? new Date(value) : null;
|
||||
|
||||
const handleChange = (date) => {
|
||||
if (!date) { onChange(''); return; }
|
||||
// Produce local datetime string yyyy-MM-ddTHH:mm
|
||||
const y = date.getFullYear();
|
||||
const mo = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const d = String(date.getDate()).padStart(2, '0');
|
||||
const h = String(date.getHours()).padStart(2, '0');
|
||||
const mi = String(date.getMinutes()).padStart(2, '0');
|
||||
onChange(`${y}-${mo}-${d}T${h}:${mi}`);
|
||||
};
|
||||
|
||||
const Icon = icon === 'clock' ? Clock : CalendarIcon;
|
||||
|
||||
return (
|
||||
<div className="dtp-wrapper">
|
||||
{label && (
|
||||
<label className="block text-sm font-medium text-th-text mb-1.5">
|
||||
{label}{required && ' *'}
|
||||
</label>
|
||||
)}
|
||||
<div className="dtp-input-wrap">
|
||||
<Icon size={15} className="dtp-icon" />
|
||||
<ReactDatePicker
|
||||
selected={selected}
|
||||
onChange={handleChange}
|
||||
showTimeSelect
|
||||
timeFormat="HH:mm"
|
||||
timeIntervals={15}
|
||||
dateFormat="dd.MM.yyyy HH:mm"
|
||||
locale={de}
|
||||
minDate={minDate}
|
||||
required={required}
|
||||
popperPlacement="bottom-start"
|
||||
popperModifiers={[
|
||||
{ name: 'offset', options: { offset: [0, 4] } },
|
||||
{ name: 'preventOverflow', options: { rootBoundary: 'viewport', tether: false, altAxis: true } },
|
||||
]}
|
||||
customInput={<CustomInput />}
|
||||
calendarClassName="dtp-calendar"
|
||||
dayClassName={(date) => 'dtp-day'}
|
||||
timeClassName={() => 'dtp-time-item'}
|
||||
renderCustomHeader={CalendarHeader}
|
||||
isClearable
|
||||
clearButtonClassName="dtp-clear-btn"
|
||||
wrapperClassName="dtp-dp-wrapper"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ── Custom Input ─────────────────────────────────────────────────────────────
|
||||
const CustomInput = forwardRef(({ value, onClick, onClear, ...rest }, ref) => (
|
||||
<button
|
||||
ref={ref}
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
className="dtp-custom-input"
|
||||
{...rest}
|
||||
>
|
||||
<span className={value ? 'dtp-value' : 'dtp-placeholder'}>
|
||||
{value || 'Datum & Uhrzeit wählen …'}
|
||||
</span>
|
||||
</button>
|
||||
));
|
||||
CustomInput.displayName = 'CustomInput';
|
||||
|
||||
// ── Custom Header ─────────────────────────────────────────────────────────────
|
||||
function CalendarHeader({
|
||||
date,
|
||||
decreaseMonth, increaseMonth,
|
||||
prevMonthButtonDisabled, nextMonthButtonDisabled,
|
||||
}) {
|
||||
const label = date.toLocaleString('de', { month: 'long', year: 'numeric' });
|
||||
return (
|
||||
<div className="dtp-header">
|
||||
<button
|
||||
type="button"
|
||||
onClick={decreaseMonth}
|
||||
disabled={prevMonthButtonDisabled}
|
||||
className="dtp-nav-btn"
|
||||
aria-label="Vorheriger Monat"
|
||||
>
|
||||
‹
|
||||
</button>
|
||||
<span className="dtp-month-label">{label}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={increaseMonth}
|
||||
disabled={nextMonthButtonDisabled}
|
||||
className="dtp-nav-btn"
|
||||
aria-label="Nächster Monat"
|
||||
>
|
||||
›
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user