Files
dyolink/frontend/src/components/ui/patient/CreatePatientModal.tsx

152 lines
3.8 KiB
TypeScript

'use client';
import { useTranslations } from 'next-intl';
import { Button } from '@/components/ui/shared/Button';
import { DialogCloseButton } from '@/components/ui/shared/DialogCloseButton';
import { Input } from '@/components/ui/shared/Input';
import { CreatePatientInput } from '@/types/patient';
interface CreatePatientModalProps {
isOpen: boolean;
formData: CreatePatientInput;
onChange: (patch: Partial<CreatePatientInput>) => void;
onSubmit: () => void;
onClose: () => void;
loading?: boolean;
/** Inline panel on Patients page; centered dialog on Appointments. */
variant?: 'inline' | 'dialog';
}
function CreatePatientFormFields({
formData,
onChange,
onSubmit,
onClose,
loading,
showCancel,
}: {
formData: CreatePatientInput;
onChange: (patch: Partial<CreatePatientInput>) => void;
onSubmit: () => void;
onClose: () => void;
loading: boolean;
showCancel: boolean;
}) {
const t = useTranslations('patients');
const tCommon = useTranslations('common');
return (
<>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<Input
label={t('firstName')}
value={formData.firstName || ''}
onChange={(e) => onChange({ firstName: e.target.value })}
/>
<Input
label={t('lastName')}
value={formData.lastName || ''}
onChange={(e) => onChange({ lastName: e.target.value })}
/>
<Input
label={t('phone')}
value={formData.phone || ''}
onChange={(e) => onChange({ phone: e.target.value })}
/>
<Input
label={tCommon('email')}
type="email"
value={formData.email || ''}
onChange={(e) => onChange({ email: e.target.value })}
/>
</div>
<div className="flex gap-2">
<Button
variant="primary"
onClick={onSubmit}
isLoading={loading}
disabled={!formData.firstName || !formData.lastName}
>
{t('savePatient')}
</Button>
{showCancel && (
<Button variant="ghost" onClick={onClose}>
{tCommon('cancel')}
</Button>
)}
</div>
</>
);
}
export function CreatePatientModal({
isOpen,
formData,
onChange,
onSubmit,
onClose,
loading = false,
variant = 'inline',
}: CreatePatientModalProps) {
const t = useTranslations('patients');
if (!isOpen) {
return null;
}
if (variant === 'dialog') {
return (
<div
className="fixed inset-0 z-[60] flex items-center justify-center p-4 bg-black/55"
role="presentation"
onMouseDown={(e) => {
if (e.target === e.currentTarget) {
onClose();
}
}}
>
<div
className="surface-card w-full max-w-[min(56rem,calc(100vw-15rem))] p-5 space-y-4 shadow-xl"
role="dialog"
aria-modal="true"
aria-labelledby="create-patient-dialog-title"
onMouseDown={(e) => e.stopPropagation()}
>
<div className="flex items-start justify-between gap-2">
<h2
id="create-patient-dialog-title"
className="text-lg font-semibold text-text-primary pr-2"
>
{t('dialogTitle')}
</h2>
<DialogCloseButton onClick={onClose} />
</div>
<CreatePatientFormFields
formData={formData}
onChange={onChange}
onSubmit={onSubmit}
onClose={onClose}
loading={loading}
showCancel={false}
/>
</div>
</div>
);
}
return (
<div className="surface-card p-4 space-y-3">
<CreatePatientFormFields
formData={formData}
onChange={onChange}
onSubmit={onSubmit}
onClose={onClose}
loading={loading}
showCancel
/>
</div>
);
}