410 lines
11 KiB
TypeScript
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;
|