254 lines
6.8 KiB
TypeScript
254 lines
6.8 KiB
TypeScript
"use client";
|
|
|
|
import React, { useState, useEffect, useCallback } from "react";
|
|
import Swal from "sweetalert2";
|
|
import withReactContent from "sweetalert2-react-content";
|
|
import { close, error, loading } from "@/config/swal";
|
|
import {
|
|
getKnowledgeBaseCategoryList,
|
|
saveKnowledgeBase,
|
|
} from "@/service/master/knowledge-base";
|
|
import { Link, useRouter } from "@/i18n/routing";
|
|
|
|
type ButtonProps = {
|
|
title: string;
|
|
type: "submit" | "link";
|
|
href?: string;
|
|
};
|
|
|
|
type KnowledgeBaseItem = {
|
|
category: string;
|
|
title: string;
|
|
question: string;
|
|
answer: string;
|
|
};
|
|
|
|
type CategoryItem = {
|
|
id: string;
|
|
name: string;
|
|
};
|
|
|
|
const Button: React.FC<ButtonProps> = ({ title, type, href }) => {
|
|
if (type === "submit") {
|
|
return (
|
|
<button
|
|
type="submit"
|
|
className="ml-2 rounded-lg bg-blue-600 text-white px-4 py-2 hover:bg-blue-700 transition"
|
|
>
|
|
{title}
|
|
</button>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Link href={href || "#"}>
|
|
<button
|
|
type="button"
|
|
className="mr-3 rounded-lg border border-blue-600 text-blue-600 px-4 py-2 hover:bg-blue-50 transition"
|
|
>
|
|
{title}
|
|
</button>
|
|
</Link>
|
|
);
|
|
};
|
|
|
|
const ImportKnowledgeBase: React.FC = () => {
|
|
const router = useRouter();
|
|
const [listCategory, setListCategory] = useState<CategoryItem[]>([]);
|
|
const [file, setFile] = useState<File | null>(null);
|
|
const [savedArray, setSavedArray] = useState<KnowledgeBaseItem[]>([]);
|
|
const [handleDelete, setHandleDelete] = useState(false);
|
|
const MySwal = withReactContent(Swal);
|
|
|
|
|
|
useEffect(() => {
|
|
async function initState() {
|
|
loading();
|
|
const response = await getKnowledgeBaseCategoryList();
|
|
const data = response?.data?.data || [];
|
|
setListCategory(data);
|
|
close();
|
|
}
|
|
initState();
|
|
}, []);
|
|
|
|
const handleOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
if (e.target.files && e.target.files[0]) {
|
|
setFile(e.target.files[0]);
|
|
}
|
|
};
|
|
|
|
const csvFileToArray = (content: string) => {
|
|
const csvHeader = ["category", "title", "question", "answer"];
|
|
const rows = content.split("\n").filter((line) => line.trim() !== "");
|
|
|
|
const parsedData: KnowledgeBaseItem[] = rows.map((row) => {
|
|
const values = row.split(";").map((v) => v.trim());
|
|
const obj = csvHeader.reduce((acc, header, index) => {
|
|
acc[header as keyof KnowledgeBaseItem] = values[index] || "";
|
|
return acc;
|
|
}, {} as KnowledgeBaseItem);
|
|
return obj;
|
|
});
|
|
|
|
setSavedArray(parsedData);
|
|
setHandleDelete(true);
|
|
};
|
|
|
|
const handleOnSubmit = useCallback(
|
|
(e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
if (file) {
|
|
const reader = new FileReader();
|
|
reader.onload = (event) => {
|
|
const text = event.target?.result as string;
|
|
csvFileToArray(text);
|
|
};
|
|
reader.readAsText(file);
|
|
}
|
|
},
|
|
[file]
|
|
);
|
|
|
|
const handleSave = async (data: KnowledgeBaseItem[]) => {
|
|
const result = await MySwal.fire({
|
|
title: "Simpan Data",
|
|
icon: "warning",
|
|
showCancelButton: true,
|
|
cancelButtonColor: "#d33",
|
|
confirmButtonColor: "#3085d6",
|
|
confirmButtonText: "Simpan",
|
|
});
|
|
|
|
if (result.isConfirmed) {
|
|
save(data);
|
|
}
|
|
};
|
|
|
|
const save = async (data: KnowledgeBaseItem[]) => {
|
|
loading();
|
|
for (const item of data) {
|
|
const categoryStringId = listCategory.find(
|
|
(c) => c.name.toLowerCase() === item.category.toLowerCase()
|
|
)?.id;
|
|
|
|
const reqData = {
|
|
title: item.title,
|
|
categoryId: categoryStringId,
|
|
question: item.question,
|
|
answer: item.answer,
|
|
};
|
|
|
|
const response = await saveKnowledgeBase(reqData);
|
|
if (response?.error) {
|
|
error(response.message);
|
|
close();
|
|
return;
|
|
}
|
|
}
|
|
close();
|
|
successSubmit("/supervisor/knowledge-base");
|
|
};
|
|
|
|
const successSubmit = async (redirect: string) => {
|
|
const result = await MySwal.fire({
|
|
title: "Sukses",
|
|
icon: "success",
|
|
confirmButtonColor: "#3085d6",
|
|
confirmButtonText: "OK",
|
|
});
|
|
|
|
if (result.isConfirmed) {
|
|
router.push(redirect);
|
|
}
|
|
};
|
|
|
|
const deleteFile = () => {
|
|
setFile(null);
|
|
setSavedArray([]);
|
|
setHandleDelete(false);
|
|
};
|
|
|
|
return (
|
|
<div className="p-4">
|
|
<form onSubmit={handleOnSubmit}>
|
|
<div className="mb-4">
|
|
<label htmlFor="csvFileInput" className="block font-medium mb-1">
|
|
Input File CSV
|
|
</label>
|
|
<input
|
|
type="file"
|
|
id="csvFileInput"
|
|
accept=".csv"
|
|
onChange={handleOnChange}
|
|
className="border border-gray-300 rounded px-3 py-2 w-full"
|
|
/>
|
|
<button
|
|
type="submit"
|
|
className="mt-2 rounded border border-green-600 text-green-600 px-4 py-2 hover:bg-green-50 transition"
|
|
>
|
|
Import Data
|
|
</button>
|
|
</div>
|
|
|
|
{savedArray.length > 0 && (
|
|
<div className="overflow-auto mb-4">
|
|
<table className="min-w-full border text-center text-sm">
|
|
<thead className="bg-gray-100">
|
|
<tr>
|
|
<th className="border px-2 py-1">Kategori</th>
|
|
<th className="border px-2 py-1">Judul</th>
|
|
<th className="border px-2 py-1">Pertanyaan</th>
|
|
<th className="border px-2 py-1">Jawaban</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{savedArray.map((item, idx) => (
|
|
<tr key={idx}>
|
|
<td className="border px-2 py-1">{item.category}</td>
|
|
<td className="border px-2 py-1">{item.title}</td>
|
|
<td className="border px-2 py-1">{item.question}</td>
|
|
<td className="border px-2 py-1">{item.answer}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
)}
|
|
|
|
{handleDelete && (
|
|
<button
|
|
type="button"
|
|
onClick={deleteFile}
|
|
className="text-red-600 hover:underline mb-4"
|
|
>
|
|
Hapus File
|
|
</button>
|
|
)}
|
|
|
|
<div className="flex justify-end gap-2">
|
|
<Link href="/supervisor/knowledge-base">
|
|
<button
|
|
type="button"
|
|
className="rounded border border-blue-600 text-blue-600 px-4 py-2 hover:bg-blue-50 transition"
|
|
>
|
|
Kembali
|
|
</button>
|
|
</Link>
|
|
{handleDelete && (
|
|
<button
|
|
type="button"
|
|
onClick={() => handleSave(savedArray)}
|
|
className="rounded bg-blue-600 text-white px-4 py-2 hover:bg-blue-700 transition"
|
|
>
|
|
Simpan
|
|
</button>
|
|
)}
|
|
</div>
|
|
</form>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ImportKnowledgeBase;
|