78 lines
2.1 KiB
TypeScript
78 lines
2.1 KiB
TypeScript
import { format, isSameDay } from 'date-fns';
|
|
import { useState } from 'react';
|
|
import { DatePicker } from '@/components/date-picker';
|
|
import InputError from '@/components/input-error';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
|
|
type DateTimeFieldProps = {
|
|
label: string;
|
|
name: string;
|
|
required?: boolean;
|
|
defaultValue?: string | null;
|
|
error?: string;
|
|
placeholder?: string;
|
|
maxNow?: boolean;
|
|
};
|
|
|
|
function parseDefault(value?: string | null): Date | undefined {
|
|
if (!value) {
|
|
return undefined;
|
|
}
|
|
|
|
const date = new Date(value);
|
|
|
|
return Number.isNaN(date.getTime()) ? undefined : date;
|
|
}
|
|
|
|
export function DateTimeField({
|
|
label,
|
|
name,
|
|
required,
|
|
defaultValue,
|
|
error,
|
|
placeholder = 'Pilih tanggal',
|
|
maxNow,
|
|
}: DateTimeFieldProps) {
|
|
const initial = parseDefault(defaultValue);
|
|
const [date, setDate] = useState<Date | undefined>(initial);
|
|
const [time, setTime] = useState(initial ? format(initial, 'HH:mm') : '');
|
|
|
|
const combined = date
|
|
? `${format(date, 'yyyy-MM-dd')} ${time || '00:00'}:00`
|
|
: '';
|
|
|
|
const now = new Date();
|
|
const maxTime =
|
|
maxNow && date && isSameDay(date, now)
|
|
? format(now, 'HH:mm')
|
|
: undefined;
|
|
|
|
return (
|
|
<div className="grid gap-2">
|
|
<Label>
|
|
{label}{' '}
|
|
{required && <span className="text-destructive">*</span>}
|
|
</Label>
|
|
<input type="hidden" name={name} value={combined} />
|
|
<div className="flex gap-2">
|
|
<DatePicker
|
|
value={date}
|
|
onChange={setDate}
|
|
placeholder={placeholder}
|
|
className="flex-1"
|
|
maxDate={maxNow ? now : undefined}
|
|
/>
|
|
<Input
|
|
type="time"
|
|
value={time}
|
|
onChange={(e) => setTime(e.target.value)}
|
|
max={maxTime}
|
|
className="w-28"
|
|
/>
|
|
</div>
|
|
<InputError message={error} />
|
|
</div>
|
|
);
|
|
}
|