groceries/frontend/src/components/GroceryList.tsx
2025-05-26 21:55:49 +02:00

162 lines
5.7 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { Grocery } from '../types';
import { groceryApi } from '../services/api';
import AddGroceryModal from './AddGroceryModal';
const GroceryList: React.FC = () => {
const [groceries, setGroceries] = useState<Grocery[]>([]);
const [loading, setLoading] = useState(true);
const [message, setMessage] = useState('');
const [isModalOpen, setIsModalOpen] = useState(false);
const [editingGrocery, setEditingGrocery] = useState<Grocery | null>(null);
useEffect(() => {
fetchGroceries();
}, []);
const fetchGroceries = async () => {
try {
setLoading(true);
const response = await groceryApi.getAll();
setGroceries(response.data);
} catch (error) {
console.error('Error fetching groceries:', error);
setMessage('Error loading groceries. Please try again.');
} finally {
setLoading(false);
}
};
const handleDelete = async (id: number) => {
if (window.confirm('Are you sure you want to delete this grocery?')) {
try {
await groceryApi.delete(id);
setMessage('Grocery deleted successfully!');
fetchGroceries();
setTimeout(() => setMessage(''), 3000);
} catch (error: any) {
console.error('Error deleting grocery:', error);
if (error.response?.status === 400) {
setMessage('Cannot delete grocery: products are still associated with this grocery.');
} else {
setMessage('Error deleting grocery. Please try again.');
}
setTimeout(() => setMessage(''), 5000);
}
}
};
const handleEdit = (grocery: Grocery) => {
setEditingGrocery(grocery);
setIsModalOpen(true);
};
const handleModalClose = () => {
setIsModalOpen(false);
setEditingGrocery(null);
fetchGroceries();
};
if (loading) {
return (
<div className="flex justify-center items-center h-64">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500"></div>
</div>
);
}
return (
<div className="max-w-4xl mx-auto">
<div className="bg-white shadow rounded-lg">
<div className="px-4 py-5 sm:p-6">
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg leading-6 font-medium text-gray-900">
Groceries
</h3>
<button
onClick={() => setIsModalOpen(true)}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
Add Grocery
</button>
</div>
{message && (
<div className={`mb-4 p-4 rounded-md ${
message.includes('Error') || message.includes('Cannot')
? 'bg-red-50 text-red-700'
: 'bg-green-50 text-green-700'
}`}>
{message}
</div>
)}
{groceries.length === 0 ? (
<div className="text-center py-8">
<p className="text-gray-500">No groceries found. Add your first grocery!</p>
</div>
) : (
<div className="overflow-hidden shadow ring-1 ring-black ring-opacity-5 md:rounded-lg">
<table className="min-w-full divide-y divide-gray-300">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Name
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Category
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Created
</th>
<th className="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
Actions
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{groceries.map((grocery) => (
<tr key={grocery.id} className="hover:bg-gray-50">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
{grocery.name}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{grocery.category.name}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{new Date(grocery.created_at).toLocaleDateString()}
</td>
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button
onClick={() => handleEdit(grocery)}
className="text-indigo-600 hover:text-indigo-900 mr-4"
>
Edit
</button>
<button
onClick={() => handleDelete(grocery.id)}
className="text-red-600 hover:text-red-900"
>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
</div>
{isModalOpen && (
<AddGroceryModal
grocery={editingGrocery}
onClose={handleModalClose}
/>
)}
</div>
);
};
export default GroceryList;