209 lines
11 KiB
JavaScript
209 lines
11 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import { Head, usePage } from '@inertiajs/react';
|
|
import { useDispatch } from 'react-redux';
|
|
import { setPageTitle } from '@/Components/features/common/headerSlice';
|
|
import ModalInput from '@/Components/ModalInput';
|
|
import DeleteButton from '@/Components/DeleteButton';
|
|
import { UserGroupIcon } from '@heroicons/react/24/outline';
|
|
|
|
export default function IndexSantri({ santri, fields, options }) {
|
|
const [selectedSantri, setSelectedSantri] = useState(null);
|
|
const [isDeleteOpen, setDeleteOpen] = useState(false);
|
|
const [searchTerm, setSearchTerm] = useState('');
|
|
const [filteredSantri, setFilteredSantri] = useState([]);
|
|
const dispatch = useDispatch();
|
|
const { flash } = usePage().props;
|
|
|
|
const openDeleteModal = (item) => {
|
|
setSelectedSantri(item);
|
|
setDeleteOpen(true);
|
|
};
|
|
|
|
useEffect(() => {
|
|
dispatch(setPageTitle("Data Santri"));
|
|
}, [dispatch]);
|
|
|
|
useEffect(() => {
|
|
if (santri?.data) {
|
|
const filtered = santri.data.filter(item =>
|
|
item.nama.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
item.nis.toString().includes(searchTerm)
|
|
);
|
|
setFilteredSantri(filtered);
|
|
}
|
|
}, [searchTerm, santri]);
|
|
|
|
const handleSearch = (e) => {
|
|
setSearchTerm(e.target.value);
|
|
};
|
|
|
|
return (
|
|
<div>
|
|
<Head title="Data Santri" />
|
|
<div className="card bg-base-100 shadow-xl">
|
|
<div className="card-body">
|
|
<div className="flex items-center mb-2">
|
|
<div className="bg-gradient-to-tr from-blue-400 to-blue-600 p-3 rounded-lg mr-3">
|
|
<UserGroupIcon className="h-6 w-6 text-white" />
|
|
</div>
|
|
<h1 className="text-2xl font-bold">Data Santri</h1>
|
|
<div className="ml-auto">
|
|
<span className="text-gray-700">Overview</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex justify-between items-center mb-4">
|
|
<div className="form-control">
|
|
<div className="input-group">
|
|
<input
|
|
type="text"
|
|
placeholder="Search..."
|
|
className="input input-bordered"
|
|
value={searchTerm}
|
|
onChange={handleSearch}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<ModalInput
|
|
fields={fields}
|
|
options={options}
|
|
tableName="users"
|
|
initialData={selectedSantri}
|
|
onClose={() => setSelectedSantri(null)}
|
|
/>
|
|
<label htmlFor="modal_input" className="btn btn-success text-white" onClick={() => setSelectedSantri(null)}>Tambah Santri</label>
|
|
</div>
|
|
|
|
<div className="overflow-x-auto">
|
|
<table className="table table-zebra w-full">
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>NIS</th>
|
|
<th>Status</th>
|
|
<th>Alamat</th>
|
|
<th>Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{filteredSantri.length > 0 ? (
|
|
filteredSantri.map((item, i) => (
|
|
<tr key={i}>
|
|
<td>
|
|
<div className="flex items-center space-x-3">
|
|
<div className="avatar">
|
|
<div className="mask mask-squircle w-12 h-12">
|
|
<img src={`https://ui-avatars.com/api/?name=${item.nama}`} alt="Avatar" />
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div className="font-bold">{item.nama}</div>
|
|
<div className="text-sm opacity-50">{item.level === 1 ? 'Admin' : 'User'}</div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td>{item.nis}</td>
|
|
<td>
|
|
<div className={`badge ${item.status_santri === 'aktif' ? 'badge-success' : 'badge-warning'} gap-2 text-white`}>
|
|
{item.status_santri || "Open"}
|
|
</div>
|
|
</td>
|
|
<td>{item.alamat || "-"}</td>
|
|
<td>
|
|
<div className="flex space-x-2">
|
|
<button
|
|
className="btn btn-sm btn-primary text-white"
|
|
onClick={() => {
|
|
setSelectedSantri(item);
|
|
document.getElementById('modal_input').checked = true;
|
|
}}
|
|
>
|
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
|
|
</svg>
|
|
</button>
|
|
<button
|
|
className="btn btn-sm btn-error text-white"
|
|
onClick={() => openDeleteModal(item)}
|
|
>
|
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
))
|
|
) : (
|
|
<tr>
|
|
<td colSpan="5" className="text-center">Tidak ada data santri.</td>
|
|
</tr>
|
|
)}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div className="flex justify-center mt-4">
|
|
{santri.current_page > 1 && (
|
|
<button
|
|
className="btn btn-sm mx-1"
|
|
onClick={() => (window.location.href = `?page=${santri.current_page - 1}`)}
|
|
>
|
|
«
|
|
</button>
|
|
)}
|
|
|
|
{Array.from({ length: santri.last_page }, (_, i) => i + 1)
|
|
.filter((page) =>
|
|
page === 1 ||
|
|
page === santri.last_page ||
|
|
Math.abs(page - santri.current_page) <= 2
|
|
)
|
|
.map((page, index, array) => {
|
|
const prevPage = array[index - 1];
|
|
const showEllipsis = prevPage && page - prevPage > 1;
|
|
|
|
return (
|
|
<React.Fragment key={page}>
|
|
{showEllipsis && (
|
|
<span className="btn btn-sm mx-1 pointer-events-none">...</span>
|
|
)}
|
|
<button
|
|
className={`btn btn-sm mx-1 ${santri.current_page === page
|
|
? 'btn-active btn-primary text-white'
|
|
: ''
|
|
}`}
|
|
onClick={() => {
|
|
window.location.href = `?page=${page}`;
|
|
}}
|
|
>
|
|
{page}
|
|
</button>
|
|
</React.Fragment>
|
|
);
|
|
})}
|
|
|
|
{/* Tombol terakhir */}
|
|
{santri.current_page < santri.last_page && (
|
|
<button
|
|
className="btn btn-sm mx-1"
|
|
onClick={() => (window.location.href = `?page=${santri.current_page + 1}`)}
|
|
>
|
|
»
|
|
</button>
|
|
)}
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<DeleteButton
|
|
isOpen={isDeleteOpen}
|
|
onClose={() => setDeleteOpen(false)}
|
|
item={selectedSantri}
|
|
tableName="users"
|
|
/>
|
|
</div>
|
|
);
|
|
}
|