MIF_E31212365/resources/js/Pages/Admin/ModuleDetail.jsx

314 lines
13 KiB
JavaScript

import React, { useState } from "react";
import AdminLayout from "./Layout/AdminLayout";
import { FaPlus, FaTrash } from "react-icons/fa6";
import Pagination from "../../Components/Pagination";
import { FaEdit } from "react-icons/fa";
import { IoBookOutline } from "react-icons/io5";
import { Link } from "@inertiajs/react";
import GenerateUrl from "../../Utils/GenerateUrl";
import useSWR, { mutate } from "swr";
import { fetcher } from "../../Utils/Fetcher";
import { debounce } from "../../Utils/Debounce";
import NoDataTable from "../../Components/NoDataTable";
import Swal from "sweetalert2";
import HitApi from "../../Utils/HitApi";
import CustomModal from "../../Components/CustomModal";
import DeleteData from "../../Utils/DeleteData";
const ModuleDetail = (props) => {
const [page, setPage] = useState(1);
const [search, setSearch] = useState("");
const URL = GenerateUrl(
"/api/v1/module",
`id=${props.id}`,
`page=${page}`,
`search=${encodeURIComponent(search)}`
);
const { data, error, isLoading } = useSWR(URL, fetcher);
const handleSearch = debounce((term) => {
setSearch(term);
}, 500);
const handleChangeSearch = (e) => {
const { value } = e.target;
setPage(1);
handleSearch(value);
};
const [showModal, setShowModal] = useState(false);
const [form, setForm] = useState({
name: "",
description: "",
option: "tambah",
});
const clearForm = () => {
setForm({
name: "",
description: "",
option: "tambah",
});
};
const myState = {
showModal,
setShowModal,
URL,
form,
setForm,
clearForm,
props,
};
return (
<AdminLayout title="Materi">
<Modal state={myState} />
<div className="w-full h-full flex flex-col px-3 py-1">
<div className="text-xs breadcrumbs mb-2">
<ul>
<li>
<Link href="/admin/materi">SD</Link>
</li>
<li>
<a>Materi</a>
</li>
</ul>
</div>
<div className="flex items-center w-full gap-4 mb-3">
<label className="input input-bordered flex w-full items-center gap-2 max-w-[200px] md:max-w-[400px]">
<input
type="text"
className="w-full"
placeholder="Search"
onChange={handleChangeSearch}
/>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
className="w-4 h-4 opacity-70"
>
<path
fillRule="evenodd"
d="M9.965 11.026a5 5 0 1 1 1.06-1.06l2.755 2.754a.75.75 0 1 1-1.06 1.06l-2.755-2.754ZM10.5 7a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Z"
clipRule="evenodd"
/>
</svg>
</label>
<div className="flex-1 justify-end flex w-full">
<button
onClick={() => {
clearForm();
setShowModal(true);
}}
className="btn btn-primary w-fit"
>
<FaPlus />
<p className="hidden md:flex">Tambah</p>
</button>
</div>
</div>
<NoDataTable
isLoading={isLoading}
isError={error}
message={error ? "Failed get data" : "No data"}
isEmpty={
data && data.result.data.length == 0 ? true : false
}
>
{data && (
<>
<div className="overflow-x-auto">
<table className="table">
{/* head */}
<thead>
<tr>
<th></th>
<th>Name</th>
<th>Deskripsi</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
{data.result.data.map((item, index) => (
<tr
key={index}
className="hover border-t-2"
>
<th>
{data.result.from + index}
</th>
<td>{item.name}</td>
<td>{item.description}</td>
<td>
<div className="flex gap-2 items-center">
<Link
href={`/admin/materi/${item.id}`}
>
<button className="btn btn-sm btn-warning">
<IoBookOutline
size={15}
/>
</button>
</Link>
<button
onClick={() => {
clearForm();
setForm({
id: item.id,
name: item.name,
description:
item.description,
option: "edit",
});
setShowModal(
true
);
}}
className="btn btn-sm btn-accent"
>
<FaEdit size={15} />
</button>
<button
onClick={() => {
DeleteData(
`/api/v1/module?id=${item.id}`,
() => {
mutate(
URL
);
}
);
}}
className="btn btn-sm btn-error"
>
<FaTrash
size={15}
/>
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
<Pagination
total={data.result.total}
showItem={data.result.data.length}
page={page}
setPage={setPage}
limit={data.result.per_page}
/>
</>
)}
</NoDataTable>
</div>
</AdminLayout>
);
};
const Modal = ({ state }) => {
const { form, setForm, clearForm, props } = state;
// handle change form
const handleChange = (e) => {
const { name, value } = e.target;
setForm((prev) => ({ ...prev, [name]: value }));
};
const handleSubmit = (e) => {
e.preventDefault();
Swal.fire({
title: "Konfirmasi",
text:
form.option == "tambah"
? "Apakah anda yakin ingin menambahkan data?"
: "Apakah anda yakin ingin mengubah data?",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: "Ya",
}).then((result) => {
if (result.isConfirmed) {
Swal.fire({
title: "Loading",
html: '<div class="body-loading"><div class="loadingspinner"></div></div>', // add html attribute if you want or remove
allowOutsideClick: false,
showConfirmButton: false,
});
HitApi({
url: "/api/v1/module",
method: form.option == "tambah" ? "POST" : "PUT",
body: { ...form, id_category: props.id },
onSuccess: () => {
Swal.fire(
"Berhasil",
form.option == "tambah"
? "Data berhasil ditambahkan"
: "Data berhasil diubah",
"success"
);
clearForm();
state.setShowModal(false);
mutate(state.URL);
},
onError: () => {
// Swal.fire("Gagal", "Data gagal ditambahkan", "error");
},
});
}
});
};
return (
<CustomModal
show={state.showModal}
setShow={state.setShowModal}
title={"Module"}
>
<form
onSubmit={handleSubmit}
className="w-full flex flex-col gap-2"
>
<label className="form-control w-full">
<div className="label">
<span className="label-text">Nama</span>
</div>
<input
value={form.name}
onChange={handleChange}
name="name"
type="text"
placeholder=""
className="input input-bordered w-full"
/>
</label>
<label className="form-control w-full">
<div className="label">
<span className="label-text">Deskripsi</span>
</div>
<textarea
className="textarea textarea-bordered h-24"
placeholder=""
name="description"
value={form.description}
onChange={handleChange}
></textarea>
</label>
<button className="btn btn-primary mb-2 mt-2">Save</button>
</form>
</CustomModal>
);
};
export default ModuleDetail;