Skip to content

Commit

Permalink
Dashboard Productos
Browse files Browse the repository at this point in the history
  • Loading branch information
Angel-Raa committed Dec 19, 2024
1 parent 6cf6e5f commit 2d3c436
Show file tree
Hide file tree
Showing 7 changed files with 297 additions and 128 deletions.
17 changes: 11 additions & 6 deletions src/actions/product/product.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import {supabase} from "../../supabase/client";
import {Product} from "../../utils";


export const getProducts = async (): Promise<Product[]> => {
const {data: products, error} = await supabase
export const getProducts = async (page:number) => {
const itemsPerPage = 10;
const from = (page - 1) * itemsPerPage;
const to = from + itemsPerPage - 1;
const {data, error, count} = await supabase
.from('products')
.select('*, variants(*)')
.order('created_at', {ascending: false});
.select('*, variants(*)', {count: 'exact'})
.order('created_at', {ascending: false}).range(from, to);

if (error) {
console.log(error.message);
throw new Error(error.message);
}

return products;
return {
data,
count
};
};

export const getFilteredProducts = async ({page = 1, brands = []}: {
Expand Down
11 changes: 9 additions & 2 deletions src/components/dashboard/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const Sidebar = () => {
return (
<>
<div className="w-[120px] bg-stone-800 text-white flex flex-col gap-10 items-center p-5 fixed h-screen lg:w-[250px] ">
<Logo isDashboard/>
<Logo isDashboard />
<nav className="w-full space-y-5 flex-1">
{dashboardLinks.map((link) => (
<NavLink
Expand All @@ -49,12 +49,19 @@ export const Sidebar = () => {
className={
"bg-red-500 w-full py-[10px] rounded-md flex items-center justify-center gap-2 font-semibold text-sm hover:underline "
}

onClick={handleLogout}
>
<span className="hidden lg:block">Cerrar session</span>
<IoLogOutOutline size={25} className="inline-block" />
</button>

<p className="text-sm text-center hidden lg:block ">
&copy; 2025 - Todos los derechos reservados
</p>
<p className="text-sm text-center lg:hidden">
&copy;
2025
</p>
</div>
</>
);
Expand Down
13 changes: 13 additions & 0 deletions src/components/dashboard/product/CellTableProduct.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
interface Props {
content: string;
}

export const CellTableProduct = ({ content }: Props) => {
return (
<>
<td className="p-4 font-medium tracking-tight">
{content}
</td>
</>
);
};
139 changes: 139 additions & 0 deletions src/components/dashboard/product/TableProduct.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
import { useState } from "react";
import { FaEllipsis } from "react-icons/fa6";
import { HiOutlineExternalLink } from "react-icons/hi";
import { Link } from "react-router-dom";
import { useProducts } from "../../../hook";
import { Loading } from "../../shared/loading/Loading";
import { formatDateLong, formatPrice } from "../../../utils";
import { Pagination } from "../../shared/pagination/Pagination";
import { CellTableProduct } from "./CellTableProduct";

const tableHeaders = [
"",
"Nombre",
Expand All @@ -8,6 +18,31 @@ const tableHeaders = [
"",
];
export const TableProduct = () => {
const [selectedVariants, setSelectedVariants] = useState<{
[key: string]: number;
}>({});
const [openMenu, setOpenMenu] = useState<number | null>(null);
const [page, setPage] = useState(1);
const { products, isLoading, totalProduct } = useProducts({ page });
const handlerDeleteProduct = (values: string): void => {
console.log(values);
};
const handlerMenuToggle = (value: number) => {
if (openMenu === value) {
setOpenMenu(null);
} else {
setOpenMenu(value);
}
};

const handlerVariantChange = (productId: string, i: number) => {
setSelectedVariants({
...selectedVariants,
[productId]: i,
});
};

if (isLoading || !products || !totalProduct) return <Loading />;
return (
<>
<div className="flex flex-col flex-1 border border-gray-200 rounded-lg p-5 bg-white">
Expand All @@ -16,10 +51,114 @@ export const TableProduct = () => {
<p className="text-sm mt-1 mb-8 font-serif text-gray-500">
Gestiona tus productos y mira las estadísticas de tus ventas
</p>

{/* Tabla */}

<div className="relative w-full h-full">
<table className="text-sm w-full caption-bottom overflow-auto">
<thead>
<tr className="text-sm font-bold">
{tableHeaders.map((header, index) => (
<th
key={index}
className="text-left p-2 border-b border-gray-200 h-12 px-4 pd-3 "
>
{header}
</th>
))}
</tr>
</thead>
<tbody>
{products.map((product, i) => {
const selectedVariantIndex = selectedVariants[product.id] ?? 0;
const selectedVariant = product.variants[selectedVariantIndex];

return (
<tr key={i}>
<td className="p-4 align-middle sm:table-cell">
<img
src={
product.images[0] ||
"https://ui.shadcn.com/placeholder.svg"
}
alt="Sample"
loading="lazy"
decoding="async"
className="w-16 h-16 aspect-square rounded-md object-contain"
/>
</td>
<td className="p-4 font-medium tracking-tight">
{product.name}
</td>
<td className="p-4 font-medium tracking-tight">
<select
onChange={(e) =>
handlerVariantChange(
product.id,
Number(e.target.value)
)
}
value={selectedVariantIndex}
className="border border-gray-300 rounded-md p-1 w-full"
name="variants"
id="variants"
>
{product.variants.map((variant, i) => (
<option value={variant.id} key={i}>
{variant.color_name} - {variant.storage}
</option>
))}
</select>
</td>
<CellTableProduct
content={formatPrice(selectedVariant.price)}
/>

<CellTableProduct
content={selectedVariant.stock.toString()}
/>

<CellTableProduct content={formatDateLong(product.created_at)} />
<td className="relative">
<button
onClick={() => handlerMenuToggle(i)}
className="text-slate-900"
>
<FaEllipsis size={20} />
</button>
{openMenu === i && (
<div
className="absolute right-0 mt-2 bg-white border-gray-200 rounded-md shadow-xl z-10 w-[120px]"
role="menu"
>
<Link
to={`/dashboard/productos/editar/${product.slug}`}
className="flex items-center gap-1 w-full text-left px-4 py-2 text-xs font-medium text-gray-700 hover:bg-gray-100"
>
Editar
<HiOutlineExternalLink
size={15}
className="inline-block"
/>
</Link>
<button
onClick={() => handlerDeleteProduct(product.id)}
className="blok w-full text-left px-4 py-2 font-medium text-gray-700 hover:bg-gray-100"
>
Eliminar
</button>
</div>
)}
</td>
</tr>
);
})}
</tbody>
</table>
</div>

{/* Controles de paginación */}
<Pagination page={page} setPage={setPage} totalItems={totalProduct} />
</div>
</>
);
Expand Down
26 changes: 15 additions & 11 deletions src/hook/product/useProducts.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import {useQuery} from "@tanstack/react-query";
import {getProducts} from "../../actions";

export const useProducts = () => {
const {data, isLoading, isError} = useQuery({
queryKey: ['products'],
queryFn: () => getProducts(),
staleTime: 1000 * 60 * 5
});
return {products: data, isLoading, isError};
}
import { useQuery } from "@tanstack/react-query";
import { getProducts } from "../../actions";

export const useProducts = ({ page = 1 }: { page?: number }) => {
const { data, isLoading, isError } = useQuery({
queryKey: ["products", page],
queryFn: () => getProducts(page),
staleTime: 1000 * 60 * 5,
});
return {
products: data?.data,
isLoading,
isError,
totalProduct: data?.count ?? 0,
};
};
Loading

0 comments on commit 2d3c436

Please sign in to comment.