diff --git a/apps/web/app/dashboard/productos/page.tsx b/apps/web/app/dashboard/productos/page.tsx index 254c9c6..26053c3 100644 --- a/apps/web/app/dashboard/productos/page.tsx +++ b/apps/web/app/dashboard/productos/page.tsx @@ -1,14 +1,26 @@ +'use client'; // import PageContainer from '@/components/layout/page-container'; -import { ProductList } from '@/feactures/inventory/components/products/product-list'; +// import { ProductList } from '@/feactures/inventory/components/products/product-list'; +import { ProductList } from '@/feactures/inventory/components/products/product-list-scroll'; import { Button } from '@repo/shadcn/components/ui/button'; -import { Metadata } from 'next'; +// import { Metadata } from 'next'; +import { useAllProductQuery } from '@/feactures/inventory/hooks/use-query-products'; +import { allProducts } from '@/feactures/inventory/schemas/inventory'; -export const metadata: Metadata = { - title: 'Productos - Fondemi', - description: 'Listado de productos disponibles', -}; -export default function SurveysPage() { +// export const metadata: Metadata = { +// title: 'Productos - Fondemi', +// description: 'Listado de productos disponibles', +// }; + +export default function SurveysPage() { + // const { data } = useAllProductQuery(); + // let products: allProducts[] = [] + + // if (data?.data) { + // products = data.data + // } + return ( //
@@ -18,7 +30,7 @@ export default function SurveysPage() { - +
//
diff --git a/apps/web/feactures/inventory/components/products/product-list-scroll.tsx b/apps/web/feactures/inventory/components/products/product-list-scroll.tsx new file mode 100644 index 0000000..da6a2ec --- /dev/null +++ b/apps/web/feactures/inventory/components/products/product-list-scroll.tsx @@ -0,0 +1,80 @@ +'use client'; +import { useRouter } from 'next/navigation'; +import { useAllProductInfiniteQuery } from '@/feactures/inventory/hooks/use-query-products'; +import { ProductCard } from '@/feactures/inventory/components/products/productCard'; +import { allProducts } from '@/feactures/inventory/schemas/inventory'; +import { useRef, useEffect } from 'react'; + +export function ProductList() { + const router = useRouter(); + const lastProductRef = useRef(null); + + const { + data, + fetchNextPage, + hasNextPage, + isFetchingNextPage, + isLoading + } = useAllProductInfiniteQuery(); + + const handle = (id: number) => { + router.push(`/dashboard/productos/${id}`); + }; + + const products = data?.pages.flatMap(page => page.data) || []; + + useEffect(() => { + if (!lastProductRef.current || !hasNextPage || isFetchingNextPage) return; + + const observer = new IntersectionObserver( + (entries) => { + if (entries[0]?.isIntersecting) { + fetchNextPage(); + } + }, + { + root: null, + rootMargin: '200px', + threshold: 1.0, + } + ); + + observer.observe(lastProductRef.current); + + return () => { + observer.disconnect(); + }; + }, [hasNextPage, isFetchingNextPage, fetchNextPage]); + + return ( +
+ {isLoading ? ( +
+

Cargando productos...

+
+ ) : products.length === 0 ? ( +
+

+ No hay productos disponibles en este momento. +

+
+ ) : ( + <> + {products.map((item, index) => { + const isLastElement = index === products.length - 1; + return ( +
+ handle(Number(item.id))} /> +
+ ); + })} + {isFetchingNextPage && ( +
+

Cargando más productos...

+
+ )} + + )} +
+ ); +} \ No newline at end of file diff --git a/apps/web/feactures/inventory/components/products/product-list.tsx b/apps/web/feactures/inventory/components/products/product-list.tsx index 8dd9d7c..6aebc0e 100644 --- a/apps/web/feactures/inventory/components/products/product-list.tsx +++ b/apps/web/feactures/inventory/components/products/product-list.tsx @@ -1,21 +1,12 @@ 'use client'; - -import { - Card, - CardContent, - CardFooter, - CardHeader, - CardTitle, -} from '@repo/shadcn/card'; import { useRouter } from 'next/navigation'; import { useAllProductQuery } from '@/feactures/inventory/hooks/use-query-products'; import { allProducts } from '../../schemas/inventory'; -// import { ImageIcon } from 'lucide-react'; +import { ProductCard } from '@/feactures/inventory/components/products/productCard' export function ProductList() { const router = useRouter(); const { data: produts } = useAllProductQuery(); - // console.log(produts); const handle = (id: number) => { router.push(`/dashboard/productos/${id}`); @@ -31,30 +22,7 @@ export function ProductList() { ) : ( produts?.data.map((data: allProducts) => ( - handle(Number(data.id))} - > - {/* */} - - {data.title.charAt(0).toUpperCase() + data.title.slice(1)} - - {/* */} - - - - - {data.status === 'AGOTADO' ? ( -

AGOTADO

- ): ('')} -

$ {data.price}

-
-
+ handle(Number(data.id))} key={data.id} /> )) )} diff --git a/apps/web/feactures/inventory/components/products/productCard.tsx b/apps/web/feactures/inventory/components/products/productCard.tsx new file mode 100644 index 0000000..0cf8709 --- /dev/null +++ b/apps/web/feactures/inventory/components/products/productCard.tsx @@ -0,0 +1,43 @@ +'use client'; + +import { + Card, + CardContent, + CardFooter, + CardHeader, + CardTitle, +} from '@repo/shadcn/card'; +import { allProducts } from '../../schemas/inventory'; + +interface cardProps { + product: allProducts; + onClick?: () => void; +} + +export function ProductCard({ product, onClick }: cardProps) { + + return ( + + {/* */} + + {product.title.charAt(0).toUpperCase() + product.title.slice(1)} + + {/* */} + + + + + {product.status === 'AGOTADO' ? ( +

AGOTADO

+ ): ('')} +

$ {product.price}

+
+
+ + ) +} \ No newline at end of file diff --git a/apps/web/feactures/inventory/hooks/use-query-products.ts b/apps/web/feactures/inventory/hooks/use-query-products.ts index da367e4..62741ba 100644 --- a/apps/web/feactures/inventory/hooks/use-query-products.ts +++ b/apps/web/feactures/inventory/hooks/use-query-products.ts @@ -1,12 +1,36 @@ 'use client' -import { useSafeQuery } from "@/hooks/use-safe-query"; +import { useSafeQuery, useSafeInfiniteQuery } from "@/hooks/use-safe-query"; import { getInventoryAction, getAllProducts } from "../actions/actions"; +// import { useInfiniteQuery } from "@tanstack/react-query"; + +interface Params { + page?: number; + limit?: number; + search?: string; + sortBy?: string; + sortOrder?: 'asc' | 'desc'; +} // Hook for users -export function useProductQuery(params = {}) { +export function useProductQuery(params: Params = {}) { return useSafeQuery(['product',params], () => getInventoryAction(params)) } -export function useAllProductQuery(params = {}) { +export function useAllProductQuery(params: Params = {}) { return useSafeQuery(['product',params], () => getAllProducts(params)) +} + +export function useAllProductInfiniteQuery() { + return useSafeInfiniteQuery( + ['product'], + // pageParam + 1 para evitar duplicación de datos + ({ pageParam = 0 }) => getAllProducts({ page: pageParam + 1, limit: 10 }), + (lastPage, allPages) => { + // Esta lógica determina el 'pageParam' para la siguiente página + const nextPage = allPages.length; + // Puedes añadir una condición para saber si hay más páginas + if (lastPage.data.length < 10) return undefined; + return nextPage; + } + ) } \ No newline at end of file diff --git a/apps/web/hooks/use-safe-query.ts b/apps/web/hooks/use-safe-query.ts index c038429..713e89e 100644 --- a/apps/web/hooks/use-safe-query.ts +++ b/apps/web/hooks/use-safe-query.ts @@ -1,4 +1,5 @@ -import { UseQueryOptions, useQuery } from '@tanstack/react-query' +import { UseQueryOptions, useInfiniteQuery, useQuery } from '@tanstack/react-query' + export function useSafeQuery( queryKey: [string, K?], @@ -10,4 +11,34 @@ export function useSafeQuery( queryFn, ...options, }) -} \ No newline at end of file +} + +export function useSafeInfiniteQuery( + queryKey: [string, K?], + queryFn: ({ pageParam }: { pageParam: number }) => Promise, + getNextPageParam: (lastPage: T, allPages: T[]) => number | undefined, + // options?: Omit, 'queryKey' | 'queryFn'> +) { + return useInfiniteQuery({ + queryKey, + queryFn, + getNextPageParam, + initialPageParam: 0, + }) +} + +// export function useAllProductInfiniteQuery(){ +// return useInfiniteQuery({ +// queryKey:['product'], +// queryFn: ({ pageParam = 0 }) => getAllProducts({ page: pageParam + 1, limit: 10 }), +// getNextPageParam: (lastPage, allPages) => { +// // Esta lógica determina el 'pageParam' para la siguiente página +// const nextPage = allPages.length; +// // Puedes añadir una condición para saber si hay más páginas +// if (lastPage.data.length < 10) return undefined; +// return nextPage; +// }, +// initialPageParam: 0, +// }) + +// } \ No newline at end of file