diff --git a/app/admin/products/page.tsx b/app/admin/products/page.tsx index 2317014..9e81d6e 100644 --- a/app/admin/products/page.tsx +++ b/app/admin/products/page.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useState, useEffect } from 'react'; +import { useState, useEffect, useCallback, useRef } from 'react'; import { useAuth } from '@/contexts/AuthContext'; import { packagesApi } from '@/lib/api/packages'; import { productsApi } from '@/lib/api/products'; @@ -17,27 +17,26 @@ export default function ProductsPage() { const [products, setProducts] = useState([]); const [selectedProduct, setSelectedProduct] = useState(null); const [isLoading, setIsLoading] = useState(false); + const [isLoadingPackages, setIsLoadingPackages] = useState(false); const [isFormVisible, setIsFormVisible] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); - // Load packages on mount + // Use refs to track initial loads and prevent duplicate calls + const initialLoadRef = useRef(false); + const prevPackageRef = useRef(null); + + // Load packages on mount - only once useEffect(() => { - if (token) { + if (token && !initialLoadRef.current) { + initialLoadRef.current = true; loadPackages(); } }, [token]); - // Load products when package is selected - useEffect(() => { - if (selectedPackage && token) { - loadProducts(selectedPackage.name!); - } else { - setProducts([]); - } - }, [selectedPackage, token]); - const loadPackages = async () => { + setIsLoadingPackages(true); + setError(null); try { const data = await packagesApi.getAllPackages(token!); setPackages(data); @@ -46,13 +45,24 @@ export default function ProductsPage() { } } catch (err) { setError('خطا در دریافت لیست پکیج‌ها'); + } finally { + setIsLoadingPackages(false); } }; - const loadProducts = async (packageName: string) => { + const loadProducts = useCallback(async (packageName: string, force = false) => { + // Prevent duplicate loads of the same package + if (!force && prevPackageRef.current === packageName) { + console.log('Skipping duplicate load for package:', packageName); + return; + } + setIsLoading(true); setError(null); + prevPackageRef.current = packageName; + try { + console.log('Loading products for package:', packageName); const data = await productsApi.getProducts(packageName, token!); setProducts(data); } catch (err) { @@ -60,13 +70,24 @@ export default function ProductsPage() { } finally { setIsLoading(false); } - }; + }, [token]); + + // Load products when package changes - with proper dependency + useEffect(() => { + if (selectedPackage?.name && token) { + loadProducts(selectedPackage.name); + } else { + setProducts([]); + } + }, [selectedPackage?.name, token, loadProducts]); const handlePackageChange = (e: React.ChangeEvent) => { const pkg = packages.find(p => p.name === e.target.value); setSelectedPackage(pkg || null); setIsFormVisible(false); setSelectedProduct(null); + setError(null); + setSuccess(null); }; const handleCreate = () => { @@ -93,7 +114,11 @@ export default function ProductsPage() { try { await productsApi.deleteProduct(selectedPackage.name!, product.id, token!); setSuccess('محصول با موفقیت حذف شد'); - await loadProducts(selectedPackage.name!); + // Force reload products after delete + if (selectedPackage.name) { + prevPackageRef.current = null; // Reset ref to force load + await loadProducts(selectedPackage.name, true); + } } catch (err) { setError(err instanceof Error ? err.message : 'خطا در حذف محصول'); } finally { @@ -119,7 +144,12 @@ export default function ProductsPage() { setSuccess('محصول با موفقیت ایجاد شد'); } - await loadProducts(selectedPackage.name!); + // Force reload products after create/update + if (selectedPackage.name) { + prevPackageRef.current = null; // Reset ref to force load + await loadProducts(selectedPackage.name, true); + } + setIsFormVisible(false); setSelectedProduct(null); } catch (err) { @@ -154,13 +184,18 @@ export default function ProductsPage() { id="package" value={selectedPackage?.name || ''} onChange={handlePackageChange} - className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" + disabled={isLoadingPackages} + className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm disabled:opacity-50" > - {packages.map((pkg) => ( - - ))} + {isLoadingPackages ? ( + + ) : ( + packages.map((pkg) => ( + + )) + )} @@ -184,7 +219,8 @@ export default function ProductsPage() {