satupeta-main/app/(modules)/admin/mapset-upload/_components/map/TablePreview.tsx

163 lines
4.8 KiB
TypeScript
Raw Normal View History

2026-01-28 05:48:46 +00:00
"use client";
import React from "react";
interface TableProps {
title: string;
columns: string[];
rows: any[];
total: number;
limit?: number;
variant?: "preview" | "warning";
}
function Table({ title, columns, rows, total, limit = 100, variant = "preview" }: TableProps) {
const displayedRows = rows.slice(0, limit);
const shorten = (text: any, max = 80) => {
if (!text) return "—";
const strText = String(text);
return strText.length > max ? strText.slice(0, max) + "..." : strText;
};
return (
<div className="w-full">
<div className="overflow-x-auto border border-gray-200 rounded-lg shadow-sm bg-white">
<table className="min-w-max text-sm text-gray-800 w-full">
<thead
className={`border-b ${
variant === "warning" ? "bg-red-50" : "bg-gray-100"
}`}
>
<tr>
{columns.map((col) => (
<th
key={col}
className="px-4 py-3 text-left font-medium text-gray-700 whitespace-nowrap"
>
{col}
</th>
))}
</tr>
</thead>
<tbody>
{displayedRows.length > 0 ? (
displayedRows.map((row, idx) => (
<tr
key={idx}
className={`border-t ${
variant === "warning"
? "bg-red-50/50 hover:bg-red-100/50"
: "even:bg-gray-50 hover:bg-blue-50"
} transition-colors`}
>
{columns.map((col) => (
<td
key={col}
className="px-4 py-2 border-t border-gray-100 whitespace-nowrap max-w-[250px] overflow-hidden text-ellipsis"
title={String(row[col] ?? "")}
>
{row[col] !== null && row[col] !== undefined && row[col] !== "" ? (
col === "geometry" ? (
shorten(row[col], 50)
) : (
shorten(row[col], 80)
)
) : (
<span className="text-gray-300"></span>
)}
</td>
))}
</tr>
))
) : (
<tr>
<td
colSpan={columns.length}
className="text-center text-gray-500 py-6 italic"
>
Tidak ada data yang dapat ditampilkan
</td>
</tr>
)}
</tbody>
</table>
</div>
<div className="flex justify-between items-center px-1 py-2 text-xs text-gray-500">
<p>
Menampilkan {Math.min(limit, displayedRows.length)} dari {total} baris.
</p>
{variant === "preview" && (
<p className="italic text-gray-400">
Hanya menampilkan cuplikan data
</p>
)}
</div>
</div>
);
}
interface TablePreviewProps {
result: {
columns?: string[];
preview?: any[];
geometry_valid?: number;
geometry_empty?: number;
warning_rows?: any[];
[key: string]: any;
} | null;
}
export default function TablePreview({ result }: TablePreviewProps) {
if (!result) return null;
const {
columns = [],
preview = [],
geometry_valid = 0,
geometry_empty = 0,
warning_rows = [],
} = result;
return (
<div className="w-full space-y-6">
{/* 1. WARNING TABLE (Jika ada data yang tidak valid geometrinya) */}
{warning_rows?.length > 0 && (
<div className="border-l-4 border-yellow-400 pl-4 py-2 bg-yellow-50 rounded-r-lg">
<h3 className="font-semibold text-yellow-800 mb-1">
Periksa Data Wilayah
</h3>
<p className="text-sm text-yellow-700 mb-3">
Sistem tidak dapat mendeteksi geometri untuk data di bawah ini. Pastikan nama wilayah sesuai referensi.
</p>
<Table
title="Data Perlu Diperiksa"
columns={columns}
rows={warning_rows}
total={geometry_empty}
limit={100}
variant="warning"
/>
</div>
)}
{/* 2. PREVIEW TABLE (Data Valid) */}
<div>
{geometry_valid > 0 ? (
<Table
title="Cuplikan Data"
columns={columns}
rows={preview}
total={geometry_valid}
limit={10} // Tampilkan 10 baris saja agar tidak terlalu panjang
variant="preview"
/>
) : (
!warning_rows?.length && <div className="text-gray-500 italic">Tidak ada data preview tersedia.</div>
)}
</div>
</div>
);
}