203 lines
7.9 KiB
TypeScript
203 lines
7.9 KiB
TypeScript
import { useState, useEffect } from "react";
|
|
import ProductCard from "../../components/ProductCard";
|
|
import Navbar from "../../components/Navbar";
|
|
import { getAllProducts, getProductsByCategory, getMediaUrl, getCategories } from "../../api/api";
|
|
import type { Product, Category } from "../../api/api";
|
|
import "./UserAccueil.css";
|
|
|
|
function UserAccueil() {
|
|
const [selectedCategory, setSelectedCategory] = useState<string>("tous");
|
|
const [categories, setCategories] = useState<Category[]>([]);
|
|
const [products, setProducts] = useState<Product[]>([]);
|
|
const [loading, setLoading] = useState<boolean>(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
getCategories().then(setCategories);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const catObj = categories.find((c) => c.name === selectedCategory);
|
|
if (catObj?.is_coming_soon) {
|
|
setLoading(false);
|
|
setProducts([]);
|
|
return;
|
|
}
|
|
loadProducts();
|
|
}, [selectedCategory, categories]);
|
|
|
|
const loadProducts = async () => {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
let response;
|
|
|
|
if (selectedCategory === "tous") {
|
|
response = await getAllProducts();
|
|
} else {
|
|
response = await getProductsByCategory(selectedCategory);
|
|
}
|
|
|
|
if (response.success && response.data) {
|
|
setProducts(response.data);
|
|
} else {
|
|
setError(
|
|
response.message ||
|
|
"Erreur lors du chargement des produits",
|
|
);
|
|
}
|
|
} catch (err: any) {
|
|
setError(err.message || "Erreur lors du chargement des produits");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleCategoryChange = (category: string) => {
|
|
setSelectedCategory(category);
|
|
};
|
|
|
|
const getProductPrice = (product: Product): number => {
|
|
if (!product.prices || product.prices.length === 0) {
|
|
return 0;
|
|
}
|
|
return product.prices[0]?.price || 0;
|
|
};
|
|
const hasProductVideo = (product: Product): boolean => {
|
|
if (!product.media || product.media.length === 0) {
|
|
return false;
|
|
}
|
|
|
|
return product.media.some(
|
|
(mediaItem) => mediaItem && mediaItem.type === "video",
|
|
);
|
|
};
|
|
const getProductVideoUrl = (product: Product): string | undefined => {
|
|
if (!product.media || product.media.length === 0) {
|
|
return undefined;
|
|
}
|
|
|
|
const videoMedia = product.media.find(
|
|
(mediaItem) => mediaItem && mediaItem.type === "video",
|
|
);
|
|
|
|
return videoMedia?.url ? getMediaUrl(videoMedia.url) : undefined;
|
|
};
|
|
const getProductImage = (product: Product): string => {
|
|
// Pas de media ? Image placeholder
|
|
if (!product.media || product.media.length === 0) {
|
|
return "https://via.placeholder.com/400x400/1a1a1a/ffffff?text=No+Image";
|
|
}
|
|
|
|
// Parcourir le tableau media pour trouver la première image
|
|
for (let i = 0; i < product.media.length; i++) {
|
|
const mediaItem = product.media[i];
|
|
|
|
// Vérifier si c'est un objet avec type "image" et url
|
|
if (mediaItem && mediaItem.type === "image" && mediaItem.url) {
|
|
return getMediaUrl(mediaItem.url);
|
|
}
|
|
}
|
|
|
|
// Si aucune image trouvée, fallback
|
|
return "https://via.placeholder.com/400x400/1a1a1a/ffffff?text=No+Image";
|
|
};
|
|
|
|
const selectedCategoryObj = categories.find((c) => c.name === selectedCategory);
|
|
const isSelectedComingSoon = selectedCategoryObj?.is_coming_soon ?? false;
|
|
|
|
return (
|
|
<>
|
|
<Navbar />
|
|
<div className="user-page-container">
|
|
<div className="category-filter">
|
|
<button
|
|
className={`category-button ${selectedCategory === "tous" ? "active" : ""}`}
|
|
data-category="tous"
|
|
onClick={() => handleCategoryChange("tous")}
|
|
>
|
|
Tous
|
|
</button>
|
|
{categories.map((category) => {
|
|
const isActive = selectedCategory === category.name;
|
|
const catColor = category.color || "#7c3aed";
|
|
return (
|
|
<button
|
|
key={category.id}
|
|
className={`category-button ${isActive ? "active" : ""}`}
|
|
style={
|
|
isActive
|
|
? {
|
|
backgroundColor: catColor,
|
|
borderColor: catColor,
|
|
color: "#ffffff",
|
|
}
|
|
: { borderColor: `${catColor}66` }
|
|
}
|
|
onClick={() => handleCategoryChange(category.name)}
|
|
>
|
|
{category.name}
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<div className="category-header">
|
|
<h2 className="category-title">
|
|
{selectedCategory === "tous" ? "Tous les produits" : selectedCategory}
|
|
</h2>
|
|
</div>
|
|
|
|
{isSelectedComingSoon ? (
|
|
<div className="coming-soon-overlay">
|
|
<span className="coming-soon-text">Prochainement</span>
|
|
<p className="coming-soon-desc">
|
|
Les produits de cette catégorie arrivent bientôt !
|
|
</p>
|
|
</div>
|
|
) : (
|
|
<>
|
|
{loading && (
|
|
<div className="loading-container">
|
|
<p>Chargement des produits...</p>
|
|
</div>
|
|
)}
|
|
|
|
{!loading && !error && products.length > 0 && (
|
|
<div className="products-grid">
|
|
{products.map((product) => (
|
|
<div
|
|
key={product.id}
|
|
data-category={product.category}
|
|
>
|
|
<ProductCard
|
|
id={product.id}
|
|
name={product.name}
|
|
price={getProductPrice(product)}
|
|
unit={product.unit || "g"}
|
|
image={getProductImage(product)}
|
|
stock={product.stock}
|
|
category={product.category}
|
|
prices={product.prices}
|
|
hasVideo={hasProductVideo(product)}
|
|
videoUrl={getProductVideoUrl(product)}
|
|
categoryColor={
|
|
categories.find(
|
|
(c) => c.name.toLowerCase() === product.category?.toLowerCase(),
|
|
)?.color
|
|
}
|
|
/>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</>
|
|
)}
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default UserAccueil;
|