import React, { useState, useMemo } from 'react' import { createFileRoute, useNavigate } from '@tanstack/react-router' import { Image as ImageIcon, Eye, Pencil, Package } from 'lucide-react' import { AppContainer, p as MyText, MyButton, SearchBar, MyFlatList } from 'web-components' import { trpc } from '@/lib/trpc-client' import { useManualRefresh, useMarkDataFetchers } from '@/lib/refresh-context' import type { AdminSku } from '@packages/shared' export const Route = createFileRoute('/dashboard/products')({ component: Products, }) type FilterType = 'all' | 'in-stock' | 'out-of-stock' type SerializedAdminSku = Omit & { createdAt: string | Date } function getDefaultSku(product: { skus: SerializedAdminSku[] }): SerializedAdminSku | null { return product.skus?.[0] ?? null } function FilterButton({ filter, label, count, activeFilter, onSelect }: { filter: FilterType, label: string, count: number, activeFilter: FilterType, onSelect: (f: FilterType) => void }) { return ( ) } function Products() { const navigate = useNavigate() const [searchTerm, setSearchTerm] = useState('') const [activeFilter, setActiveFilter] = useState('all') const { data: productsData, isLoading, error, refetch } = trpc.admin.product.getProducts.useQuery() useManualRefresh(refetch) useMarkDataFetchers(() => { refetch() }) const products = productsData?.products || [] const filteredProducts = useMemo(() => { return products.filter((product) => { const defaultSku = getDefaultSku(product) const matchesSearch = product.name.toLowerCase().includes(searchTerm.toLowerCase()) || (product.shortDescription?.toLowerCase().includes(searchTerm.toLowerCase())) const matchesFilter = activeFilter === 'all' || (activeFilter === 'in-stock' && !defaultSku?.isOutOfStock) || (activeFilter === 'out-of-stock' && defaultSku?.isOutOfStock) return matchesSearch && matchesFilter }) }, [products, searchTerm, activeFilter]) const handleEdit = (productId: number) => { navigate({ to: '/dashboard/products/edit', search: { id: String(productId) } }) } const handleViewDetails = (productId: number) => { navigate({ to: '/dashboard/products/$id', params: { id: String(productId) } }) } if (isLoading) { return (
Loading products...
) } if (error) { return (
Error loading products
) } const inStockCount = products.filter((p) => getDefaultSku(p) && !getDefaultSku(p)!.isOutOfStock).length const outOfStockCount = products.filter((p) => getDefaultSku(p)?.isOutOfStock).length const listHeader = ( <>
Products navigate({ to: '/dashboard/products/new' })}> Add Product
) const renderItem = (product: any) => { const defaultSku = getDefaultSku(product) const skuImages = defaultSku?.images ?? null const isOut = defaultSku?.isOutOfStock ?? false return (
{skuImages && skuImages.length > 0 ? ( {product.name} ) : (
)}
{product.name}
{isOut ? 'Out' : 'In'}
{product.shortDescription && ( {product.shortDescription} )}
{product.skus?.length ?? 0} Variants
) } return (
item.id.toString()} ListHeaderComponent={listHeader} ListEmptyComponent={
{searchTerm || activeFilter !== 'all' ? 'No products match your filters' : 'No products found'} {searchTerm || activeFilter !== 'all' ? 'Try adjusting your search or filters' : 'Start by adding your first product'} {(searchTerm || activeFilter !== 'all') && ( )}
} className="pb-4" />
) }