chore: add ansible backend docker frontend-prep

This commit is contained in:
2026-01-21 13:05:13 +01:00
parent 5a280b6b01
commit 943fe4de7d
14930 changed files with 2341433 additions and 0 deletions
+181
View File
@@ -0,0 +1,181 @@
import { useState, useEffect } from "react";
import ProductCard from "../../components/ProductCard";
import Navbar from "../../components/Navbar";
import { getAllProducts, getProductsByCategory } from "../../api/api";
import type { Product } from "../../api/api";
import "./UserAccueil.css";
function UserAccueil() {
const [selectedCategory, setSelectedCategory] = useState<string>("tous");
const [products, setProducts] = useState<Product[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
const categories = [
{ label: "Tous", value: "tous" },
{ label: "Weed&Hash", value: "weed&hash" },
{ label: "Zipette&Co", value: "zipette&co" },
{ label: "Gros&Semi", value: "gros&semi" },
];
const categoryTitles: Record<string, string> = {
tous: "Tous les produits",
"weed&hash": "Weed & Hash",
"zipette&co": "Zipette & Co",
"gros&semi": "Gros & Semi",
};
useEffect(() => {
loadProducts();
}, [selectedCategory]);
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
? `http://localhost:8080${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 `http://localhost:8080${mediaItem.url}`;
}
}
// Si aucune image trouvée, fallback
return "https://via.placeholder.com/400x400/1a1a1a/ffffff?text=No+Image";
};
return (
<>
<Navbar />
<div className="user-page-container">
<div className="category-filter">
{categories.map((category) => (
<button
key={category.value}
className={`category-button ${selectedCategory === category.value ? "active" : ""}`}
data-category={category.value}
onClick={() => handleCategoryChange(category.value)}
>
{category.label}
</button>
))}
</div>
<div className="category-header">
<h2 className="category-title">
{categoryTitles[selectedCategory]}
</h2>
</div>
{loading && (
<div className="loading-container">
<p>Chargement des produits...</p>
</div>
)}
{error && (
<div className="error-container">
<p className="error-message">{error}</p>
</div>
)}
{!loading && !error && products.length === 0 && (
<div className="empty-container">
<p>Aucun produit disponible dans cette catégorie.</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="g"
image={getProductImage(product)}
stock={product.stock}
category={product.category}
prices={product.prices}
hasVideo={hasProductVideo(product)}
videoUrl={getProductVideoUrl(product)} // ✨ Nouveau prop
/>
</div>
))}
</div>
)}
</div>
</>
);
}
export default UserAccueil;