Skip to content

Commit 2c96944

Browse files
committed
refactor(produto): improve error rendering on the homepage.
1 parent 55b5c94 commit 2c96944

1 file changed

Lines changed: 78 additions & 109 deletions

File tree

web/src/app/HomePage/page.tsx

Lines changed: 78 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,118 +1,87 @@
1-
import { useEffect, useState } from "react";
2-
import ProductCard from "../../components/ProductCard";
3-
import ProductCardSkeleton from "../../components/ProductCardSkeleton";
1+
import { useState } from "react";
2+
import ProductCard from "../../components/ProductCard";
3+
import ProductCardSkeleton from "../../components/ProductCardSkeleton";
4+
import useProducts from "../../hooks/api/useProducts";
45

5-
type Category = {
6-
id: number;
7-
name: string;
8-
};
6+
export default function Home() {
7+
const { products, loading, error } = useProducts();
8+
const [search, setSearch] = useState("");
99

10-
type Product = {
11-
id: number;
12-
name: string;
13-
category?: Category;
14-
price: number;
15-
};
10+
const filtered = products.filter((p) =>
11+
p.name.toLowerCase().includes(search.toLowerCase()),
12+
);
1613

17-
export default function Home() {
18-
const [products, setProducts] = useState<Product[]>([]);
19-
const [loading, setLoading] = useState(true);
20-
const [error, setError] = useState<string | null>(null);
21-
const [search, setSearch] = useState("");
14+
return (
15+
<div className="p-4">
16+
{loading ? (
17+
<div>
18+
{/* Busca */}
19+
<div className="w-full h-11 bg-gray-200 rounded-xl mb-4 animate-pulse"></div>
2220

23-
useEffect(() => {
24-
async function fetchProducts() {
25-
try {
26-
setLoading(true);
21+
{/* Título */}
22+
<div className="h-6 w-28 bg-gray-200 rounded mb-2 animate-pulse"></div>
2723

28-
await new Promise((resolve) => setTimeout(resolve, 3000));
24+
{/* Quantidade */}
25+
<div className="h-4 w-16 bg-gray-200 rounded mb-4 animate-pulse"></div>
2926

30-
const res = await fetch("http://localhost:8080/products");
31-
32-
if (!res.ok) throw new Error("Erro ao buscar produtos");
33-
34-
const data: Product[] = await res.json();
35-
setProducts(data);
36-
} catch (err: unknown) {
37-
if (err instanceof Error) {
38-
setError(err.message);
39-
} else {
40-
setError("Erro desconhecido");
41-
}
42-
} finally {
43-
setLoading(false);
44-
}
45-
}
46-
47-
fetchProducts();
48-
}, []);
49-
50-
const filtered = products.filter((p) =>
51-
p.name.toLowerCase().includes(search.toLowerCase()),
52-
);
53-
54-
return (
55-
<div className="p-4">
56-
{loading ? (
57-
<div>
58-
{/* Busca */}
59-
<div className="w-full h-11 bg-gray-200 rounded-xl mb-4 animate-pulse"></div>
60-
61-
{/* Título */}
62-
<div className="h-6 w-28 bg-gray-200 rounded mb-2 animate-pulse"></div>
63-
64-
{/* Quantidade */}
65-
<div className="h-4 w-16 bg-gray-200 rounded mb-4 animate-pulse"></div>
66-
67-
{/* Cards */}
68-
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
69-
{Array.from({ length: 4 }).map((_, index) => (
70-
<ProductCardSkeleton key={index} />
71-
))}
72-
</div>
73-
</div>
74-
) : (
75-
<>
76-
{/* Busca */}
77-
<input
78-
type="text"
79-
placeholder="Buscar produtos..."
80-
className="w-full bg-surface border border-border rounded-xl px-3 py-2 mb-4"
81-
value={search}
82-
onChange={(e) => setSearch(e.target.value)}
83-
/>
84-
85-
{/* Título */}
86-
<h2 className="text-lg font-semibold">Produtos</h2>
87-
88-
{/* Quantidade */}
89-
<p className="text-sm text-gray-500 mb-3">
90-
{filtered.length} itens
91-
</p>
92-
93-
{/* ERRO */}
94-
{error && (
95-
<p className="text-red-500">{error}</p>
96-
)}
97-
98-
{/* Nenhum produto */}
99-
{filtered.length === 0 && !error && (
100-
<p>Nenhum produto encontrado.</p>
101-
)}
102-
103-
{/* LISTA */}
104-
{!error && filtered.length > 0 && (
27+
{/* Cards */}
10528
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
106-
{filtered.map((product) => (
107-
<ProductCard
108-
key={product.id}
109-
product={product}
110-
/>
29+
{Array.from({ length: 4 }).map((_, index) => (
30+
<ProductCardSkeleton key={index} />
11131
))}
11232
</div>
113-
)}
114-
</>
115-
)}
116-
</div>
117-
);
118-
}
33+
</div>
34+
) : (
35+
<>
36+
{!error && (
37+
<>
38+
{/* Busca */}
39+
<input
40+
type="text"
41+
placeholder="Buscar produtos..."
42+
className="w-full bg-surface border border-border rounded-xl px-3 py-2 mb-4"
43+
value={search}
44+
onChange={(e) => setSearch(e.target.value)}
45+
/>
46+
47+
{/* Título */}
48+
<h2 className="text-lg font-semibold">Produtos</h2>
49+
50+
{/* Quantidade */}
51+
<p className="text-sm text-gray-500 mb-3">
52+
{filtered.length} itens
53+
</p>
54+
</>
55+
)}
56+
57+
{/* ERRO */}
58+
{error ? (
59+
<div className="space-y-4">
60+
<h2 className="text-lg font-semibold">Produtos</h2>
61+
<p className="text-red-500">{error}</p>
62+
<div className="grid grid-cols-2 gap-3">
63+
{Array.from({ length: 4 }).map((_, index) => (
64+
<ProductCardSkeleton key={index} />
65+
))}
66+
</div>
67+
</div>
68+
) : (
69+
<>
70+
{/* Nenhum produto */}
71+
{filtered.length === 0 && <p>Nenhum produto encontrado.</p>}
72+
73+
{/* LISTA */}
74+
{filtered.length > 0 && (
75+
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
76+
{filtered.map((product) => (
77+
<ProductCard key={product.id} product={product} />
78+
))}
79+
</div>
80+
)}
81+
</>
82+
)}
83+
</>
84+
)}
85+
</div>
86+
);
87+
}

0 commit comments

Comments
 (0)