import { useEffect, useState } from 'react' import { Link, useNavigate, useSearchParams } from 'react-router-dom' import { Plus, RotateCcw, Search, Sparkles } from 'lucide-react' import { ProductCard } from '../components/ProductCard' import { AddProductByAiModal } from '../components/AddProductByAiModal' import { Pagination } from '../components/Pagination' import { ConfirmDeleteModal } from '../components/ConfirmDeleteModal' import { ProductVariantsModal } from '../components/ProductVariantsModal' import { ProductTechnicalInfoModal } from '../components/ProductTechnicalInfoModal' import { ProductCommentsModal } from '../components/ProductCommentsModal' import { Breadcrumbs } from '../components/Breadcrumbs' import { useT } from '../i18n/useT' import { ApiError } from '../lib/api' import { deleteProduct, listProducts, PRODUCTS_PER_PAGE, } from '../services/productService' import type { Product } from '../types/product' import pageStyles from '../components/PageContent.module.css' import filterStyles from '../components/ListFiltersPanel.module.css' import styles from './MyProductsPage.module.css' import aiStyles from '../styles/ai.module.css' function readListQuery(searchParams: URLSearchParams) { const name = searchParams.get('q')?.trim() ?? '' const pageRaw = Number(searchParams.get('page')) const page = Number.isFinite(pageRaw) && pageRaw >= 1 ? Math.floor(pageRaw) : 1 return { name, page } } export function MyProductsPage() { const t = useT() const navigate = useNavigate() const [searchParams, setSearchParams] = useSearchParams() const { name: appliedName, page: currentPage } = readListQuery(searchParams) const [products, setProducts] = useState([]) const [totalProducts, setTotalProducts] = useState(0) const [isLoading, setIsLoading] = useState(true) const [isDeleting, setIsDeleting] = useState(false) const [error, setError] = useState('') const [variantCounts, setVariantCounts] = useState>({}) const [commentCounts, setCommentCounts] = useState>({}) const [deleteTarget, setDeleteTarget] = useState<{ id: string; name: string } | null>(null) const [variantsTarget, setVariantsTarget] = useState<{ id: string name: string categoryId: string } | null>(null) const [commentsTarget, setCommentsTarget] = useState<{ id: string; name: string } | null>(null) const [technicalTarget, setTechnicalTarget] = useState<{ id: string name: string categoryId: string } | null>(null) const [aiModalOpen, setAiModalOpen] = useState(false) const [draftName, setDraftName] = useState(appliedName) const totalPages = Math.max(1, Math.ceil(totalProducts / PRODUCTS_PER_PAGE)) useEffect(() => { setDraftName(appliedName) }, [appliedName]) useEffect(() => { const controller = new AbortController() void loadProducts(currentPage, controller.signal) return () => controller.abort() }, [currentPage, appliedName]) function writeListQuery(name: string, page: number) { const next = new URLSearchParams() if (name) next.set('q', name) if (page > 1) next.set('page', String(page)) setSearchParams(next, { replace: true }) } async function loadProducts(page: number, signal?: AbortSignal) { setIsLoading(true) setError('') try { const data = await listProducts( page, PRODUCTS_PER_PAGE, signal, appliedName ? { name: appliedName } : undefined, ) setProducts(data.items) setTotalProducts(data.total) setVariantCounts( Object.fromEntries(data.items.map((product) => [product.id, product.variantCount ?? 0])), ) } catch (err) { if (err instanceof DOMException && err.name === 'AbortError') return if (err instanceof ApiError) { setError(err.message) } else { setError(t('products.list.errorLoad')) } } finally { setIsLoading(false) } } function handleEdit(id: string) { navigate(`/products/edit/${id}`) } function handleComments(id: string) { const product = products.find((p) => p.id === id) if (product) { setCommentsTarget({ id, name: product.nameFa || product.nameEn }) } } function handleVariations(id: string) { const product = products.find((p) => p.id === id) if (product) { setVariantsTarget({ id, name: product.nameFa || product.nameEn, categoryId: product.categoryId, }) } } function handleTechnicalInfo(id: string) { const product = products.find((p) => p.id === id) if (product) { setTechnicalTarget({ id, name: product.nameFa || product.nameEn, categoryId: product.categoryId, }) } } function handleRemoveRequest(id: string) { const product = products.find((p) => p.id === id) if (product) { setDeleteTarget({ id, name: product.nameFa || product.nameEn }) } } async function confirmDelete() { if (!deleteTarget) return setIsDeleting(true) setError('') try { await deleteProduct(deleteTarget.id) const nextTotal = totalProducts - 1 const nextTotalPages = Math.max(1, Math.ceil(nextTotal / PRODUCTS_PER_PAGE)) const nextPage = currentPage > nextTotalPages ? nextTotalPages : currentPage setDeleteTarget(null) writeListQuery(appliedName, nextPage) await loadProducts(nextPage) } catch (err) { if (err instanceof ApiError) { setError(err.message) } else { setError(t('products.list.errorDelete')) } } finally { setIsDeleting(false) } } function handlePageChange(page: number) { writeListQuery(appliedName, page) window.scrollTo({ top: 0, behavior: 'smooth' }) } function applyFilters() { writeListQuery(draftName.trim(), 1) } function clearFilters() { setDraftName('') writeListQuery('', 1) } function handleCommentCountChange(count: number) { if (!commentsTarget) return setCommentCounts((prev) => ({ ...prev, [commentsTarget.id]: count, })) } return (

{t('title.myProducts')}

{t('products.list.subtitle', { count: totalProducts })}

{t('products.list.filters')}
{ e.preventDefault(); applyFilters() }}>
setDraftName(e.target.value)} placeholder={t('products.list.filterNamePlaceholder')} aria-label={t('products.list.filterName')} disabled={isLoading} />
{error && (
{error}
)} {isLoading ? (

{t('products.list.loading')}

) : products.length === 0 ? (

{appliedName ? t('products.list.emptyFiltered') : t('products.list.empty')}

) : ( <>
{products.map((product) => ( {}} onComments={handleComments} onTechnicalInfo={handleTechnicalInfo} onVariations={handleVariations} onRemove={handleRemoveRequest} /> ))}
{t('products.list.pagination', { page: currentPage, totalPages, perPage: PRODUCTS_PER_PAGE, total: totalProducts, })}
)} !isDeleting && setDeleteTarget(null)} /> {variantsTarget && ( setVariantsTarget(null)} onVariantsChange={(count) => { setVariantCounts((prev) => ({ ...prev, [variantsTarget.id]: count, })) }} /> )} {commentsTarget && ( setCommentsTarget(null)} onCountChange={handleCommentCountChange} /> )} {technicalTarget && ( setTechnicalTarget(null)} /> )} setAiModalOpen(false)} onCreated={(productId) => navigate(`/products/edit/${productId}`)} />
) }