diff --git a/src/components/layouts/BaseLayout/componets/Navbar/Navbar.tsx b/src/components/layouts/BaseLayout/componets/Navbar/Navbar.tsx
deleted file mode 100644
index 8f0d5f9..0000000
--- a/src/components/layouts/BaseLayout/componets/Navbar/Navbar.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-"use client";
-
-import React, { useCallback } from "react";
-import { usePathname } from "next/navigation";
-import Link from "next/link";
-import { Menus, PATH } from "@/constant/config";
-import clsx from "clsx";
-import { Hospital } from "lucide-react";
-
-const Navbar = () => {
- const pathname = usePathname();
-
- const checkActive = useCallback(
- (pathActive: string) => {
- // Handle root path "/" as dashboard
- if (pathname === "/" && pathActive === "/dashboard") {
- return true;
- }
-
- const currentRoute = pathname.split("/")[1];
- return pathActive === `/${currentRoute}`;
- },
- [pathname],
- );
-
- return (
-
-
- {/*
*/}
-
-
- Quản lý khám bệnh
-
-
-
- {Menus.map((menu, i) => (
-
- {/* TITLE */}
-
- {menu.title}
-
-
-
- {menu.group.map((tab, y) => {
- const isActive = checkActive(tab.pathActive);
-
- return (
-
-
-
{tab.title}
-
- );
- })}
-
-
- ))}
-
-
- );
-};
-
-export default Navbar;
diff --git a/src/components/layouts/BaseLayout/componets/Navbar/index.ts b/src/components/layouts/BaseLayout/componets/Navbar/index.ts
deleted file mode 100644
index 8d95d66..0000000
--- a/src/components/layouts/BaseLayout/componets/Navbar/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./Navbar";
diff --git a/src/components/utils/FilterDateRage/FilterDateRange.tsx b/src/components/utils/FilterDateRage/FilterDateRange.tsx
deleted file mode 100644
index 9e52a04..0000000
--- a/src/components/utils/FilterDateRage/FilterDateRange.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-"use client";
-
-import React, { useEffect, useState } from "react";
-import clsx from "clsx";
-import * as Popover from "@radix-ui/react-popover";
-
-import { PropsFilterDateRange } from "./interface";
-import Moment from "react-moment";
-import { TYPE_DATE } from "@/constant/config/enum";
-import { getDateRange } from "@/common/funcs/selectData";
-import { ListOptionFilterDate } from "@/constant/config";
-import { ChevronDown } from "lucide-react";
-import DateOption from "./components/DateOption";
-
-function FilterDateRange({
- styleRounded = false,
- showOptionAll = false,
- date,
- setDate,
- typeDate,
- setTypeDate,
- title = "Thời gian",
-}: PropsFilterDateRange) {
- const [openDate, setOpenDate] = useState(false);
-
- useEffect(() => {
- if (typeDate !== null && typeDate !== TYPE_DATE.LUA_CHON) {
- setDate(getDateRange(typeDate));
- }
- }, [typeDate, setDate]);
-
- return (
-
-
-
-
-
-
-
-
-
- );
-}
-
-export default FilterDateRange;
diff --git a/src/components/utils/FilterDateRage/components/CalendarMain/CalendarMain.tsx b/src/components/utils/FilterDateRage/components/CalendarMain/CalendarMain.tsx
deleted file mode 100644
index be006da..0000000
--- a/src/components/utils/FilterDateRage/components/CalendarMain/CalendarMain.tsx
+++ /dev/null
@@ -1,230 +0,0 @@
-"use client";
-
-import { memo, useCallback, useContext, useMemo } from "react";
-import clsx from "clsx";
-import { ContextCalendar } from "../RangeDatePicker/RangeDatePicker";
-import { PropsCalendarMain } from "./interface";
-
-const months = Array.from({ length: 12 }, (_, i) => i + 1);
-
-function CalendarMain({
- date,
- setDate,
- setType,
- type,
- year,
-}: PropsCalendarMain) {
- // ✅ destructure context (fix React Compiler)
- const { datePicker, dateHover, setDatePicker, setDateHover } =
- useContext(ContextCalendar);
-
- // ===================== HOVER RANGE =====================
- const hoverRange = useMemo(() => {
- if (datePicker?.from && dateHover) {
- return dateHover > datePicker.from
- ? { start: datePicker.from, end: dateHover }
- : { start: dateHover, end: datePicker.from };
- }
- return null;
- }, [datePicker?.from, dateHover]);
-
- // ===================== HANDLE PICK =====================
- const handleDatePick = useCallback(
- (datePick: Date) => {
- if (!datePicker?.from || datePicker?.to) {
- return setDatePicker({
- from: datePick,
- to: null,
- });
- }
-
- setDateHover(null);
-
- if (datePick < datePicker.from) {
- return setDatePicker({
- from: datePick,
- to: datePicker.from,
- });
- }
-
- return setDatePicker({
- ...datePicker,
- to: datePick,
- });
- },
- [datePicker, setDatePicker, setDateHover],
- );
-
- // ===================== HANDLE HOVER =====================
- const handleHover = useCallback(
- (d: Date) => {
- if (datePicker?.from && !datePicker?.to) {
- setDateHover(d);
- }
- },
- [datePicker?.from, datePicker?.to, setDateHover],
- );
-
- // ===================== BUILD CALENDAR =====================
- const rows = useMemo(() => {
- const currentDate = new Date();
- const monthStart = new Date(date.getFullYear(), date.getMonth(), 1);
- const monthEnd = new Date(date.getFullYear(), date.getMonth() + 1, 0);
-
- const startDate = new Date(monthStart);
- const result: React.ReactNode[] = [];
-
- // lùi về CN
- while (startDate.getDay() !== 0) {
- startDate.setDate(startDate.getDate() - 1);
- }
-
- while (startDate <= monthEnd) {
- const cells: React.ReactNode[] = [];
-
- for (let i = 0; i < 7; i++) {
- const currDate = new Date(startDate);
-
- const isStart = currDate.getTime() === datePicker?.from?.getTime();
- const isEnd = currDate.getTime() === datePicker?.to?.getTime();
-
- const isBetween =
- datePicker?.from &&
- datePicker?.to &&
- currDate > datePicker.from &&
- currDate < datePicker.to;
-
- const isHover =
- hoverRange &&
- currDate > hoverRange.start &&
- currDate < hoverRange.end;
-
- const isStartHover =
- hoverRange && currDate.getTime() === hoverRange.start.getTime();
-
- const isEndHover =
- hoverRange && currDate.getTime() === hoverRange.end.getTime();
-
- const isDisabled = startDate.getMonth() !== date.getMonth();
-
- const isToday =
- startDate.toDateString() === currentDate.toDateString() &&
- startDate.getMonth() === date.getMonth();
-
- cells.push(
- handleDatePick(currDate)}
- onMouseOver={() => handleHover(currDate)}
- className={clsx(
- "flex items-center justify-center px-2 py-1 text-sm font-medium rounded border border-transparent transition",
-
- "cursor-pointer select-none hover:opacity-60",
-
- isDisabled && "pointer-events-none opacity-30",
-
- isToday && "border-blue-700",
-
- isStart && "bg-blue-700 text-white rounded-l-md",
- isEnd && "bg-blue-700 text-white rounded-r-md",
-
- isBetween && "bg-gray-100",
-
- isHover && "border-y border-blue-700",
- isStartHover && "border border-blue-700 rounded-l-md",
- isEndHover && "border border-blue-700 rounded-r-md",
- )}
- >
- {startDate.getDate()}
-
,
- );
-
- startDate.setDate(startDate.getDate() + 1);
- }
-
- result.push(
-
- {cells}
-
,
- );
- }
-
- return result;
- }, [
- date,
- datePicker?.from,
- datePicker?.to,
- handleDatePick,
- handleHover,
- hoverRange,
- ]);
-
- // ===================== YEAR LIST =====================
- const listYear = useMemo(() => {
- if (!year) return [];
- return Array.from(
- { length: year.last - year.first + 1 },
- (_, i) => year.first + i,
- );
- }, [year]);
-
- // ===================== UI =====================
- return (
- setDateHover(null)}>
- {/* DATE */}
- {type === 0 && rows}
-
- {/* MONTH */}
- {type === 1 && (
-
- {months.map((m) => (
-
{
- const newDate = new Date(date);
- newDate.setMonth(m - 1);
- setDate(newDate);
- setType(0);
- }}
- className={clsx(
- "cursor-pointer select-none rounded px-2 py-1 text-center text-sm font-semibold transition",
- "hover:bg-gray-100 hover:opacity-70",
- m === date.getMonth() + 1 &&
- "bg-blue-500 text-white hover:bg-blue-500 hover:opacity-100",
- )}
- >
- Tháng {m}
-
- ))}
-
- )}
-
- {/* YEAR */}
- {type === 2 && (
-
- {listYear.map((y) => (
-
{
- const newDate = new Date(date);
- newDate.setFullYear(y);
- setDate(newDate);
- setType(1);
- }}
- className={clsx(
- "cursor-pointer select-none rounded px-2 py-1 text-center text-sm font-semibold transition",
- "hover:bg-gray-100 hover:opacity-70",
- y === date.getFullYear() &&
- "bg-blue-500 text-white hover:bg-blue-500 hover:opacity-100",
- )}
- >
- {y}
-
- ))}
-
- )}
-
- );
-}
-
-export default memo(CalendarMain);
diff --git a/src/components/utils/FilterDateRage/components/CalendarMain/index.ts b/src/components/utils/FilterDateRage/components/CalendarMain/index.ts
deleted file mode 100644
index cadb07e..0000000
--- a/src/components/utils/FilterDateRage/components/CalendarMain/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./CalendarMain";
diff --git a/src/components/utils/FilterDateRage/components/CalendarMain/interface/index.ts b/src/components/utils/FilterDateRage/components/CalendarMain/interface/index.ts
deleted file mode 100644
index 0a74bfd..0000000
--- a/src/components/utils/FilterDateRage/components/CalendarMain/interface/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export interface PropsCalendarMain {
- date: Date;
- setDate: (date: Date) => void;
- setType: (num: number) => void;
- type: number;
- year: any;
-}
diff --git a/src/components/utils/FilterDateRage/components/DateOption/DateOption.tsx b/src/components/utils/FilterDateRage/components/DateOption/DateOption.tsx
deleted file mode 100644
index 3f37f0e..0000000
--- a/src/components/utils/FilterDateRage/components/DateOption/DateOption.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-"use client";
-
-import clsx from "clsx";
-import { Check } from "lucide-react";
-
-import { PropsDateOption } from "./interface";
-
-import { TYPE_DATE } from "@/constant/config/enum";
-import { getDateRange } from "@/common/funcs/selectData";
-import { ListOptionFilterDate } from "@/constant/config";
-
-import RangeDatePicker from "../RangeDatePicker";
-
-export default function DateOption({
- showOptionAll,
- date,
- setDate,
- typeDate,
- setTypeDate,
- show,
- setShow,
-}: PropsDateOption) {
- const isCustom = Number(typeDate) === TYPE_DATE.LUA_CHON;
-
- return (
-
- {/* MENU */}
-
- {ListOptionFilterDate.map((item) => {
- const active = item.value === typeDate;
-
- return (
-
{
- setTypeDate(item.value);
-
- if (item.value !== TYPE_DATE.LUA_CHON) {
- setDate(getDateRange(item.value));
- setShow(false);
- }
- }}
- className={clsx(
- "flex cursor-pointer items-center justify-between rounded-lg px-3 py-2 text-sm",
- active ? "bg-blue-50 text-blue-600" : "hover:bg-gray-50",
- )}
- >
- {item.name}
-
- {active && item.value !== TYPE_DATE.LUA_CHON && (
-
- )}
-
- );
- })}
-
-
- {/* DATE PICKER */}
- {isCustom && (
-
setShow(false)}
- />
- )}
-
- );
-}
diff --git a/src/components/utils/FilterDateRage/components/DateOption/index.ts b/src/components/utils/FilterDateRage/components/DateOption/index.ts
deleted file mode 100644
index 09e27e5..0000000
--- a/src/components/utils/FilterDateRage/components/DateOption/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./DateOption";
diff --git a/src/components/utils/FilterDateRage/components/DateOption/interface/index.ts b/src/components/utils/FilterDateRage/components/DateOption/interface/index.ts
deleted file mode 100644
index 5a52221..0000000
--- a/src/components/utils/FilterDateRage/components/DateOption/interface/index.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-export interface PropsDateOption {
- showOptionAll?: boolean;
- date: {
- from: Date | null;
- to: Date | null;
- } | null;
- setDate: (any: any) => void;
- typeDate: number | null;
- setTypeDate: (any: any) => void;
- show: boolean;
- setShow: (any: any) => void;
-}
diff --git a/src/components/utils/FilterDateRage/components/RangeDatePicker/RangeDatePicker.tsx b/src/components/utils/FilterDateRage/components/RangeDatePicker/RangeDatePicker.tsx
deleted file mode 100644
index 4021770..0000000
--- a/src/components/utils/FilterDateRage/components/RangeDatePicker/RangeDatePicker.tsx
+++ /dev/null
@@ -1,220 +0,0 @@
-"use client";
-
-import { createContext, memo, useCallback, useEffect, useState } from "react";
-import { PropsRangeDatePicker } from "./interface";
-import clsx from "clsx";
-import { ChevronLeft, MoveRight, ChevronRight } from "lucide-react";
-import CalendarMain from "../CalendarMain";
-import Button from "@/components/customs/custom-button";
-import Moment from "react-moment";
-import CustomButton from "@/components/customs/custom-button";
-
-const daysOfWeek = ["CN", "T2", "T3", "T4", "T5", "T6", "T7"];
-
-export const ContextCalendar = createContext(null);
-
-function RangeDatePicker({
- onClose,
- onSetValue,
- value,
- open,
- onSubmit,
-}: PropsRangeDatePicker) {
- const [typeCalendarLeft, setTypeCalendarLeft] = useState(0);
- const [typeCalendarRight, setTypeCalendarRight] = useState(0);
- const [dateLeft, setDateLeft] = useState(new Date());
- const [dateRight, setDateRight] = useState(
- new Date(new Date().getFullYear(), new Date().getMonth() + 1),
- );
-
- const [dateHover, setDateHover] = useState(null);
- const [yearTableLeft, setYearTableLeft] = useState();
- const [yearTableRight, setYearTableRight] = useState();
- const [datePicker, setDatePicker] = useState({
- from: null as Date | null,
- to: null as Date | null,
- });
-
- // ===== HANDLE =====
- const handleNext = useCallback(
- (isRight?: boolean) => {
- if (isRight) {
- if (typeCalendarRight === 0) {
- setDateRight((prev) => {
- const newDate = new Date(prev.getFullYear(), prev.getMonth() + 1);
- return newDate;
- });
- }
- } else {
- if (typeCalendarLeft === 0) {
- setDateLeft((prev) => {
- const newDate = new Date(prev.getFullYear(), prev.getMonth() + 1);
- return newDate < dateRight ? newDate : prev;
- });
- }
- }
- },
- [dateRight, typeCalendarLeft, typeCalendarRight],
- );
-
- const handlePrev = useCallback(
- (isRight?: boolean) => {
- if (isRight) {
- if (typeCalendarRight === 0) {
- setDateRight((prev) => {
- const newDate = new Date(prev.getFullYear(), prev.getMonth() - 1);
- return dateLeft < newDate ? newDate : prev;
- });
- }
- } else {
- if (typeCalendarLeft === 0) {
- setDateLeft((prev) => {
- return new Date(prev.getFullYear(), prev.getMonth() - 1);
- });
- }
- }
- },
- [dateLeft, typeCalendarLeft, typeCalendarRight],
- );
-
- const handleSubmit = useCallback(() => {
- if (datePicker.from && datePicker.to) {
- onSetValue(datePicker);
- onClose();
- onSubmit && onSubmit();
- }
- }, [datePicker]);
-
- // ===== EFFECT =====
- useEffect(() => {
- if (!open) {
- setDatePicker({ from: value?.from, to: value?.to });
- }
- }, [open, value]);
-
- useEffect(() => {
- setYearTableLeft({
- first: dateLeft.getFullYear() - 5,
- last: dateLeft.getFullYear() + 6,
- });
- setYearTableRight({
- first: dateRight.getFullYear() - 5,
- last: dateRight.getFullYear() + 6,
- });
- }, [dateLeft, dateRight]);
-
- return (
-
-
- {/* HEADER DATE */}
-
-
- {datePicker.from ? (
- {datePicker.from}
- ) : (
- "Ngày bắt đầu"
- )}
-
-
-
-
-
- {datePicker.to ? (
- {datePicker.to}
- ) : (
- "Ngày kết thúc"
- )}
-
-
-
- {/* CALENDAR */}
-
- {[false, true].map((isRight, idx) => {
- const date = isRight ? dateRight : dateLeft;
- const type = isRight ? typeCalendarRight : typeCalendarLeft;
- const setType = isRight
- ? setTypeCalendarRight
- : setTypeCalendarLeft;
- const year = isRight ? yearTableRight : yearTableLeft;
-
- return (
-
- {/* TITLE */}
-
-
-
-
setType(type === 0 ? 1 : type === 1 ? 2 : 0)}
- >
- Tháng {date.getMonth() + 1}, {date.getFullYear()}
-
-
-
-
-
- {/* DAYS */}
- {type === 0 && (
-
- {daysOfWeek.map((d) => (
-
- {d}
-
- ))}
-
- )}
-
- {/* CALENDAR MAIN */}
-
-
- );
- })}
-
-
- {/* BUTTON */}
-
- Hủy bỏ
-
- Áp dụng
-
-
-
-
- );
-}
-
-export default memo(RangeDatePicker);
diff --git a/src/components/utils/FilterDateRage/components/RangeDatePicker/index.ts b/src/components/utils/FilterDateRage/components/RangeDatePicker/index.ts
deleted file mode 100644
index 68339b9..0000000
--- a/src/components/utils/FilterDateRage/components/RangeDatePicker/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./RangeDatePicker";
diff --git a/src/components/utils/FilterDateRage/components/RangeDatePicker/interface/index.ts b/src/components/utils/FilterDateRage/components/RangeDatePicker/interface/index.ts
deleted file mode 100644
index 1a4febd..0000000
--- a/src/components/utils/FilterDateRage/components/RangeDatePicker/interface/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export interface PropsRangeDatePicker {
- onClose: () => void;
- onSetValue: (any: any) => void;
- onSubmit?: () => void;
- value: any;
- open?: boolean;
-}
diff --git a/src/components/utils/FilterDateRage/index.ts b/src/components/utils/FilterDateRage/index.ts
deleted file mode 100644
index 18d4824..0000000
--- a/src/components/utils/FilterDateRage/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./FilterDateRange";
diff --git a/src/components/utils/FilterDateRage/interface/index.ts b/src/components/utils/FilterDateRage/interface/index.ts
deleted file mode 100644
index 5e6d459..0000000
--- a/src/components/utils/FilterDateRage/interface/index.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { Dispatch, SetStateAction } from "react";
-import { TYPE_DATE } from "@/constant/config/enum";
-
-export interface PropsFilterDateRange {
- styleRounded?: boolean;
- showOptionAll?: boolean;
- date: {
- from: Date | null;
- to: Date | null;
- } | null;
- setDate: Dispatch<
- SetStateAction<{ from: Date | null; to: Date | null } | null>
- >;
- typeDate: TYPE_DATE;
- setTypeDate: Dispatch>;
- title?: string;
-}
diff --git a/src/components/utils/PositionContainer/PositionContainer.tsx b/src/components/utils/PositionContainer/PositionContainer.tsx
deleted file mode 100644
index 34ce4d5..0000000
--- a/src/components/utils/PositionContainer/PositionContainer.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-"use client";
-
-import { ReactNode, useEffect, useRef, useState } from "react";
-
-import { createPortal } from "react-dom";
-import clsx from "clsx";
-
-import { PropsPositionContainer } from "./interface";
-
-export default function PositionContainer({
- children,
- open,
- onClose,
- disableOverlay,
- idParent,
- classStyle,
-}: PropsPositionContainer) {
- const containerRef = useRef(null);
-
- // ✅ create portal element ONCE
- const [portalElement] = useState(() => {
- if (typeof window === "undefined") {
- return null;
- }
-
- return document.createElement("div");
- });
-
- // ================= APPEND PORTAL =================
- useEffect(() => {
- if (!portalElement) return;
-
- const parent = idParent ? document.getElementById(idParent) : document.body;
-
- if (!parent) return;
-
- parent.appendChild(portalElement);
-
- return () => {
- parent.removeChild(portalElement);
- };
- }, [idParent, portalElement]);
-
- // ================= CLICK OUTSIDE =================
- useEffect(() => {
- if (!disableOverlay || !open) return;
-
- const handleMouseUp = (e: MouseEvent) => {
- const target = e.target as HTMLElement;
-
- const insideClick = target.closest(".click");
-
- if (
- containerRef.current &&
- !containerRef.current.contains(target) &&
- !insideClick
- ) {
- onClose();
- }
- };
-
- document.addEventListener("mouseup", handleMouseUp);
-
- return () => {
- document.removeEventListener("mouseup", handleMouseUp);
- };
- }, [disableOverlay, open, onClose]);
-
- // ================= SSR SAFE =================
- if (!portalElement) return null;
-
- return createPortal(
-
- {/* overlay */}
- {!disableOverlay && (
-
- )}
-
- {/* panel */}
-
- {children}
-
-
,
- portalElement,
- );
-}
diff --git a/src/components/utils/PositionContainer/components/ClickOpen/ClickOpen.tsx b/src/components/utils/PositionContainer/components/ClickOpen/ClickOpen.tsx
deleted file mode 100644
index 3528f9e..0000000
--- a/src/components/utils/PositionContainer/components/ClickOpen/ClickOpen.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-"use client";
-
-import { useEffect, useRef } from "react";
-import { PropsClickOpen } from "./interface";
-
-export default function ClickOpen({
- children,
- onClick,
- duration = 100,
-}: PropsClickOpen) {
- const timeoutRef = useRef(null);
-
- const handleClick = () => {
- // clear timeout cũ nếu spam click
- if (timeoutRef.current) {
- clearTimeout(timeoutRef.current);
- }
-
- onClick(false);
-
- timeoutRef.current = setTimeout(() => {
- onClick(true);
- }, duration);
- };
-
- useEffect(() => {
- return () => {
- // cleanup khi unmount
- if (timeoutRef.current) {
- clearTimeout(timeoutRef.current);
- }
- };
- }, []);
-
- return {children}
;
-}
diff --git a/src/components/utils/PositionContainer/components/ClickOpen/index.ts b/src/components/utils/PositionContainer/components/ClickOpen/index.ts
deleted file mode 100644
index 19f3c55..0000000
--- a/src/components/utils/PositionContainer/components/ClickOpen/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./ClickOpen";
diff --git a/src/components/utils/PositionContainer/components/ClickOpen/interface/index.ts b/src/components/utils/PositionContainer/components/ClickOpen/interface/index.ts
deleted file mode 100644
index 5f77f1b..0000000
--- a/src/components/utils/PositionContainer/components/ClickOpen/interface/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export interface PropsClickOpen {
- children: any;
- onClick: (bol: boolean) => void;
- duration?: number;
-}
diff --git a/src/components/utils/PositionContainer/index.ts b/src/components/utils/PositionContainer/index.ts
deleted file mode 100644
index e69de29..0000000
diff --git a/src/components/utils/PositionContainer/interface/index.ts b/src/components/utils/PositionContainer/interface/index.ts
deleted file mode 100644
index d0dec60..0000000
--- a/src/components/utils/PositionContainer/interface/index.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export interface PropsPositionContainer {
- children: any;
- open: boolean;
- onClose: () => void;
- disableOverlay?: boolean;
- idParent?: string;
- classStyle?: {
- main: string;
- open: string;
- };
-}
diff --git a/src/components/utils/UploadAvatar/UploadAvatar.tsx b/src/components/utils/UploadAvatar/UploadAvatar.tsx
deleted file mode 100644
index a09bde5..0000000
--- a/src/components/utils/UploadAvatar/UploadAvatar.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-import React, { useEffect, useState } from "react";
-
-import { PropsUploadAvatar } from "./interface";
-// import { toastError, toastWarn } from "~/common/funcs/toast";
-import Image from "next/image";
-import { toastError, toastWarn } from "@/common/funcs/toast";
-import { Trash } from "lucide-react";
-// import icons from "~/constants/images/icons";
-
-const MAXIMUM_FILE = 10;
-
-function UploadAvatar({ path, name, onSetFile, resetPath }: PropsUploadAvatar) {
- const [imageBase64, setImageBase64] = useState("");
- const [fileName, setFileName] = useState("");
-
- const handleSelectImg = (e: React.ChangeEvent) => {
- const file = e.target.files?.[0];
-
- if (file) {
- const { size, type, name } = file;
- const maxSize = MAXIMUM_FILE; // MB
-
- if (size / 1000000 > maxSize) {
- return toastError({
- msg: `Kích thước tối đa của ảnh là ${maxSize} MB`,
- });
- } else if (!["image/jpeg", "image/jpg", "image/png"].includes(type)) {
- return toastWarn({
- msg: `Định dạng tệp không chính xác, chỉ chấp nhận .jpg, .jpeg, .png`,
- });
- }
-
- const imageUrl = URL.createObjectURL(file);
- setImageBase64((prev) => {
- URL.revokeObjectURL(prev);
- return imageUrl;
- });
- setFileName(name);
- onSetFile && onSetFile(file);
- }
- };
-
- useEffect(() => {
- return () => {
- if (imageBase64) {
- URL.revokeObjectURL(imageBase64);
- }
- };
- }, [imageBase64]);
-
- const handleRemoveImg = () => {
- setImageBase64("");
- setFileName("");
- onSetFile && onSetFile(null);
- resetPath && resetPath();
- };
-
- return (
-
-
-
-
-
-
-
- {/* Xóa avatar */}
-
-
-
- Xóa ảnh đại diện
-
-
-
-
-
- Hình ảnh được dùng làm ảnh đại diện, kích thước tối thiểu 300px X
- 300px để đảm bảo độ sắc nét.
-
-
-
- );
-}
-
-export default UploadAvatar;
diff --git a/src/components/utils/UploadAvatar/index.ts b/src/components/utils/UploadAvatar/index.ts
deleted file mode 100644
index 9c7d933..0000000
--- a/src/components/utils/UploadAvatar/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./UploadAvatar";
diff --git a/src/components/utils/UploadAvatar/interface/index.ts b/src/components/utils/UploadAvatar/interface/index.ts
deleted file mode 100644
index 34cacd7..0000000
--- a/src/components/utils/UploadAvatar/interface/index.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { Dispatch, SetStateAction } from "react";
-
-export interface PropsUploadAvatar {
- path: any;
- name: string;
- onSetFile: Dispatch>;
- resetPath?: () => void;
-}
diff --git a/src/components/utils/UploadImage/UploadImage.tsx b/src/components/utils/UploadImage/UploadImage.tsx
deleted file mode 100644
index fb04efb..0000000
--- a/src/components/utils/UploadImage/UploadImage.tsx
+++ /dev/null
@@ -1,243 +0,0 @@
-"use client";
-
-import React, { useEffect, useMemo, useState } from "react";
-
-import Image from "next/image";
-
-import clsx from "clsx";
-
-import { UploadCloud, X } from "lucide-react";
-
-import { toastError, toastWarn } from "@/common/funcs/toast";
-
-import { UploadImageProps } from "./interface";
-
-const MAXIMUM_FILE = 10; // MB
-
-const ACCEPT_TYPES = ["image/jpeg", "image/jpg", "image/png"];
-
-/* =========================
- COMPONENT
-========================= */
-
-const UploadImage = ({
- label,
- name,
- path,
- file,
- setFile,
- resetPath,
- isWidthFull = true,
- disabled = false,
-}: UploadImageProps) => {
- const [dragging, setDragging] = useState(false);
-
- /* =========================
- PREVIEW IMAGE
- ========================= */
-
- const imagePreview = useMemo(() => {
- if (!file) return "";
-
- return URL.createObjectURL(file);
- }, [file]);
-
- /* =========================
- CLEANUP OBJECT URL
- ========================= */
-
- useEffect(() => {
- return () => {
- if (imagePreview) {
- URL.revokeObjectURL(imagePreview);
- }
- };
- }, [imagePreview]);
-
- /* =========================
- VALIDATE FILE
- ========================= */
-
- const validateFile = (selectedFile: File | null | undefined) => {
- if (!selectedFile) return;
-
- const { size, type } = selectedFile;
-
- /**
- * CHECK SIZE
- */
- if (size / 1000000 > MAXIMUM_FILE) {
- return toastError({
- msg: `Kích thước tối đa của ảnh là ${MAXIMUM_FILE} MB`,
- });
- }
-
- /**
- * CHECK TYPE
- */
- if (!ACCEPT_TYPES.includes(type)) {
- return toastWarn({
- msg: "Định dạng không hợp lệ. Chỉ chấp nhận JPG, JPEG, PNG",
- });
- }
-
- /**
- * SET FILE
- */
- setFile(selectedFile);
- };
-
- /* =========================
- DRAG EVENTS
- ========================= */
-
- const handleDragEnter = (e: React.DragEvent): void => {
- e.preventDefault();
-
- if (disabled) return;
-
- setDragging(true);
- };
-
- const handleDragLeave = (): void => {
- setDragging(false);
- };
-
- const handleDrop = (e: React.DragEvent): void => {
- e.preventDefault();
-
- if (disabled) return;
-
- setDragging(false);
-
- const droppedFile = e.dataTransfer.files?.[0];
-
- validateFile(droppedFile);
- };
-
- /* =========================
- SELECT FILE
- ========================= */
-
- const handleSelectImage = (e: React.ChangeEvent): void => {
- if (disabled) return;
-
- const selectedFile = e.target.files?.[0];
-
- validateFile(selectedFile);
- };
-
- /* =========================
- REMOVE IMAGE
- ========================= */
-
- const handleRemoveImage = (): void => {
- setFile(null);
-
- resetPath?.();
- };
-
- /* =========================
- IMAGE SOURCE
- ========================= */
-
- const imageSrc = imagePreview || path || "";
-
- /* =========================
- UI
- ========================= */
-
- return (
-
- {/* LABEL */}
- {label && (
-
- {typeof label === "string" ? (
-
{label}
- ) : (
- label
- )}
-
- )}
-
- {/* PREVIEW */}
- {imageSrc ? (
-
-
-
- {/* REMOVE BUTTON */}
- {!disabled && (
-
- )}
-
- ) : (
-
- )}
-
- );
-};
-
-export default UploadImage;
diff --git a/src/components/utils/UploadImage/index.ts b/src/components/utils/UploadImage/index.ts
deleted file mode 100644
index 87abefe..0000000
--- a/src/components/utils/UploadImage/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./UploadImage";
diff --git a/src/components/utils/UploadImage/interface/index.ts b/src/components/utils/UploadImage/interface/index.ts
deleted file mode 100644
index c44672b..0000000
--- a/src/components/utils/UploadImage/interface/index.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-export interface UploadImageProps {
- isWidthFull?: boolean;
-
- label?: string | React.ReactNode;
-
- name: string;
-
- file: File | null;
-
- setFile: (file: File | null) => void;
-
- path?: string;
-
- resetPath?: () => void;
-
- disabled?: boolean;
-}
diff --git a/src/components/utils/UploadMultipleFile/UploadMultipleFile.tsx b/src/components/utils/UploadMultipleFile/UploadMultipleFile.tsx
deleted file mode 100644
index e89c3ba..0000000
--- a/src/components/utils/UploadMultipleFile/UploadMultipleFile.tsx
+++ /dev/null
@@ -1,211 +0,0 @@
-"use client";
-
-import React from "react";
-import Image from "next/image";
-import {
- X,
- CirclePlus,
- FileText,
- FileSpreadsheet,
- FileType,
- FileImage,
-} from "lucide-react";
-
-import clsx from "clsx";
-import { PropsUploadMultipleFile, UploadFileItem } from "./interface";
-
-export default function UploadMultipleFile({
- images = [],
- setImages,
- isDisableDelete = false,
-}: PropsUploadMultipleFile) {
- /* =========================
- CHECK IMAGE FILE
- ========================= */
- const isImageFile = (item: UploadFileItem) => {
- const type = item?.fileType || "";
-
- return (
- type.startsWith("image/") ||
- /\.(jpg|jpeg|png|gif|webp)$/i.test(item?.path || "")
- );
- };
-
- /* =========================
- GET FILE ICON
- ========================= */
- const renderFileIcon = (item: UploadFileItem) => {
- const fileName = item?.fileName || item?.path?.split("/").pop() || "";
-
- const ext = fileName.split(".").pop()?.toLowerCase();
-
- switch (ext) {
- case "jpg":
- case "jpeg":
- case "png":
- case "gif":
- case "webp":
- return ;
-
- case "pdf":
- return ;
-
- case "xls":
- case "xlsx":
- return ;
-
- case "doc":
- case "docx":
- return ;
-
- case "ppt":
- case "pptx":
- return ;
-
- case "txt":
- return ;
-
- default:
- return ;
- }
- };
-
- /* =========================
- UPLOAD FILES
- ========================= */
- const handleFileChange = (event: React.ChangeEvent) => {
- const files = event.target.files;
-
- if (!files) return;
-
- const newFiles: UploadFileItem[] = Array.from(files).map((file) => ({
- file,
- url: URL.createObjectURL(file),
- fileName: file.name,
- fileType: file.type,
- }));
-
- setImages((prev) => [...prev, ...newFiles]);
- };
-
- /* =========================
- DELETE FILE
- ========================= */
- const handleDelete = (index: number) => {
- setImages((prev) => {
- const target = prev[index];
-
- if (target?.url) {
- URL.revokeObjectURL(target.url);
- }
-
- return prev.filter((_, i) => i !== index);
- });
- };
-
- return (
-
- {/* FILE LIST */}
- {images?.length > 0 && (
-
- {images.map((item, index) => {
- const fileUrl =
- item?.url ||
- (item?.path
- ? `${process.env.NEXT_PUBLIC_IMAGE}${item.path}`
- : "");
-
- return (
-
- );
- })}
-
- )}
-
- {/* UPLOAD BUTTON */}
-
-
-
-
-
Upload file
-
-
- JPG, PNG, PDF, Word, Excel, PPT (≤ 50MB)
-
-
-
-
- );
-}
diff --git a/src/components/utils/UploadMultipleFile/index.ts b/src/components/utils/UploadMultipleFile/index.ts
deleted file mode 100644
index 7f24387..0000000
--- a/src/components/utils/UploadMultipleFile/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./UploadMultipleFile";
diff --git a/src/components/utils/UploadMultipleFile/interface/index.ts b/src/components/utils/UploadMultipleFile/interface/index.ts
deleted file mode 100644
index e44b849..0000000
--- a/src/components/utils/UploadMultipleFile/interface/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-export interface UploadFileItem {
- file?: File | null;
- url?: string;
- path?: string;
- img?: string;
-
- fileName?: string;
- fileType?: string;
-}
-
-export interface PropsUploadMultipleFile {
- images: UploadFileItem[];
- setImages: React.Dispatch>;
- isDisableDelete?: boolean;
-}
diff --git a/src/constant/config/index.ts b/src/constant/config/index.ts
index fb4ed8d..d07b8f3 100644
--- a/src/constant/config/index.ts
+++ b/src/constant/config/index.ts
@@ -1,22 +1,14 @@
-import {
- ChartNoAxesCombined,
- CircleGauge,
- HeartPulse,
- Pill,
- Users,
-} from "lucide-react";
+// import {
+// ChartNoAxesCombined,
+// CircleGauge,
+// HeartPulse,
+// Pill,
+// Users,
+// } from "lucide-react";
import { TYPE_DATE } from "./enum";
export enum PATH {
HOME = "/",
- DASHBOARD = "/dashboard",
- PATIENT = "/patient",
- CONSULTATION = "/consultation",
- PRESCRIPTION = "/prescription",
- CREATE_PRESCRIPTION = "/prescription/create",
-
- STATISTICAL = "/statistical",
-
LOGIN = "/auth/login",
REGISTER = "/auth/register",
FORGOT_PASSWORD = "/auth/forgot-password",
@@ -25,51 +17,51 @@ export enum PATH {
UPDATEPROFILE = "/profile/update",
}
-export const Menus: {
- title?: string;
- group: {
- path: string;
- pathActive: string;
- // isSpecial?: TYPE_SPECIAL;
- title: string;
- icon: React.ElementType;
- }[];
-}[] = [
- {
- group: [
- {
- title: "Dashboard",
- icon: CircleGauge,
- path: PATH.DASHBOARD || PATH.HOME,
- pathActive: PATH.DASHBOARD,
- },
- {
- title: "Bệnh nhân",
- icon: Users,
- path: PATH.PATIENT,
- pathActive: PATH.PATIENT,
- },
- {
- title: "Phiên khám",
- icon: HeartPulse,
- path: PATH.CONSULTATION,
- pathActive: PATH.CONSULTATION,
- },
- {
- title: "Đơn thuốc",
- icon: Pill,
- path: PATH.PRESCRIPTION,
- pathActive: PATH.PRESCRIPTION,
- },
- {
- title: "Thống kê chuyên khoa",
- icon: ChartNoAxesCombined,
- path: PATH.STATISTICAL,
- pathActive: PATH.STATISTICAL,
- },
- ],
- },
-];
+// export const Menus: {
+// title?: string;
+// group: {
+// path: string;
+// pathActive: string;
+// // isSpecial?: TYPE_SPECIAL;
+// title: string;
+// icon: React.ElementType;
+// }[];
+// }[] = [
+// {
+// group: [
+// {
+// title: "Dashboard",
+// icon: CircleGauge,
+// path: PATH.DASHBOARD || PATH.HOME,
+// pathActive: PATH.DASHBOARD,
+// },
+// {
+// title: "Bệnh nhân",
+// icon: Users,
+// path: PATH.PATIENT,
+// pathActive: PATH.PATIENT,
+// },
+// {
+// title: "Phiên khám",
+// icon: HeartPulse,
+// path: PATH.CONSULTATION,
+// pathActive: PATH.CONSULTATION,
+// },
+// {
+// title: "Đơn thuốc",
+// icon: Pill,
+// path: PATH.PRESCRIPTION,
+// pathActive: PATH.PRESCRIPTION,
+// },
+// {
+// title: "Thống kê chuyên khoa",
+// icon: ChartNoAxesCombined,
+// path: PATH.STATISTICAL,
+// pathActive: PATH.STATISTICAL,
+// },
+// ],
+// },
+// ];
export const ListOptionFilterDate: {
name: string;