feat: add Zustand store, product list and add product modal (Steps 2-3)

- Create useProductStore with Zustand for state management
- Enrich client.js with all API functions (CRUD, scrape)
- Connect HomePage to store with loading/error states
- Add ProductCard with scrape/delete actions
- Add ProductGrid component
- Add AddProductModal with URL extraction
- Update Header with refresh and scrape all buttons
- Add comprehensive styles for cards and modal

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-18 19:30:23 +01:00
parent a49b0e3bad
commit 744d16c2c5
9 changed files with 783 additions and 39 deletions

View File

@@ -1,17 +1,35 @@
import React from "react";
import React, { useState } from "react";
import { BrowserRouter, Routes, Route, NavLink } from "react-router-dom";
import HomePage from "./pages/HomePage";
import DebugPage from "./pages/DebugPage";
import useProductStore from "./stores/useProductStore";
import AddProductModal from "./components/products/AddProductModal";
const App = () => (
<BrowserRouter>
<div className="app-shell">
const Header = () => {
const { fetchProducts, scrapeAll, loading } = useProductStore();
const [showAddModal, setShowAddModal] = useState(false);
const handleRefresh = () => {
fetchProducts();
};
const handleScrapeAll = async () => {
if (!confirm("Lancer le scraping de tous les produits ?")) return;
try {
await scrapeAll();
} catch (err) {
console.error("Erreur scrape all:", err);
}
};
return (
<>
<header className="app-header">
<div className="brand">
<NavLink to="/">suivi_produits</NavLink>
</div>
<nav className="nav-links">
<NavLink to="/" className={({ isActive }) => isActive ? "active" : ""}>
<NavLink to="/" end className={({ isActive }) => isActive ? "active" : ""}>
<i className="fa-solid fa-home"></i> Accueil
</NavLink>
<NavLink to="/debug" className={({ isActive }) => isActive ? "active" : ""}>
@@ -19,15 +37,29 @@ const App = () => (
</NavLink>
</nav>
<div className="actions">
<button className="btn btn-primary">
<button className="btn btn-primary" onClick={() => setShowAddModal(true)}>
<i className="fa-solid fa-plus"></i> Add Product
</button>
<button className="btn">
<i className="fa-solid fa-refresh"></i> Refresh
<button className="btn" onClick={handleScrapeAll} disabled={loading}>
<i className="fa-solid fa-bolt"></i> Scrape All
</button>
<button className="btn" onClick={handleRefresh} disabled={loading}>
<i className={`fa-solid fa-refresh ${loading ? "fa-spin" : ""}`}></i>
</button>
</div>
</header>
{showAddModal && (
<AddProductModal onClose={() => setShowAddModal(false)} />
)}
</>
);
};
const App = () => (
<BrowserRouter>
<div className="app-shell">
<Header />
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/debug" element={<DebugPage />} />