- Implemented InviteDoctorModal component for inviting doctors to clinics. - Updated ClinicDashboard to include a button for inviting doctors and handle modal state. - Added createAppointment API endpoint in AdminApiController for scheduling appointments. - Enhanced ClinicInvitationController to check user access when inviting doctors. - Updated MyAppointmentsController to ensure unique appointment records. - Added seed_test_data.php for populating test data including doctors, clinics, and appointments. - Refactored styles to include new appointment status badges and updated font imports.
70 lines
2.2 KiB
TypeScript
70 lines
2.2 KiB
TypeScript
import React, { useRef } from 'react';
|
|
import { CalendarDaysIcon, XMarkIcon } from '@heroicons/react/24/outline';
|
|
import { formatDate } from '../../lib/utils';
|
|
|
|
interface Props {
|
|
value: string;
|
|
onChange: (v: string) => void;
|
|
placeholder?: string;
|
|
min?: string;
|
|
max?: string;
|
|
style?: React.CSSProperties;
|
|
className?: string;
|
|
}
|
|
|
|
export default function PersianDateInput({ value, onChange, placeholder = 'انتخاب تاریخ', min, max, style, className }: Props) {
|
|
const hiddenRef = useRef<HTMLInputElement>(null);
|
|
|
|
const open = () => {
|
|
const el = hiddenRef.current;
|
|
if (!el) return;
|
|
if (typeof el.showPicker === 'function') {
|
|
try { el.showPicker(); } catch { el.focus(); }
|
|
} else {
|
|
el.focus();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div style={{ position: 'relative', display: 'inline-flex', alignItems: 'center', ...style }} className={className}>
|
|
{/* visible text layer */}
|
|
<div
|
|
onClick={open}
|
|
style={{
|
|
display: 'flex', alignItems: 'center', gap: 7,
|
|
height: 36, padding: '0 10px', borderRadius: 'var(--r-sm)',
|
|
border: '1px solid var(--border)', background: 'var(--surface)',
|
|
cursor: 'pointer', fontSize: 13, color: value ? 'var(--text)' : 'var(--text-3)',
|
|
userSelect: 'none', minWidth: 148, whiteSpace: 'nowrap',
|
|
}}
|
|
>
|
|
<CalendarDaysIcon style={{ width: 15, height: 15, color: 'var(--text-3)', flexShrink: 0 }} />
|
|
<span style={{ flex: 1 }}>{value ? formatDate(value) : placeholder}</span>
|
|
{value && (
|
|
<span
|
|
onClick={e => { e.stopPropagation(); onChange(''); }}
|
|
style={{ display: 'flex', alignItems: 'center', cursor: 'pointer', color: 'var(--text-3)' }}
|
|
>
|
|
<XMarkIcon style={{ width: 13, height: 13 }} />
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
{/* hidden native input — opens picker on click */}
|
|
<input
|
|
ref={hiddenRef}
|
|
type="date"
|
|
value={value}
|
|
min={min}
|
|
max={max}
|
|
onChange={e => onChange(e.target.value)}
|
|
style={{
|
|
position: 'absolute', opacity: 0, pointerEvents: 'none',
|
|
width: 1, height: 1, top: 0, left: 0,
|
|
}}
|
|
tabIndex={-1}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|