file_table_reader/src/pages/admin/upload/views_admin_upload.jsx

243 lines
9.1 KiB
React
Raw Normal View History

2025-10-30 04:28:14 +00:00
import { useUploadController } from "./controller_admin_upload";
2025-11-05 02:34:59 +00:00
import { useDispatch } from "react-redux";
2025-11-06 07:59:34 +00:00
import LoadingOverlay from "../../../components/LoadingOverlay";
2025-10-30 04:28:14 +00:00
import FileDropzone from "../../../components/FileDropzone";
2025-11-04 07:24:45 +00:00
import PdfPageSelector from "../../../components/PdfPageSelector";
2025-10-30 04:28:14 +00:00
import { Link } from "react-router-dom";
2025-11-06 07:59:34 +00:00
import { useEffect } from "react";
import { reset } from "../../../store/slices/uploadSlice";
2025-10-30 04:28:14 +00:00
export default function ViewsAdminUploadStep1() {
2025-11-05 02:34:59 +00:00
const dispatch = useDispatch();
2025-10-30 04:28:14 +00:00
const {
loading,
file,
result,
2025-11-04 07:24:45 +00:00
pdfPageCount,
selectedPages,
2025-10-30 04:28:14 +00:00
selectedTable,
2025-11-04 09:54:10 +00:00
sheetCount,
sheetNames,
selectedSheet,
2025-11-04 07:24:45 +00:00
setSelectedPages,
2025-10-30 04:28:14 +00:00
setSelectedTable,
2025-11-04 09:54:10 +00:00
setSelectedSheet,
2025-10-30 04:28:14 +00:00
handleFileSelect,
handleUpload,
2025-11-04 07:24:45 +00:00
handleNextPdf
2025-10-30 04:28:14 +00:00
} = useUploadController();
2025-11-04 07:24:45 +00:00
const handlePageSelection = (pages) => {
console.log("Halaman PDF yang dipilih:", pages);
2025-11-05 02:34:59 +00:00
// setSelectedPages(pages);
dispatch(setSelectedPages(pages));
2025-11-04 07:24:45 +00:00
};
const ext = file ? file.name.split(".").pop().toLowerCase() : "";
2025-11-06 07:59:34 +00:00
useEffect(() => {
dispatch(reset())
}, [])
2025-10-30 04:28:14 +00:00
return (
<div className="max-w-4xl mx-auto py-10">
2025-11-06 07:59:34 +00:00
<LoadingOverlay show={loading} text="Processing..." />
2025-10-30 04:28:14 +00:00
<div className="mb-6 flex justify-between items-center">
<h1 className="text-2xl font-bold text-gray-800">Upload Data</h1>
<p className="text-lg text-gray-600">
<Link to="/admin/upload/rules" className="text-blue-600 hover:underline">
Panduan upload
</Link>
</p>
</div>
2025-11-04 07:24:45 +00:00
{/* Dropzone */}
2025-10-30 04:28:14 +00:00
<FileDropzone onFileSelect={handleFileSelect} />
2025-11-04 07:24:45 +00:00
{/* {!file && (
)} */}
2025-10-30 04:28:14 +00:00
{file && (
2025-11-04 07:24:45 +00:00
<div className="mt-6 border border-gray-200 bg-white rounded-xl p-6 shadow-sm">
{/* Info File */}
<div className="">
<p className="text-gray-800 text-sm font-medium flex items-center gap-2">
📎
<span
className={`${
file.name.endsWith('.pdf')
? 'text-red-500'
: file.name.endsWith('.csv')
? 'text-green-500'
: file.name.endsWith('.zip')
? 'text-yellow-500'
: 'text-gray-500'
}`}
>
{file.name}
</span>
</p>
{ext === "pdf" && pdfPageCount && (
<p className="text-gray-500 text-xs mt-1">
File PDF <span className="font-semibold">{pdfPageCount}</span> halaman.
</p>
)}
</div>
{/* Selector Halaman (hanya untuk PDF dengan > 1 halaman) */}
{ext === "pdf" && pdfPageCount > 1 && (
<div className="mt-4">
<PdfPageSelector totalPages={pdfPageCount} onChange={handlePageSelection} />
</div>
)}
2025-11-04 09:54:10 +00:00
{(ext === "xlsx" || ext === "xls") && sheetCount > 1 && (
<>
<ul className="border rounded-lg divide-y overflow-hidden">
{sheetNames.map((name, i) => (
<li
key={i}
onClick={() => setSelectedSheet(name)}
className={`flex items-center gap-2 p-3 cursor-pointer hover:bg-blue-50 transition ${
selectedSheet === name ? "bg-blue-100 font-semibold" : ""
}`}
>
<span className={`text-green-600 ${selectedSheet === name ? "" : "opacity-0"}`}></span>
<span>{name}</span>
</li>
))}
</ul>
<p className="text-xs text-gray-500 mt-1 ml-2 py-0">
<i>*Pilih sheet yang akan dimasukan</i>
</p>
</>
)}
2025-11-04 07:24:45 +00:00
{/* Tombol Upload */}
<div className={`mt-6 flex justify-center ${(result && result.file_type === ".pdf" && result.tables?.length > 1) ? 'hidden' : 'block' }`}>
<button
onClick={handleUpload}
2025-11-05 02:34:59 +00:00
disabled={
loading ||
(result && result.file_type === ".pdf" && result.tables?.length > 1) ||
(ext === "pdf" && pdfPageCount > 3 && (selectedPages === "" || selectedPages == null))}
2025-11-04 07:24:45 +00:00
className="w-full px-6 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition"
>
2025-11-05 02:34:59 +00:00
{loading ? "Mengunggah..." : "Process"}
2025-11-04 07:24:45 +00:00
</button>
</div>
2025-10-30 04:28:14 +00:00
</div>
)}
2025-11-04 07:24:45 +00:00
2025-10-30 04:28:14 +00:00
{result && result.file_type === ".pdf" && result.tables?.length > 1 && (
2025-11-04 07:24:45 +00:00
<div className="mt-6 border border-gray-200 bg-white rounded-xl p-6 shadow-sm">
2025-10-30 04:28:14 +00:00
<h2 className="text-lg font-semibold mb-2 text-gray-700">Hasil Analisis Backend</h2>
2025-11-04 09:54:10 +00:00
{/* <ul className="border rounded-lg divide-y overflow-hidden">
{result.tables.map((t, i) => (
<li
key={i}
onClick={() => setSelectedTable(t)}
className={`flex items-center gap-2 p-3 cursor-pointer hover:bg-blue-50 transition ${
selectedTable?.title === t.title ? "bg-blue-100 font-semibold" : ""
}`}
>
<span className={`text-green-600 ${selectedTable?.title === t.title ? "" : "opacity-0"}`}></span>
<span>{t.title}</span>
</li>
))}
</ul> */}
2025-11-04 07:24:45 +00:00
<ul className="space-y-3 mt-4">
2025-10-30 04:28:14 +00:00
{result.tables.map((t, i) => (
<li
key={i}
onClick={() => setSelectedTable(t)}
2025-11-04 07:24:45 +00:00
className={`group relative border border-gray-200 rounded-lg cursor-pointer overflow-hidden transition-all duration-200
hover:shadow-sm hover:border-blue-300 ${
selectedTable?.title === t.title ? "bg-blue-50 border-blue-400" : "bg-white"
}`}
2025-10-30 04:28:14 +00:00
>
2025-11-04 07:24:45 +00:00
{/* Header nama tabel */}
<div className="flex justify-between items-center px-4 py-2 bg-gray-50 border-b border-gray-200">
<span
className={`text-sm font-medium ${
selectedTable?.title === t.title ? "text-blue-700" : "text-gray-700"
}`}
>
📄 Tabel {t.title}
</span>
<span
className={`text-green-600 text-lg transition-opacity ${
selectedTable?.title === t.title ? "opacity-100" : "opacity-0"
}`}
>
</span>
</div>
{/* Mini preview kolom */}
<div className="overflow-x-auto">
<table className="min-w-full text-xs">
<thead className="bg-gray-100 text-gray-600">
<tr>
{t.columns?.map((col, idx) => (
<th
key={idx}
className="px-3 py-2 text-left font-medium whitespace-nowrap border-r last:border-none border-gray-200"
>
{col}
</th>
))}
</tr>
</thead>
</table>
</div>
{/* Highlight bar animasi */}
<div
className={`absolute bottom-0 left-0 h-1 bg-blue-500 transition-all duration-300 ${
selectedTable?.title === t.title ? "w-full opacity-100" : "w-0 opacity-0"
}`}
/>
2025-10-30 04:28:14 +00:00
</li>
))}
</ul>
2025-11-04 07:24:45 +00:00
2025-10-30 04:28:14 +00:00
<button
onClick={handleNextPdf}
disabled={!selectedTable}
2025-11-04 07:24:45 +00:00
className="w-full mt-4 px-5 py-2 bg-green-600 text-white rounded hover:bg-green-700 disabled:bg-gray-300"
2025-10-30 04:28:14 +00:00
>
Lanjut ke Validasi
</button>
2025-11-04 07:24:45 +00:00
<p className="text-xs text-gray-500 mt-1 ml-1 py-0">
<i>*Pilih tabel yang akan di proses ke database</i>
</p>
</div>
)}
{result && result.file_type === ".pdf" && result.tables?.length == 0 && (
<div className="mt-6 flex items-start gap-3 border-l-4 border-yellow-500 bg-yellow-50 p-4 rounded-md shadow-sm">
<div className="text-yellow-500 mt-0.5">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor" className="w-6 h-6">
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v3.75m0 3.75h.007v.007H12v-.007zM21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<div>
<h3 className="font-semibold text-yellow-800">Tidak Ditemukan Tabel Valid</h3>
<p className="text-yellow-700 text-sm">
2025-11-06 08:21:37 +00:00
Pastikan file pdf berisi tabel yang memiliki kolom geometry dan bukan hasil scan.
2025-11-04 07:24:45 +00:00
</p>
</div>
2025-10-30 04:28:14 +00:00
</div>
)}
</div>
);
}