import { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import Navbar from "../../components/Navbar"; import "./ConsultationHistorique.css"; import { getMyCompletedOrders, formatPrice, getOrderAge, getMyPenalties, isUserAuthenticated, getPublicSettings, getReferralBalance, getMyPointsRewards, claimMyReward, } from "../../api/api"; import type { PublicSettings, PointsPoolInfo, PointsRewardConfig } from "../../api/api"; import type { CompletedOrder, ClientStats, PenaltyInfo, } from "../../api/api_types"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faCannabis, faPills, faFlask, faMortarPestle, faStar, faTrophy, faExclamationTriangle, faShieldAlt, faGift, faReceipt, faMapMarkerAlt, faClock, faBicycle, faChevronRight, faCheckCircle, faHistory, } from "@fortawesome/free-solid-svg-icons"; function ConsultationHistorique() { const navigate = useNavigate(); const [orders, setOrders] = useState([]); const [clientStats, setClientStats] = useState(null); const [penalties, setPenalties] = useState(null); const [appSettings, setAppSettings] = useState({ penalties_enabled: true, show_amende_score: true, points_enabled: true, points_separated: true, referral_enabled: true, referral_amount: 0, pool_names: ["Pool 1", "Pool 2"], crypto_payment_enabled: false, crypto_only: false, nowpayments_currencies: [], shop_name: "Milieu-Nantais", two_fa_enabled: false, contact_telegram: "", }); const [referralBalance, setReferralBalance] = useState(0); const [pointsRewards, setPointsRewards] = useState<{ enabled: boolean; pools: PointsPoolInfo[]; reward: PointsRewardConfig | null; } | null>(null); const [claimingPool, setClaimingPool] = useState(null); const [claimFeedback, setClaimFeedback] = useState<{ pool: string; type: "success" | "error"; text: string } | null>(null); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(""); useEffect(() => { if (!isUserAuthenticated()) navigate("/login/client", { replace: true }); }, [navigate]); useEffect(() => { const interval = setInterval(() => { if (!isUserAuthenticated()) navigate("/login/client", { replace: true }); }, 5000); return () => clearInterval(interval); }, [navigate]); useEffect(() => { fetchHistory(); fetchPenalties(); getPublicSettings().then((s) => { setAppSettings(s); if (s.referral_enabled) { getReferralBalance().then((r) => { if (r.success) setReferralBalance(r.balance); }); } }); getMyPointsRewards().then((r) => { if (r.success && r.enabled) setPointsRewards(r); }); }, []); // eslint-disable-line react-hooks/exhaustive-deps const fetchHistory = async () => { if (!isUserAuthenticated()) { navigate("/login/client", { replace: true }); return; } setIsLoading(true); setError(""); try { const result = await getMyCompletedOrders(); if (result.success) { setOrders(result.commands); setClientStats(result.client_stats || null); } else { setError(result.message || "Erreur lors du chargement"); } } catch { setError("Erreur de connexion"); } finally { setIsLoading(false); } }; const fetchPenalties = async () => { if (!isUserAuthenticated()) return; try { const result = await getMyPenalties(); if (result.success && result.data) setPenalties(result.data); } catch { /* ignore */ } }; const viewOrderDetails = (order: CompletedOrder) => { if (!isUserAuthenticated()) { navigate("/login/client", { replace: true }); return; } navigate(`/user/commande/${order.client_order_number ?? order.id}`, { state: { commandId: order.id }, }); }; const formatDate = (dateStr: string) => { const d = new Date(dateStr); return d.toLocaleDateString("fr-FR", { day: "2-digit", month: "short", year: "numeric", }); }; if (isLoading) { return ( <>

Chargement de l'historique...

); } const handleClaim = async (poolKey: string) => { setClaimingPool(poolKey); setClaimFeedback(null); const res = await claimMyReward(poolKey); setClaimingPool(null); if (res.success) { setClaimFeedback({ pool: poolKey, type: "success", text: res.description || "Récompense réclamée !" }); getMyPointsRewards().then((r) => { if (r.success) setPointsRewards(r); }); } else { setClaimFeedback({ pool: poolKey, type: "error", text: res.error || "Erreur" }); } }; const poolNames = clientStats?.pool_names?.length ? clientStats.pool_names : appSettings.pool_names; const poolPoints = clientStats?.pool_points ?? [clientStats?.points ?? 0]; const totalPoints = poolPoints.reduce((s, v) => s + (v || 0), 0); const penaltyCount = penalties?.total_penalty || clientStats?.penalties || 0; const poolIcons = [faCannabis, faPills, faFlask, faMortarPestle, faStar]; const poolIconColors = [ "#10b981", "#e879f9", "#fb923c", "#38bdf8", "#7c3aed", ]; return ( <>

Historique des commandes

{/* Stats grid */}
{/* Total commandes */}

{clientStats?.total_commands ?? orders.length}

Commandes

{/* Points */} {appSettings.points_enabled && (poolNames.length <= 1 ? (

{poolPoints[0] || 0}

Pts {poolNames[0] ?? "Points"}

) : ( <> {poolNames.map((name, i) => (

{poolPoints[i] || 0}

Pts {name}

))} {totalPoints > 0 && (

{totalPoints}

Total Points

)} ))} {/* Score amendes */} {appSettings.show_amende_score && (
= 3 ? " stat-card-danger" : penaltyCount > 0 ? " stat-card-warning" : ""}`} >
= 3 ? "icon-penalty-critical" : penaltyCount > 0 ? "icon-penalty-warning" : "icon-penalty-ok"}`} > 0 ? faExclamationTriangle : faShieldAlt } />

= 3 ? "value-danger" : penaltyCount > 0 ? "value-warning" : ""}`} > {penaltyCount}

Score amendes

)}
{/* Section récompenses par palier */} {pointsRewards?.enabled && pointsRewards.reward && pointsRewards.pools.length > 0 && (

Récompenses

{pointsRewards.reward.description}

{pointsRewards.pools.map((pool) => { const threshold = pointsRewards.reward!.threshold; const progress = Math.min(100, Math.round((pool.points % threshold) / threshold * 100)); const remaining = threshold - (pool.points % threshold); const isClaiming = claimingPool === pool.key; const feedback = claimFeedback?.pool === pool.key ? claimFeedback : null; return (
{pool.name} {pool.points} pts
{pool.eligible_configs.length > 0 && (
{pool.eligible_configs.map((cfg) => cfg.all_products ? ( {cfg.category}{cfg.amount > 0 ? ` — ${cfg.amount}€` : ""} ) : ( cfg.product_names.map((name) => ( {name} )) ) )}
)}
{pool.rewards_available > 0 ? ( {pool.rewards_available} récompense{pool.rewards_available > 1 ? "s" : ""} disponible{pool.rewards_available > 1 ? "s" : ""} ) : ( Encore {remaining} pts pour une récompense )}
{feedback && (

{feedback.text}

)} {pool.rewards_available > 0 && ( )}
); })}
)} {/* Bouton parrainage */} {appSettings.referral_enabled && (
navigate("/user/parrainage")} > Parrainage {referralBalance > 0 ? ` — ${referralBalance.toFixed(2)} €` : ""}
)} {error && (

{error}

)} {orders.length === 0 ? (

Aucun historique

Vos commandes terminées apparaîtront ici

) : ( <>

Historique des commandes

{orders.map((order) => (
viewOrderDetails(order)} >
Commande # {(order.client_order_number ?? 0) .toString() .padStart(4, "0")} Livrée
{order.adresse ? order.adresse.length > 50 ? order.adresse.substring( 0, 50, ) + "…" : order.adresse : "N/A"}
{formatDate(order.created_at)} ·{" "} {getOrderAge(order.created_at)}
{order.livreur_assign && (
{order.livreur_assign}
)}
{formatPrice((order.total_prix || 0) - (order.referral_used || 0))}
))}
)}
); } export default ConsultationHistorique;