feat-update
This commit is contained in:
@@ -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)}
|
||||
|
||||
Reference in New Issue
Block a user