2025-10-30 04:28:14 +00:00
|
|
|
import { useUploadController } from "./controller_admin_upload";
|
|
|
|
|
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";
|
|
|
|
|
|
|
|
|
|
export default function ViewsAdminUploadStep1() {
|
|
|
|
|
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);
|
|
|
|
|
setSelectedPages(pages);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const ext = file ? file.name.split(".").pop().toLowerCase() : "";
|
|
|
|
|
|
2025-10-30 04:28:14 +00:00
|
|
|
return (
|
|
|
|
|
<div className="max-w-4xl mx-auto py-10">
|
|
|
|
|
<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}
|
|
|
|
|
disabled={loading || (result && result.file_type === ".pdf" && result.tables?.length > 1) || (ext === "pdf" && pdfPageCount > 3 && selectedPages === "")}
|
|
|
|
|
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"
|
|
|
|
|
>
|
|
|
|
|
{loading ? "Mengunggah..." : "Upload"}
|
|
|
|
|
</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">
|
|
|
|
|
Pastikan file pdf berisi tabel yang valid dan bukan hasil scan.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
2025-10-30 04:28:14 +00:00
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|