metms_fe/src/components/page/patient/PopupUpdatePatient/PopupUpdatePatient.tsx
2026-05-31 09:38:10 +07:00

410 lines
11 KiB
TypeScript

"use client";
import React, { useEffect, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { X } from "lucide-react";
import CustomButton from "@/components/customs/custom-button";
import CustomLoading from "@/components/customs/custom-loading";
import FormCustom from "@/components/utils/FormCustom";
import InputForm from "@/components/utils/FormCustom/components/InputForm";
import TextArea from "@/components/utils/FormCustom/components/TextArea";
import { ContextFormCustom } from "@/components/utils/FormCustom/contexts";
import { QUERY_KEY, TYPE_GENDER } from "@/constant/config/enum";
import { httpRequest } from "@/services";
import patientServices, { PatientDetail } from "@/services/patientServices";
import { toastWarn } from "@/common/funcs/toast";
import { timeSubmit } from "@/common/funcs/optionConvert";
interface PopupUpdatePatientProps {
onClose: () => void;
id: string;
}
interface IUpdatePatient {
fullName: string;
gender: string;
phone: string;
email: string;
address: string;
emergencyContactName: string;
emergencyContactPhone: string;
allergyNotes: string;
chronicDiseaseNotes: string;
insuranceNumber: string;
notes: string;
}
const defaultForm: IUpdatePatient = {
fullName: "",
gender: "",
phone: "",
email: "",
address: "",
emergencyContactName: "",
emergencyContactPhone: "",
allergyNotes: "",
chronicDiseaseNotes: "",
insuranceNumber: "",
notes: "",
};
const PopupUpdatePatient = ({ onClose, id }: PopupUpdatePatientProps) => {
const queryClient = useQueryClient();
const [form, setForm] = useState<IUpdatePatient>(defaultForm);
const patientDetailQuery = useQuery<PatientDetail>({
queryKey: [QUERY_KEY.chi_tiet_benh_nhan, id],
enabled: !!id,
queryFn: async () => {
const res = await httpRequest<PatientDetail>({
showMessageFailed: true,
http: patientServices.detailPatient(id),
});
return (
res || {
id: "",
patientCode: "",
identificationNumber: "",
fullName: "",
dateOfBirth: "",
gender: "",
phone: "",
email: "",
address: "",
emergencyContactName: null,
emergencyContactPhone: null,
allergyNotes: null,
chronicDiseaseNotes: null,
insuranceNumber: null,
notes: null,
isActive: false,
}
);
},
});
useEffect(() => {
const patient = patientDetailQuery.data;
if (!patient) return;
setForm((prev) => {
/**
* tránh render loop
*/
if (
prev.fullName === patient.fullName &&
prev.phone === patient.phone &&
prev.email === patient.email
) {
return prev;
}
return {
fullName: patient.fullName || "",
gender: patient.gender || TYPE_GENDER.MALE,
phone: patient.phone || "",
email: patient.email || "",
address: patient.address || "",
emergencyContactName: patient.emergencyContactName || "",
emergencyContactPhone: patient.emergencyContactPhone || "",
allergyNotes: patient.allergyNotes || "",
chronicDiseaseNotes: patient.chronicDiseaseNotes || "",
insuranceNumber: patient.insuranceNumber || "",
notes: patient.notes || "",
};
});
}, [patientDetailQuery.data]);
const updatePatientMutation = useMutation({
mutationFn: async () => {
return httpRequest({
showMessageFailed: true,
showMessageSuccess: true,
msgSuccess: "Cập nhật bệnh nhân thành công!",
http: patientServices.putPatient(id, {
fullName: form.fullName,
gender: form.gender,
phone: form.phone,
email: form.email,
address: form.address,
emergencyContactName: form.emergencyContactName,
emergencyContactPhone: form.emergencyContactPhone,
allergyNotes: form.allergyNotes,
chronicDiseaseNotes: form.chronicDiseaseNotes,
insuranceNumber: form.insuranceNumber,
notes: form.notes,
}),
});
},
onSuccess(data) {
if (!data) return;
queryClient.invalidateQueries({
queryKey: [QUERY_KEY.table_list_patient],
});
queryClient.invalidateQueries({
queryKey: [QUERY_KEY.chi_tiet_benh_nhan, id],
});
onClose();
},
});
const handleSubmit = () => {
if (!form.gender) {
return toastWarn({ msg: "Vui lòng chọn giới tính!" });
}
updatePatientMutation.mutate();
};
if (patientDetailQuery.isLoading) {
return (
<div className="flex h-[400px] items-center justify-center">
<CustomLoading />
</div>
);
}
return (
<FormCustom form={form} setForm={setForm} onSubmit={handleSubmit}>
<div
className="
relative
h-[680px]
w-[640px]
max-w-[95vw]
rounded-3xl
bg-white
shadow-xl
flex
flex-col
overflow-hidden
"
>
{/* CLOSE */}
<button
type="button"
onClick={onClose}
className="
absolute
right-5
top-5
z-10
text-gray-400
transition
hover:text-gray-600
"
>
<X size={22} />
</button>
{/* HEADER */}
<div
className="
shrink-0
border-b
px-7
py-5
bg-white
"
>
<h2 className="text-[30px] font-semibold text-[#111827]">
Cập nhật thông tin bệnh nhân
</h2>
</div>
{/* BODY */}
<div
className="
flex-1
overflow-y-auto
px-7
py-5
"
>
<div className="space-y-5">
<InputForm
label={
<span>
Tên bệnh nhân
<span className="text-red-500"> *</span>
</span>
}
placeholder="Tên bệnh nhân"
name="fullName"
type="text"
value={form.fullName}
isRequired
/>
{/* GENDER */}
<div>
<label className="text-base font-medium">Giới tính</label>
<div className="mt-2 flex items-center gap-6">
{/* NAM */}
<div className="flex items-center gap-2">
<input
type="radio"
id="male"
checked={form.gender === TYPE_GENDER.MALE}
onChange={() =>
setForm((prev) => ({
...prev,
gender: TYPE_GENDER.MALE,
}))
}
/>
<label htmlFor="male">Nam</label>
</div>
{/* NỮ */}
<div className="flex items-center gap-2">
<input
type="radio"
id="female"
checked={form.gender === TYPE_GENDER.FEMALE}
onChange={() =>
setForm((prev) => ({
...prev,
gender: TYPE_GENDER.FEMALE,
}))
}
/>
<label htmlFor="female">Nữ</label>
</div>
</div>
</div>
<InputForm
label={
<span>
Số điện thoại
<span className="text-red-500"> *</span>
</span>
}
placeholder="Số điện thoại"
name="phone"
type="phone"
isPhone
value={form.phone}
isRequired
/>
<InputForm
label={<span>Email</span>}
placeholder="Email"
name="email"
type="email"
isEmail
value={form.email}
/>
<TextArea
name="address"
placeholder="Địa chỉ"
label="Địa chỉ"
value={form.address}
isRequired
isBlur
max={5000}
/>
<InputForm
isRequired
label="Người liên hệ khẩn cấp"
placeholder="Người liên hệ khẩn cấp"
name="emergencyContactName"
type="text"
value={form.emergencyContactName}
/>
<InputForm
label="SĐT khẩn cấp"
placeholder="SĐT khẩn cấp"
name="emergencyContactPhone"
type="phone"
isRequired
isPhone
value={form.emergencyContactPhone}
/>
<TextArea
name="allergyNotes"
placeholder="Dị ứng"
label="Dị ứng"
value={form.allergyNotes}
isBlur
max={5000}
/>
<TextArea
name="chronicDiseaseNotes"
placeholder="Bệnh nền"
label="Bệnh nền"
value={form.chronicDiseaseNotes}
isBlur
max={5000}
/>
<InputForm
label="Số bảo hiểm"
placeholder="Số bảo hiểm"
name="insuranceNumber"
type="text"
isRequired
value={form.insuranceNumber}
/>
<TextArea
name="notes"
placeholder="Ghi chú"
label="Ghi chú"
value={form.notes}
isBlur
max={5000}
/>
</div>
</div>
{/* FOOTER */}
<div
className="
shrink-0
border-t
bg-white
px-7
py-5
flex
items-center
justify-end
gap-3
"
>
<CustomButton variant="grey" rounded="md" onClick={onClose}>
Hủy bỏ
</CustomButton>
<ContextFormCustom.Consumer>
{({ isDone }) => (
<CustomButton
disabled={!isDone || updatePatientMutation.isPending}
variant="midnightBlue"
rounded="md"
type="submit"
>
{updatePatientMutation.isPending
? "Đang cập nhật..."
: "Cập nhật"}
</CustomButton>
)}
</ContextFormCustom.Consumer>
</div>
</div>
</FormCustom>
);
};
export default PopupUpdatePatient;