Add duplicate button to ProductList

This commit is contained in:
2025-05-28 13:51:14 +02:00
parent 1a8c0587ee
commit 56c3c16f6d
2 changed files with 37 additions and 6 deletions

View File

@@ -8,6 +8,7 @@ interface AddProductModalProps {
onClose: () => void; onClose: () => void;
onProductAdded: () => void; onProductAdded: () => void;
editProduct?: Product | null; editProduct?: Product | null;
duplicateProduct?: Product | null;
} }
interface ProductFormData { interface ProductFormData {
@@ -19,7 +20,7 @@ interface ProductFormData {
weight_unit: string; weight_unit: string;
} }
const AddProductModal: React.FC<AddProductModalProps> = ({ isOpen, onClose, onProductAdded, editProduct }) => { const AddProductModal: React.FC<AddProductModalProps> = ({ isOpen, onClose, onProductAdded, editProduct, duplicateProduct }) => {
const [formData, setFormData] = useState<ProductFormData>({ const [formData, setFormData] = useState<ProductFormData>({
name: '', name: '',
category_id: undefined, category_id: undefined,
@@ -64,7 +65,7 @@ const AddProductModal: React.FC<AddProductModalProps> = ({ isOpen, onClose, onPr
} }
}; };
// Populate form when editing // Populate form when editing or duplicating
useEffect(() => { useEffect(() => {
if (editProduct) { if (editProduct) {
setFormData({ setFormData({
@@ -75,6 +76,15 @@ const AddProductModal: React.FC<AddProductModalProps> = ({ isOpen, onClose, onPr
weight: editProduct.weight, weight: editProduct.weight,
weight_unit: editProduct.weight_unit weight_unit: editProduct.weight_unit
}); });
} else if (duplicateProduct) {
setFormData({
name: duplicateProduct.name,
category_id: duplicateProduct.category_id,
brand_id: duplicateProduct.brand_id,
organic: duplicateProduct.organic,
weight: duplicateProduct.weight,
weight_unit: duplicateProduct.weight_unit
});
} else { } else {
// Reset form for adding new product // Reset form for adding new product
setFormData({ setFormData({
@@ -87,7 +97,7 @@ const AddProductModal: React.FC<AddProductModalProps> = ({ isOpen, onClose, onPr
}); });
} }
setError(''); setError('');
}, [editProduct, isOpen]); }, [editProduct, duplicateProduct, isOpen]);
const handleSubmit = useCallback(async (e: React.FormEvent) => { const handleSubmit = useCallback(async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
@@ -187,7 +197,7 @@ const AddProductModal: React.FC<AddProductModalProps> = ({ isOpen, onClose, onPr
<div className="mt-3"> <div className="mt-3">
<div className="flex justify-between items-center mb-4"> <div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-medium text-gray-900"> <h3 className="text-lg font-medium text-gray-900">
{editProduct ? 'Edit Product' : 'Add New Product'} {editProduct ? 'Edit Product' : duplicateProduct ? 'Duplicate Product' : 'Add New Product'}
</h3> </h3>
<button <button
onClick={onClose} onClick={onClose}
@@ -324,8 +334,8 @@ const AddProductModal: React.FC<AddProductModalProps> = ({ isOpen, onClose, onPr
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-md disabled:opacity-50 disabled:cursor-not-allowed" className="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-md disabled:opacity-50 disabled:cursor-not-allowed"
> >
{loading {loading
? (editProduct ? 'Updating...' : 'Adding...') ? (editProduct ? 'Updating...' : duplicateProduct ? 'Duplicating...' : 'Adding...')
: (editProduct ? 'Update Product' : 'Add Product') : (editProduct ? 'Update Product' : duplicateProduct ? 'Duplicate Product' : 'Add Product')
} }
</button> </button>
</div> </div>

View File

@@ -14,6 +14,7 @@ const ProductList: React.FC = () => {
const [editingProduct, setEditingProduct] = useState<Product | null>(null); const [editingProduct, setEditingProduct] = useState<Product | null>(null);
const [deletingProduct, setDeletingProduct] = useState<Product | null>(null); const [deletingProduct, setDeletingProduct] = useState<Product | null>(null);
const [deleteLoading, setDeleteLoading] = useState(false); const [deleteLoading, setDeleteLoading] = useState(false);
const [duplicatingProduct, setDuplicatingProduct] = useState<Product | null>(null);
const [sortField, setSortField] = useState<string>('name'); const [sortField, setSortField] = useState<string>('name');
const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc'); const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc');
@@ -46,6 +47,11 @@ const ProductList: React.FC = () => {
setIsModalOpen(true); setIsModalOpen(true);
}; };
const handleDuplicate = (product: Product) => {
setDuplicatingProduct(product);
setIsModalOpen(true);
};
const handleDelete = (product: Product) => { const handleDelete = (product: Product) => {
setDeletingProduct(product); setDeletingProduct(product);
}; };
@@ -73,6 +79,7 @@ const ProductList: React.FC = () => {
const handleCloseModal = () => { const handleCloseModal = () => {
setIsModalOpen(false); setIsModalOpen(false);
setEditingProduct(null); setEditingProduct(null);
setDuplicatingProduct(null);
}; };
const handleCloseDeleteModal = () => { const handleCloseDeleteModal = () => {
@@ -176,6 +183,7 @@ const ProductList: React.FC = () => {
<button <button
onClick={() => { onClick={() => {
setEditingProduct(null); setEditingProduct(null);
setDuplicatingProduct(null);
setIsModalOpen(true); setIsModalOpen(true);
}} }}
className="w-full sm:w-auto bg-blue-500 hover:bg-blue-700 text-white font-bold py-3 sm:py-2 px-4 rounded text-base sm:text-sm" className="w-full sm:w-auto bg-blue-500 hover:bg-blue-700 text-white font-bold py-3 sm:py-2 px-4 rounded text-base sm:text-sm"
@@ -271,6 +279,12 @@ const ProductList: React.FC = () => {
> >
Edit Edit
</button> </button>
<button
onClick={() => handleDuplicate(product)}
className="text-green-600 hover:text-green-900 mr-3"
>
Duplicate
</button>
<button <button
onClick={() => handleDelete(product)} onClick={() => handleDelete(product)}
className="text-red-600 hover:text-red-900" className="text-red-600 hover:text-red-900"
@@ -317,6 +331,12 @@ const ProductList: React.FC = () => {
> >
Edit Edit
</button> </button>
<button
onClick={() => handleDuplicate(product)}
className="flex-1 text-center py-2 px-4 border border-green-300 text-green-600 hover:bg-green-50 rounded-md text-sm font-medium"
>
Duplicate
</button>
<button <button
onClick={() => handleDelete(product)} onClick={() => handleDelete(product)}
className="flex-1 text-center py-2 px-4 border border-red-300 text-red-600 hover:bg-red-50 rounded-md text-sm font-medium" className="flex-1 text-center py-2 px-4 border border-red-300 text-red-600 hover:bg-red-50 rounded-md text-sm font-medium"
@@ -336,6 +356,7 @@ const ProductList: React.FC = () => {
onClose={handleCloseModal} onClose={handleCloseModal}
onProductAdded={handleProductAdded} onProductAdded={handleProductAdded}
editProduct={editingProduct} editProduct={editingProduct}
duplicateProduct={duplicatingProduct}
/> />
<ConfirmDeleteModal <ConfirmDeleteModal