feat:update all page

This commit is contained in:
TuanVT 2026-05-26 16:43:42 +07:00
parent bce004352c
commit 56e2733d8f
18 changed files with 480 additions and 262 deletions

View File

@ -4,6 +4,16 @@ const nextConfig: NextConfig = {
turbopack: {
root: process.cwd(),
},
images: {
remotePatterns: [
{
protocol: "http",
hostname: "127.0.0.1",
port: "5264",
pathname: "/uploads/**",
},
],
},
};
export default nextConfig;

View File

@ -0,0 +1,14 @@
"use client";
import BaseLayout from "@/components/layouts/BaseLayout";
import TableHistoryPatient from "@/components/page/consultation/TableHistoryPatient";
import React from "react";
const page = () => {
return (
<BaseLayout title="Lịch sử các phiên khám">
<TableHistoryPatient />
</BaseLayout>
);
};
export default page;

View File

@ -63,6 +63,19 @@ export default function fancyTimeFormat(duration: number) {
return ret;
}
export function checkTime(i: any) {
if (Math.abs(i) < 10) {
i = "0" + i;
}
return i;
}
export const timeSubmit = (date: Date | null | undefined, isTo?: boolean) => {
return date
? `${date.getFullYear()}-${checkTime(date.getMonth() + 1)}-${checkTime(date.getDate())}T${isTo ? "23:59:59" : "00:00:00"}`
: null;
};
export function getKeyCert(): {
time: string;
keyCert: string;

View File

@ -11,6 +11,16 @@ export const ContextBaseLayout = React.createContext<TContextBaseLayout>({});
const BaseLayout = ({ children, title, breadcrumb }: PropsBaseLayout) => {
const [showFull, setShowFull] = React.useState(false);
const [openMenuMobile, setOpenMenuMobile] = React.useState(false);
// Khi mount trên client, mở sidebar mặc định nếu là màn hình desktop (xl)
// React.useEffect(() => {
// try {
// if (window?.innerWidth >= 1280) {
// setShowFull(true);
// }
// } catch (e) {
// // ignore
// }
// }, []);
return (
<RequireAuth>
<ContextBaseLayout

View File

@ -51,7 +51,7 @@ const MenuProfile = ({ onClose }: PropsMenuProfile) => {
return (
<div className="w-[260px] bg-white rounded-xl shadow-md p-2">
{/* PROFILE */}
<Link
{/* <Link
href={PATH.PROFILE}
onClick={onClose}
className={clsx(
@ -65,10 +65,10 @@ const MenuProfile = ({ onClose }: PropsMenuProfile) => {
<p className="text-xs text-gray-500">Chi tiết tài khoản</p>
</div>
</Link>
<div className="h-px bg-gray-200 my-1" />
<div className="h-px bg-gray-200 my-1" /> */}
{/* CHANGE PASSWORD */}
<Link
{/* <Link
href={`${PATH.PROFILE}?_action=change-password`}
onClick={onClose}
className={clsx(
@ -84,7 +84,7 @@ const MenuProfile = ({ onClose }: PropsMenuProfile) => {
<p className="text-xs text-gray-500">Thay đi mật khẩu</p>
</div>
</Link>
<div className="h-px bg-gray-200 my-1" />
<div className="h-px bg-gray-200 my-1" /> */}
{/* LOGOUT */}
<div

View File

@ -25,6 +25,7 @@ import CustomButton from "@/components/customs/custom-button";
import { useRouter } from "next/navigation";
import InputForm from "@/components/utils/FormCustom/components/InputForm";
import GridColumn from "@/components/layouts/GridColumn";
import { toastWarn } from "@/common/funcs/toast";
const CreateConsultation = () => {
const router = useRouter();
@ -111,6 +112,9 @@ const CreateConsultation = () => {
});
const handleSubmit = () => {
if (!form?.patientId) {
return toastWarn({ msg: "Vui lòng chọn bệnh nhân" });
}
createConsultationMutation.mutate();
};
@ -118,14 +122,14 @@ const CreateConsultation = () => {
<FormCustom form={form} setForm={setForm} onSubmit={handleSubmit}>
<div
className="
relative
max-w-[95vw]
rounded-3xl
h-[485px]
border
rounded-lg
bg-white
shadow-xl
flex
flex-col
overflow-hidden
"
>
<div className="flex items-center justify-between">
@ -139,9 +143,46 @@ const CreateConsultation = () => {
"
>
<h2 className="text-[30px] font-semibold text-[#111827]">
Thêm phiên khám
Tạo phiên khám
</h2>
</div>
</div>
{/* BODY */}
<div className="flex-1 px-7 py-5">
<div className="space-y-5 mb-2">
<SelectForm
label={
<span className="text-[14px] font-medium text-[#374151]">
Bệnh nhân
<span className="text-red-500">*</span>
</span>
}
placeholder="Chọn bệnh nhân"
value={form.patientId}
options={patientOptions}
// loading={patientQuery.isLoading}
onSelect={(item: PatientItem) =>
setForm((prev) => ({
...prev,
patientId: item.id,
}))
}
onClean={() =>
setForm((prev) => ({
...prev,
patientId: "",
}))
}
getOptionLabel={(item: PatientItem) =>
`${item.fullName} - ${item.identificationNumber}`
}
getOptionValue={(item: PatientItem) => item.id}
/>
</div>
</div>
{/* FOOTER */}
<div
className="
shrink-0
@ -176,8 +217,6 @@ const CreateConsultation = () => {
}
variant="midnightBlue"
rounded="md"
fullWidth={false}
className="min-w-[180px] "
onClick={handleSubmit}
>
{createConsultationMutation.isPending
@ -186,97 +225,6 @@ const CreateConsultation = () => {
</CustomButton>
</div>
</div>
{/* BODY */}
<div className="flex-1 overflow-y-auto px-7 py-5">
<div className="space-y-5 mb-2">
<SelectForm
label={
<span className="text-[14px] font-medium text-[#374151]">
Bệnh nhân
<span className="text-red-500">*</span>
</span>
}
placeholder="Chọn bệnh nhân"
value={form.patientId}
options={patientOptions}
// loading={patientQuery.isLoading}
onSelect={(item: PatientItem) =>
setForm((prev) => ({
...prev,
patientId: item.id,
}))
}
onClean={() =>
setForm((prev) => ({
...prev,
patientId: "",
}))
}
getOptionLabel={(item: PatientItem) =>
`${item.fullName} - ${item.identificationNumber}`
}
getOptionValue={(item: PatientItem) => item.id}
/>
</div>
{/* <GridColumn col={3}>
<InputForm
label="Lý do khám"
name="chiefComplaint"
type="text"
value={form.chiefComplaint}
placeholder="Nhập lý do khám"
isRequired
/>
<InputForm
type="text"
label="Triệu chứng"
name="symptomsText"
placeholder="Nhập triệu chứng"
isRequired
value={form.symptomsText}
/>
<InputForm
type="text"
label="Nhiệt độ cơ thể"
name="vitalSigns"
placeholder="Nhập nhiệt độ cơ thể"
value={form.vitalSigns}
isRequired
/>
<InputForm
type="text"
label="Chẩn đoán"
name="diagnosis"
placeholder="Nhập chẩn đoán"
value={form.diagnosis}
isRequired
/>
<InputForm
type="text"
label="Kế hoạch điều trị"
name="treatmentPlan"
placeholder="Nhập kế hoạch điều trị"
value={form.treatmentPlan}
isRequired
/>
<InputForm
type="text"
label="Ghi chú bác sĩ"
name="doctorNotes"
placeholder="Nhập ghi chú"
value={form.doctorNotes}
isRequired
/>
</GridColumn> */}
</div>
{/* FOOTER */}
</div>
</FormCustom>
);
};

View File

@ -272,20 +272,6 @@ const MainPageConsultation = () => {
rowKey={(item) => item.id}
data={consultationData}
column={[
{
fixedLeft: true,
title: "ID PHIÊN KHÁM",
render: (item: ConsultationItem) => (
<Link
href={`/consultation/${item.id}`}
className="text-blue-500 hover:underline"
>
{item.id}
</Link>
),
},
{
title: "TÊN BỆNH NHÂN",
@ -296,9 +282,14 @@ const MainPageConsultation = () => {
{
title: "MÃ PHIÊN KHÁM",
fixedLeft: true,
render: (item: ConsultationItem) => (
<span>{item.sessionCode}</span>
<Link
href={`/consultation/${item.id}`}
className="text-blue-500 hover:underline"
>
{item.sessionCode}
</Link>
),
},

View File

@ -0,0 +1,196 @@
"use client";
import React from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useQuery } from "@tanstack/react-query";
import Link from "next/link";
import consultationServices, {
ConsultationItem,
ConsultationResponse,
} from "@/services/consultationServices";
import { httpRequest } from "@/services";
import { QUERY_KEY, TYPE_STATUS } from "@/constant/config/enum";
import DataWrapper from "@/components/customs/DataWrapper";
import Table from "@/components/customs/custom-table";
import StateActive from "@/components/customs/StateActive";
import Pagination from "@/components/customs/custom-pagination";
import Search from "@/components/customs/custom-search";
const TableHistoryPatient = () => {
const searchParams = useSearchParams();
const router = useRouter();
const pathname = usePathname();
const patientId = searchParams.get("_id");
const consultationQuery = useQuery<ConsultationResponse>({
queryKey: [QUERY_KEY.table_list_consultation, patientId, "full-history"],
enabled: !!patientId,
queryFn: async () => {
const res = await httpRequest<ConsultationResponse>({
showMessageFailed: true,
http: consultationServices.getConsultations({
Page: 1,
PageSize: 1000,
PatientId: patientId || "",
}),
});
return (
res || {
items: [],
page: 1,
pageSize: 10,
total: 0,
totalPages: 0,
}
);
},
});
const _page = searchParams.get("_page");
const _pageSize = searchParams.get("_pageSize");
const _keyword = searchParams.get("_keyword");
const page = _page ? Number(_page) : 1;
const pageSize = _pageSize ? Number(_pageSize) : 10;
const updateQuery = (key: string, value: string | number) => {
const params = new URLSearchParams(searchParams.toString());
if (!value || value === "" || (key === "_page" && value === 1)) {
params.delete(key);
} else {
params.set(key, String(value));
}
if (key === "_pageSize") {
params.delete("_page");
}
const queryString = params.toString();
router.push(queryString ? `?${queryString}` : pathname);
};
const data = consultationQuery.data?.items || [];
// lấy tên bệnh nhân từ record đầu tiên (nếu backend có trả)
const patientName = data?.[0]?.patientName || "Bệnh nhân";
return (
<div className="rounded-2xl border border-gray-200 bg-white p-6 shadow-sm">
<div className="flex items-center justify-between mb-4">
<h2 className="text-xl font-semibold">
Lịch sử phiên khám của {patientName}
</h2>
<button
onClick={() => router.back()}
className="text-blue-500 hover:underline"
>
Quay lại
</button>
</div>
<div className="flex items-center justify-between gap-4">
<div className="w-full md:min-w-[400px]">
<Search
keyword={_keyword ?? ""}
setKeyword={(value) => updateQuery("_keyword", value)}
placeholder="Tìm kiếm phiên khám..."
/>
</div>
</div>
<DataWrapper
data={data}
loading={consultationQuery.isLoading}
title="Không có dữ liệu"
note="Bệnh nhân chưa có lịch sử khám"
>
<Table
rowKey={(item: ConsultationItem) => item.id}
data={data}
column={[
{
title: "MÃ PHIÊN KHÁM",
render: (item: ConsultationItem) => (
<Link
href={`/consultation/${item.id}`}
className="text-blue-500 hover:underline"
>
{item.sessionCode}
</Link>
),
},
{
title: "NGÀY KHÁM",
render: (item: ConsultationItem) => <span>{item.visitDate}</span>,
},
{
title: "DẤU HIỆU",
render: (item: ConsultationItem) => (
<span>{item.symptomsText || "---"}</span>
),
},
{
title: "CHẨN ĐOÁN",
render: (item: ConsultationItem) => (
<span>{item.diagnosis || "---"}</span>
),
},
{
title: "TRẠNG THÁI",
render: (item: ConsultationItem) => (
<StateActive
stateActive={item.status}
listState={[
{
state: TYPE_STATUS.Draft,
text: "Đang chờ",
textColor: "#000",
backgroundColor: "#FFE4C4",
},
{
state: TYPE_STATUS.InProgress,
text: "Đang thực hiện",
textColor: "#000",
backgroundColor: "#ff3300",
},
{
state: TYPE_STATUS.Completed,
text: "Hoàn thành",
textColor: "#000",
backgroundColor: "#3d69eb",
},
{
state: TYPE_STATUS.Cancelled,
text: "Đã hủy",
textColor: "#000",
backgroundColor: "#cccccc",
},
]}
/>
),
},
]}
/>
</DataWrapper>
<Pagination
total={data.length}
page={page}
pageSize={pageSize}
onSetPage={(value) => updateQuery("_page", value)}
onSetPageSize={(value) => updateQuery("_pageSize", value)}
dependencies={[_pageSize, _keyword]}
/>
</div>
);
};
export default TableHistoryPatient;

View File

@ -0,0 +1 @@
export { default } from "./TableHistoryPatient";

View File

@ -174,34 +174,12 @@ const UpdateConsultation = () => {
<div className="flex items-center justify-between border-b pb-5">
<div>
<h2 className="text-[28px] font-semibold text-[#111827]">
Chỉnh sửa phiên khám
Phiên khám
</h2>
<p className="mt-1 text-sm text-[#697586]">
Cập nhật thông tin chi tiết quá trình khám bệnh
</p>
</div>
<div className="flex items-center gap-3">
<CustomButton
type="button"
variant="grey"
rounded="md"
onClick={() => router.back()}
className="min-w-[120px]"
>
Hủy bỏ
</CustomButton>
<CustomButton
type="submit"
variant="midnightBlue"
rounded="md"
disabled={isLoading || !id || id === "undefined"}
className="min-w-[140px]"
>
{updateConsultationMutation.isPending
? "Đang cập nhật..."
: "Cập nhật"}
</CustomButton>
</div>
</div>
{/* GENERAL INFO (PATIENT) */}
@ -251,9 +229,9 @@ const UpdateConsultation = () => {
<InputForm
type="text"
label="Nhiệt độ cơ thể"
label="Chỉ số huyết áp, chỉ số mạch"
name="vitalSigns"
placeholder="Nhập nhiệt độ cơ thể"
placeholder="Nhập chỉ số huyết áp, chỉ số mạch"
value={form.vitalSigns}
isRequired
onChangeValue={(v) =>
@ -297,6 +275,28 @@ const UpdateConsultation = () => {
}
/>
</GridColumn>
<div className="flex items-center gap-3">
<CustomButton
type="button"
variant="grey"
rounded="md"
onClick={() => router.back()}
className="min-w-[120px]"
>
Hủy bỏ
</CustomButton>
<CustomButton
type="submit"
variant="midnightBlue"
rounded="md"
disabled={isLoading || !id || id === "undefined"}
className="min-w-[140px]"
>
{updateConsultationMutation.isPending
? "Đang cập nhật..."
: "Cập nhật"}
</CustomButton>
</div>
</div>
</FormCustom>
);

View File

@ -119,9 +119,8 @@ const DetailPatient = () => {
queryKey: [QUERY_KEY.table_list_consultation, patientId],
});
// Nếu API trả về thông tin phiên khám vừa tạo (có chứa id), chuyển thẳng tới trang update
if (res?.id) {
router.push(`${PATH.CONSULTATION}/update/${res.id}`);
router.push(`${PATH.CONSULTATION}/${res.id}`); // detail
}
},
});
@ -293,7 +292,7 @@ const DetailPatient = () => {
Lịch sử phiên khám
</h2>
<Link
href={`/consultation`}
href={`/consultation/history?_id=${patientId}`}
className="text-blue-500 hover:underline"
>
Tất cả
@ -310,23 +309,17 @@ const DetailPatient = () => {
data={consultationData}
column={[
{
title: "MÃ PHIÊN KHÁM",
fixedLeft: true,
title: "ID PHIÊN KHÁM",
render: (item: ConsultationItem) => (
<Link
href={`/consultation/${item.id}`}
className="text-blue-500 hover:underline"
>
{item.id}
{item.sessionCode}
</Link>
),
},
{
title: "MÃ PHIÊN KHÁM",
render: (item: ConsultationItem) => (
<span>{item.sessionCode}</span>
),
},
{
title: "NGÀY KHÁM",
render: (item: ConsultationItem) => (

View File

@ -14,6 +14,8 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
import { httpRequest } from "@/services";
import patientServices from "@/services/patientServices";
import { toastWarn } from "@/common/funcs/toast";
import { timeSubmit } from "@/common/funcs/optionConvert";
export interface ICreatePatient {
identificationNumber: string;
@ -77,6 +79,16 @@ const PopupCreatePatient = ({ onClose }: PropsPopupCreatePatient) => {
});
const handleSubmit = () => {
if (!form.gender) {
return toastWarn({ msg: "Vui lòng chọn giới tính!" });
}
const today = new Date(timeSubmit(new Date())!);
const birthDay = new Date(form.dateOfBirth);
if (today < birthDay) {
return toastWarn({ msg: "Ngày sinh không hợp lệ!" });
}
createPatientMutation.mutate();
};
@ -241,29 +253,31 @@ const PopupCreatePatient = ({ onClose }: PropsPopupCreatePatient) => {
}
placeholder="Số điện thoại"
name="phone"
type="text"
type="phone"
isPhone
value={form.phone}
isRequired
/>
<InputForm
label={
<span>
Email
<span className="text-red-500"> *</span>
</span>
}
label={<span>Email</span>}
placeholder="Email"
name="email"
type="text"
type="email"
isEmail
value={form.email}
isRequired
/>
<TextArea
name="address"
placeholder="Địa chỉ"
label="Địa chỉ"
label={
<span>
Đa chỉ
<span className="text-red-500"> *</span>
</span>
}
isRequired
isBlur
max={5000}
/>

View File

@ -12,6 +12,8 @@ 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;
@ -147,6 +149,10 @@ const PopupUpdatePatient = ({ onClose, id }: PopupUpdatePatientProps) => {
});
const handleSubmit = () => {
if (!form.gender) {
return toastWarn({ msg: "Vui lòng chọn giới tính!" });
}
updatePatientMutation.mutate();
};
@ -268,23 +274,6 @@ const PopupUpdatePatient = ({ onClose, id }: PopupUpdatePatientProps) => {
<label htmlFor="female">Nữ</label>
</div>
{/* KHÁC */}
<div className="flex items-center gap-2">
<input
type="radio"
id="other"
checked={form.gender === TYPE_GENDER.OTHER}
onChange={() =>
setForm((prev) => ({
...prev,
gender: TYPE_GENDER.OTHER,
}))
}
/>
<label htmlFor="other">Khác</label>
</div>
</div>
</div>
@ -297,23 +286,19 @@ const PopupUpdatePatient = ({ onClose, id }: PopupUpdatePatientProps) => {
}
placeholder="Số điện thoại"
name="phone"
type="text"
type="number"
isPhone
value={form.phone}
isRequired
/>
<InputForm
label={
<span>
Email
<span className="text-red-500"> *</span>
</span>
}
label={<span>Email</span>}
placeholder="Email"
name="email"
type="text"
type="email"
isEmail
value={form.email}
isRequired
/>
<TextArea
@ -321,11 +306,13 @@ const PopupUpdatePatient = ({ onClose, id }: PopupUpdatePatientProps) => {
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"
@ -337,7 +324,9 @@ const PopupUpdatePatient = ({ onClose, id }: PopupUpdatePatientProps) => {
label="SĐT khẩn cấp"
placeholder="SĐT khẩn cấp"
name="emergencyContactPhone"
type="text"
type="number"
isRequired
isPhone
value={form.emergencyContactPhone}
/>
@ -364,6 +353,7 @@ const PopupUpdatePatient = ({ onClose, id }: PopupUpdatePatientProps) => {
placeholder="Số bảo hiểm"
name="insuranceNumber"
type="text"
isRequired
value={form.insuranceNumber}
/>

View File

@ -29,7 +29,7 @@ import consultationServices, {
ConsultationResponse,
} from "@/services/consultationServices";
import { QUERY_KEY } from "@/constant/config/enum";
import { QUERY_KEY, TYPE_STATUS } from "@/constant/config/enum";
import { toastWarn } from "@/common/funcs/toast";
@ -111,7 +111,12 @@ const CreatePrescription = () => {
},
});
const examinationSessionOptions = examinationSessionQuery.data?.items || [];
const examinationSessionOptions =
examinationSessionQuery.data?.items?.filter(
(item) =>
item.status === TYPE_STATUS.Draft ||
item.status === TYPE_STATUS.InProgress,
) || [];
/* =========================
CREATE MUTATION
@ -119,11 +124,17 @@ const CreatePrescription = () => {
const createPrescriptionMutation = useMutation({
mutationFn: async () => {
/**
* CREATE FORMDATA
*/
const formData = new FormData();
formData.append("examinationSessionId", form.examinationSessionId);
/**
* BASIC INFO
*/
formData.append("ExaminationSessionId", form.examinationSessionId);
formData.append("notes", form.notes);
formData.append("Notes", form.notes);
/**
* FILE
@ -133,22 +144,17 @@ const CreatePrescription = () => {
}
/**
* MEDICINE ITEMS
* ITEMS
* BACKEND EXPECT:
* Items = JSON.stringify([...])
*/
form.items
.filter((x) => x.medicineName.trim() !== "")
.forEach((item, index) => {
formData.append(`items[${index}].medicineName`, item.medicineName);
const validItems = form.items.filter((x) => x.medicineName.trim() !== "");
formData.append(`items[${index}].dosage`, item.dosage);
formData.append(`items[${index}].frequency`, item.frequency);
formData.append(`items[${index}].duration`, item.duration);
formData.append(`items[${index}].instructions`, item.instructions);
});
formData.append("Items", JSON.stringify(validItems));
/**
* API
*/
return await httpRequest({
showMessageFailed: true,
@ -237,6 +243,10 @@ const CreatePrescription = () => {
========================= */
const handleSubmit = () => {
/**
* VALIDATE
*/
if (!form.examinationSessionId) {
return toastWarn({
msg: "Vui lòng chọn phiên khám",
@ -249,6 +259,17 @@ const CreatePrescription = () => {
});
}
const validMedicine = form.items.some((x) => x.medicineName.trim() !== "");
if (!validMedicine) {
return toastWarn({
msg: "Vui lòng nhập ít nhất 1 loại thuốc",
});
}
/**
* MUTATE
*/
createPrescriptionMutation.mutate();
};

View File

@ -6,12 +6,15 @@ import prescriptionServices, {
PrescriptionDetail,
} from "@/services/prescriptionServices";
import { useQuery } from "@tanstack/react-query";
import Image from "next/image";
import { useParams } from "next/navigation";
import React from "react";
import React, { useState } from "react";
import CustomPopup from "@/components/customs/custom-popup";
const DetailPrescription = () => {
const params = useParams();
const PrescriptionId = params?.id as string;
const [openImagePreview, setOpenImagePreview] = useState(false);
const prescriptionDetailQuery = useQuery<PrescriptionDetail>({
queryKey: [QUERY_KEY.chi_tiet_don_thuoc, PrescriptionId],
@ -61,7 +64,7 @@ const DetailPrescription = () => {
</div>
<div>
<strong>Phiên khám:</strong> {data.examinationSessionId}
<strong>Id phiên khám:</strong> {data.examinationSessionId}
</div>
<div>
@ -73,11 +76,34 @@ const DetailPrescription = () => {
<strong>nh đơn thuốc:</strong>
<div className="mt-2">
{data.prescriptionImg ? (
<img
src={data.prescriptionImg}
<>
<Image
src={`${process.env.NEXT_PUBLIC_IMAGE}${data.prescriptionImg}`}
alt="prescription"
className="h-32 w-32 object-cover rounded"
width={140}
height={140}
className="h-10 w-10 rounded object-cover cursor-pointer hover:opacity-80 transition-opacity"
onClick={() => setOpenImagePreview(true)}
unoptimized
/>
{/* IMAGE PREVIEW POPUP */}
<CustomPopup
open={openImagePreview}
onClose={() => setOpenImagePreview(false)}
>
<div className="relative rounded-lg p-4 max-w-[90vw] max-h-[90vh] flex items-center justify-center">
<Image
src={`${process.env.NEXT_PUBLIC_IMAGE}${data.prescriptionImg}`}
alt="prescription preview"
width={600}
height={600}
className="max-w-full max-h-full object-contain"
unoptimized
/>
</div>
</CustomPopup>
</>
) : (
<span className="text-gray-400">Không nh</span>
)}

View File

@ -130,12 +130,6 @@ const MainPrescription = () => {
),
},
// ================= SESSION =================
{
title: "PHIÊN KHÁM",
render: (item: any) => <span>{item.examinationSessionId}</span>,
},
// ================= NOTES =================
{
title: "GHI CHÚ",
@ -148,11 +142,12 @@ const MainPrescription = () => {
render: (item: any) =>
item.prescriptionImg ? (
<Image
src={item.prescriptionImg}
src={`${process.env.NEXT_PUBLIC_IMAGE}${item.prescriptionImg}`}
alt="prescription"
width={40}
height={40}
className="h-10 w-10 rounded object-cover"
unoptimized
/>
) : (
<span className="text-gray-400">Không nh</span>

View File

@ -45,12 +45,12 @@ export const Menus: {
path: PATH.CONSULTATION,
pathActive: PATH.CONSULTATION,
},
// {
// title: "Đơn thuốc",
// icon: Pill,
// path: PATH.PRESCRIPTION,
// pathActive: PATH.PRESCRIPTION,
// },
{
title: "Đơn thuốc",
icon: Pill,
path: PATH.PRESCRIPTION,
pathActive: PATH.PRESCRIPTION,
},
],
},
];

View File

@ -53,59 +53,55 @@ export interface PrescriptionResponse {
}
const prescriptionServices = {
createPrescription: (
data: {
examinationSessionId: string;
notes: string;
PrescriptionFile: string;
items: {
medicineName: string;
dosage: string;
frequency: string;
duration: string;
instructions: string;
}[];
},
tokenAxios?: any,
) => {
/**
* CREATE
*/
createPrescription: (data: FormData, tokenAxios?: any) => {
return axiosClient.post(`/Prescription`, data, {
headers: {
"Content-Type": "multipart/form-data",
},
cancelToken: tokenAxios,
});
},
/**
* GET LIST
*/
getPrescription: (params?: GetPrescriptionParams, tokenAxios?: any) => {
return axiosClient.get<PrescriptionResponse>(`/Prescription`, {
params,
cancelToken: tokenAxios,
});
},
putPrescription: (
id: string,
data: {
notes: string;
prescriptionImg: string;
items: {
medicineName: string;
dosage: string;
frequency: string;
duration: string;
instructions: string;
}[];
},
tokenAxios?: any,
) => {
/**
* UPDATE
*/
putPrescription: (id: string, data: FormData, tokenAxios?: any) => {
return axiosClient.put(`/Prescription/${id}`, data, {
headers: {
"Content-Type": "multipart/form-data",
},
cancelToken: tokenAxios,
});
},
/**
* DETAIL
*/
detailPrescription: (id: string, tokenAxios?: any) => {
return axiosClient.get<PrescriptionDetail>(`/Prescription/${id}`, {
cancelToken: tokenAxios,
});
},
/**
* UPLOAD IMAGE
*/
uploadImage: (body: FormData) => {
return axiosClient.post("/upload", body, {
headers: {