92 lines
3.6 KiB
TypeScript
92 lines
3.6 KiB
TypeScript
import React from 'react';
|
|
import DatePicker from 'react-multi-date-picker';
|
|
import TimePicker from 'react-multi-date-picker/plugins/time_picker';
|
|
import persian from 'react-date-object/calendars/persian';
|
|
import persian_fa from 'react-date-object/locales/persian_fa';
|
|
import DateObject from 'react-date-object';
|
|
import { Label } from './Typography';
|
|
import { X } from 'lucide-react';
|
|
|
|
interface JalaliDateTimePickerProps {
|
|
label?: string;
|
|
value?: string | null;
|
|
onChange: (value: string | undefined) => void;
|
|
error?: string;
|
|
placeholder?: string;
|
|
}
|
|
|
|
const toIsoLike = (date?: DateObject | null): string | undefined => {
|
|
if (!date) return undefined;
|
|
try {
|
|
const g = date.convert(undefined);
|
|
const yyyy = g.year.toString().padStart(4, '0');
|
|
const mm = g.month.toString().padStart(2, '0');
|
|
const dd = g.day.toString().padStart(2, '0');
|
|
const hh = g.hour.toString().padStart(2, '0');
|
|
const mi = g.minute.toString().padStart(2, '0');
|
|
return `${yyyy}-${mm}-${dd}T${hh}:${mi}:00Z`;
|
|
} catch {
|
|
return undefined;
|
|
}
|
|
};
|
|
|
|
const fromIsoToDateObject = (value?: string | null): DateObject | undefined => {
|
|
if (!value) return undefined;
|
|
try {
|
|
const d = new Date(value);
|
|
if (isNaN(d.getTime())) return undefined;
|
|
return new DateObject(d).convert(persian, persian_fa);
|
|
} catch {
|
|
return undefined;
|
|
}
|
|
};
|
|
|
|
export const JalaliDateTimePicker: React.FC<JalaliDateTimePickerProps> = ({ label, value, onChange, error, placeholder }) => {
|
|
const selected = fromIsoToDateObject(value);
|
|
|
|
return (
|
|
<div className="space-y-1">
|
|
{label && <Label>{label}</Label>}
|
|
<div className="relative">
|
|
<DatePicker
|
|
value={selected}
|
|
onChange={(val) => onChange(toIsoLike(val as DateObject | null))}
|
|
format="YYYY/MM/DD HH:mm"
|
|
calendar={persian}
|
|
locale={persian_fa}
|
|
calendarPosition="bottom-center"
|
|
disableDayPicker={false}
|
|
inputClass={`w-full border rounded-lg px-3 py-3 pr-10 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 focus:outline-none focus:ring-2 ${error ? 'border-red-300 focus:border-red-500 focus:ring-red-500' : 'border-gray-300 dark:border-gray-600 focus:border-primary-500 focus:ring-primary-500'}`}
|
|
containerClassName="w-full"
|
|
placeholder={placeholder || 'تاریخ و ساعت'}
|
|
editable={false}
|
|
plugins={[<TimePicker key="time" position="bottom" />]}
|
|
disableMonthPicker={false}
|
|
disableYearPicker={false}
|
|
showOtherDays
|
|
/>
|
|
{value && (
|
|
<button
|
|
type="button"
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
onChange(undefined);
|
|
}}
|
|
className="absolute left-2 top-1/2 -translate-y-1/2 p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors"
|
|
title="پاک کردن"
|
|
>
|
|
<X className="h-4 w-4" />
|
|
</button>
|
|
)}
|
|
</div>
|
|
{error && (
|
|
<p className="text-xs text-red-600 dark:text-red-400" role="alert">{error}</p>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default JalaliDateTimePicker;
|
|
|
|
|