import React, { useState, useEffect } from 'react'; import { Plus, Edit2, Trash2, Loader2, Save, X } from 'lucide-react'; import DeleteConfirmationModal from '../Components/DeleteConfirmationModal'; export default function MasterTable({ type, onNotify, btnLabel }) { const [data, setData] = useState([]); const [loading, setLoading] = useState(true); const [isModalOpen, setIsModalOpen] = useState(false); const [editingItem, setEditingItem] = useState(null); const [formData, setFormData] = useState({ name: '', status: 'Active' }); const [isSaving, setIsSaving] = useState(false); // Delete Confirmation State const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [itemToDelete, setItemToDelete] = useState(null); const [isDeleting, setIsDeleting] = useState(false); useEffect(() => { fetchData(); }, [type]); const fetchData = async () => { setLoading(true); try { const response = await fetch(`/api/masters/${type}`); const result = await response.json(); setData(result); } catch (error) { console.error('Error fetching data:', error); onNotify('Failed to fetch data.', 'error'); } finally { setLoading(false); } }; const handleOpenModal = (item = null) => { if (item) { setEditingItem(item); setFormData({ name: item.name, status: item.status }); } else { setEditingItem(null); setFormData({ name: '', status: 'Active' }); } setIsModalOpen(true); }; const handleSave = async (e) => { e.preventDefault(); setIsSaving(true); const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); try { const url = editingItem ? `/api/masters/${type}/${editingItem.id}` : `/api/masters/${type}`; const method = editingItem ? 'PUT' : 'POST'; const response = await fetch(url, { method, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': csrfToken }, body: JSON.stringify(formData) }); if (response.ok) { onNotify(`${editingItem ? 'Updated' : 'Added'} successfully!`, 'success'); setIsModalOpen(false); fetchData(); } else { const err = await response.json().catch(() => ({})); onNotify(err.message || 'Error occurred while saving.', 'error'); } } catch (error) { onNotify('Server error.', 'error'); } finally { setIsSaving(false); } }; const handleToggleStatus = async (item) => { const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); const newStatus = item.status === 'Active' ? 'Inactive' : 'Active'; try { const response = await fetch(`/api/masters/${type}/${item.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': csrfToken }, body: JSON.stringify({ ...item, status: newStatus }) }); if (response.ok) { setData(data.map(i => i.id === item.id ? { ...i, status: newStatus } : i)); } } catch (error) { onNotify('Failed to update status.', 'error'); } }; const handleDelete = async () => { if (!itemToDelete) return; setIsDeleting(true); const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); try { const response = await fetch(`/api/masters/${type}/${itemToDelete}`, { method: 'DELETE', headers: { 'X-CSRF-TOKEN': csrfToken } }); if (response.ok) { onNotify('Deleted successfully!', 'success'); setIsDeleteModalOpen(false); setItemToDelete(null); fetchData(); } else { const err = await response.json().catch(() => ({})); onNotify(err.message || 'Failed to delete.', 'error'); } } catch (error) { onNotify('Failed to delete.', 'error'); } finally { setIsDeleting(false); } }; const confirmDelete = (id) => { setItemToDelete(id); setIsDeleteModalOpen(true); }; if (loading) return (
Loading data...
); return (
{data.length === 0 ? ( ) : data.map((item) => ( ))}
Name Status Actions
No records found.
{item.name}
{item.status}
{item.name !== 'Product Sale' && ( )}
{/* Modal */} {isModalOpen && (

{editingItem ? `Edit ${btnLabel}` : `Add New ${btnLabel}`}

setFormData({ ...formData, name: e.target.value })} className="w-full px-4 py-3 bg-gray-50 border border-gray-100 rounded-2xl focus:outline-none focus:ring-2 focus:ring-red-500/20 focus:border-red-500 transition-all text-gray-900 placeholder:text-gray-400" placeholder={`Enter ${btnLabel.toLowerCase()} name`} />
Set as Active
)} setIsDeleteModalOpen(false)} onConfirm={handleDelete} />
); }