feat-update

This commit is contained in:
TuanVT
2026-08-20 18:07:25 +07:00
parent 94e7975cd0
commit a6f0a2ef9a
+11 -10
View File
@@ -10,7 +10,7 @@ import {
} from "lucide-react";
/* ================= TYPES ================= */
interface ColumnType<T> {
export interface ColumnType<T> {
title: string | React.ReactNode;
render: (row: T, index: number, path?: number[]) => React.ReactNode;
className?: string;
@@ -23,7 +23,8 @@ interface ColumnType<T> {
interface PropsTable<T> {
data: T[];
column: ColumnType<T>[];
// Cập nhật kiểu dữ liệu ở đây để chấp nhận thêm false | null | undefined
column: (ColumnType<T> | false | null | undefined)[];
fixedHeader?: boolean;
activeHeader?: boolean;
handleCheckedAll?: (e: React.ChangeEvent<HTMLInputElement>) => void;
@@ -38,7 +39,7 @@ interface PropsTable<T> {
/* ================= COMPONENT ================= */
export default function Table<T>({
data,
column,
column: rawColumn, // Đổi tên prop column thành rawColumn
fixedHeader,
activeHeader,
handleCheckedAll,
@@ -52,6 +53,12 @@ export default function Table<T>({
const tableRef = useRef<HTMLDivElement>(null);
const thRefs = useRef<(HTMLTableCellElement | null)[]>([]);
// Lọc bỏ các giá trị falsy (false, null, undefined) để thu được mảng ColumnType<T>[] hợp lệ
const column = useMemo(
() => rawColumn.filter((col): col is ColumnType<T> => Boolean(col)),
[rawColumn],
);
const [expandedRows, setExpandedRows] = useState<React.Key[]>([]);
const [sortConfig, setSortConfig] = useState<{
key: string;
@@ -172,7 +179,7 @@ export default function Table<T>({
);
});
/* ================= MOBILE CARDS (KHUÔN BẢNG GIỐNG ẢNH MẪU) ================= */
/* ================= MOBILE CARDS ================= */
const renderMobileCards = (rows: T[], path: number[] = []): React.ReactNode =>
rows.map((row, i) => {
const currentPath = [...path, i];
@@ -182,15 +189,12 @@ export default function Table<T>({
return (
<Fragment key={String(keyPath)}>
{/* Khung Card cho mỗi bệnh nhân / dòng */}
<div className="border border-gray-500 bg-white overflow-hidden text-sm rounded-none mb-3">
{column.map((col, idx) => (
<div
key={idx}
/* Chia 40% - 60% giúp cột chứa button Action rộng rãi hơn */
className="grid grid-cols-[2fr_3fr] border-b border-gray-500 last:border-b-0 divide-x divide-gray-500 min-h-[44px]"
>
{/* Tiêu đề bên trái (TÊN BỆNH NHÂN, MÃ PHIÊN KHÁM,...) */}
<div className="p-2 font-bold flex items-center justify-center text-center bg-white uppercase text-xs tracking-tight text-gray-900 leading-tight min-w-0 break-words">
{col.checkBox && (
<input
@@ -203,14 +207,12 @@ export default function Table<T>({
{col.title}
</div>
{/* Giá trị / Nút bấm bên phải */}
<div className="p-2 flex flex-wrap items-center justify-center text-center gap-1.5 min-w-0 break-words overflow-hidden text-gray-800 font-normal">
{col.render(row, i, currentPath)}
</div>
</div>
))}
{/* Xem thêm nếu có hàng con */}
{getChildren && !!children?.length && (
<div className="p-2 bg-gray-50 border-t border-gray-500 text-center">
<button
@@ -230,7 +232,6 @@ export default function Table<T>({
)}
</div>
{/* Render hàng con nếu có */}
{expanded && children && (
<div className="pl-2 border-l-2 border-blue-500 space-y-1">
{renderMobileCards(children, currentPath)}