fix: ts
This commit is contained in:
@@ -52,10 +52,6 @@ type GeoService struct {
|
|||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================
|
|
||||||
// CONSTRUCTEUR
|
|
||||||
// ============================================
|
|
||||||
|
|
||||||
func NewGeoService(redisClient *redis.Client, ctx context.Context) *GeoService {
|
func NewGeoService(redisClient *redis.Client, ctx context.Context) *GeoService {
|
||||||
return &GeoService{
|
return &GeoService{
|
||||||
redis: redisClient,
|
redis: redisClient,
|
||||||
|
|||||||
@@ -1,278 +1,408 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from "react";
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from "react-router-dom";
|
||||||
import Navbar from '../../components/Navbar';
|
import Navbar from "../../components/Navbar";
|
||||||
import './ConsultationHistorique.css';
|
import "./ConsultationHistorique.css";
|
||||||
import {
|
import {
|
||||||
getMyCompletedOrders,
|
getMyCompletedOrders,
|
||||||
formatPrice,
|
formatPrice,
|
||||||
getOrderAge,
|
getOrderAge,
|
||||||
getMyPenalties,
|
getMyPenalties,
|
||||||
isUserAuthenticated,
|
isUserAuthenticated,
|
||||||
getPublicSettings,
|
getPublicSettings,
|
||||||
getReferralBalance,
|
getReferralBalance,
|
||||||
} from '../../api/api';
|
} from "../../api/api";
|
||||||
import type { PublicSettings } from '../../api/api';
|
import type { PublicSettings } from "../../api/api";
|
||||||
import type { CompletedOrder, ClientStats, PenaltyInfo } from "../../api/api_types";
|
import type {
|
||||||
|
CompletedOrder,
|
||||||
|
ClientStats,
|
||||||
|
PenaltyInfo,
|
||||||
|
} from "../../api/api_types";
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import {
|
import {
|
||||||
faCannabis,
|
faCannabis,
|
||||||
faPills,
|
faPills,
|
||||||
faFlask,
|
faFlask,
|
||||||
faMortarPestle,
|
faMortarPestle,
|
||||||
faStar,
|
faStar,
|
||||||
faTrophy,
|
faTrophy,
|
||||||
faExclamationTriangle,
|
faExclamationTriangle,
|
||||||
faShieldAlt,
|
faShieldAlt,
|
||||||
faGift,
|
faGift,
|
||||||
faReceipt,
|
faReceipt,
|
||||||
faMapMarkerAlt,
|
faMapMarkerAlt,
|
||||||
faClock,
|
faClock,
|
||||||
faBicycle,
|
faBicycle,
|
||||||
faChevronRight,
|
faChevronRight,
|
||||||
faCheckCircle,
|
faCheckCircle,
|
||||||
faHistory,
|
faHistory,
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
function ConsultationHistorique() {
|
function ConsultationHistorique() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [orders, setOrders] = useState<CompletedOrder[]>([]);
|
const [orders, setOrders] = useState<CompletedOrder[]>([]);
|
||||||
const [clientStats, setClientStats] = useState<ClientStats | null>(null);
|
const [clientStats, setClientStats] = useState<ClientStats | null>(null);
|
||||||
const [penalties, setPenalties] = useState<PenaltyInfo | null>(null);
|
const [penalties, setPenalties] = useState<PenaltyInfo | null>(null);
|
||||||
const [appSettings, setAppSettings] = useState<PublicSettings>({ 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 });
|
const [appSettings, setAppSettings] = useState<PublicSettings>({
|
||||||
const [referralBalance, setReferralBalance] = useState<number>(0);
|
penalties_enabled: true,
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
show_amende_score: true,
|
||||||
const [error, setError] = useState<string>('');
|
points_enabled: true,
|
||||||
|
points_separated: true,
|
||||||
useEffect(() => {
|
referral_enabled: true,
|
||||||
if (!isUserAuthenticated()) navigate('/login/client', { replace: true });
|
referral_amount: 0,
|
||||||
}, [navigate]);
|
pool_names: ["Pool 1", "Pool 2"],
|
||||||
|
crypto_payment_enabled: false,
|
||||||
useEffect(() => {
|
crypto_only: false,
|
||||||
const interval = setInterval(() => {
|
nowpayments_currencies: [],
|
||||||
if (!isUserAuthenticated()) navigate('/login/client', { replace: true });
|
shop_name: "Milieu-Nantais",
|
||||||
}, 5000);
|
two_fa_enabled: false,
|
||||||
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); });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
const [referralBalance, setReferralBalance] = useState<number>(0);
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [error, setError] = useState<string>("");
|
||||||
|
|
||||||
const fetchHistory = async () => {
|
useEffect(() => {
|
||||||
if (!isUserAuthenticated()) { navigate('/login/client', { replace: true }); return; }
|
if (!isUserAuthenticated())
|
||||||
setIsLoading(true);
|
navigate("/login/client", { replace: true });
|
||||||
setError('');
|
}, [navigate]);
|
||||||
try {
|
|
||||||
const result = await getMyCompletedOrders();
|
useEffect(() => {
|
||||||
if (result.success) {
|
const interval = setInterval(() => {
|
||||||
setOrders(result.commands);
|
if (!isUserAuthenticated())
|
||||||
setClientStats(result.client_stats || null);
|
navigate("/login/client", { replace: true });
|
||||||
} else {
|
}, 5000);
|
||||||
setError(result.message || 'Erreur lors du chargement');
|
return () => clearInterval(interval);
|
||||||
}
|
}, [navigate]);
|
||||||
} catch {
|
|
||||||
setError('Erreur de connexion');
|
useEffect(() => {
|
||||||
} finally {
|
fetchHistory();
|
||||||
setIsLoading(false);
|
fetchPenalties();
|
||||||
|
getPublicSettings().then((s) => {
|
||||||
|
setAppSettings(s);
|
||||||
|
if (s.referral_enabled) {
|
||||||
|
getReferralBalance().then((r) => {
|
||||||
|
if (r.success) setReferralBalance(r.balance);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, []); // 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 (
|
||||||
|
<>
|
||||||
|
<Navbar />
|
||||||
|
<div className="history-container">
|
||||||
|
<div className="loading-container">
|
||||||
|
<div className="loading-spinner">
|
||||||
|
<div className="spinner"></div>
|
||||||
|
</div>
|
||||||
|
<p className="loading-text">
|
||||||
|
Chargement de l'historique...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const fetchPenalties = async () => {
|
const poolNames = clientStats?.pool_names?.length
|
||||||
if (!isUserAuthenticated()) return;
|
? clientStats.pool_names
|
||||||
try {
|
: appSettings.pool_names;
|
||||||
const result = await getMyPenalties();
|
const poolPoints = clientStats?.pool_points ?? [clientStats?.points ?? 0];
|
||||||
if (result.success && result.data) setPenalties(result.data);
|
const totalPoints = poolPoints.reduce((s, v) => s + (v || 0), 0);
|
||||||
} catch { /* ignore */ }
|
const penaltyCount =
|
||||||
};
|
penalties?.total_penalty || clientStats?.penalties || 0;
|
||||||
|
const poolIcons = [faCannabis, faPills, faFlask, faMortarPestle, faStar];
|
||||||
|
const poolIconColors = [
|
||||||
|
"#10b981",
|
||||||
|
"#e879f9",
|
||||||
|
"#fb923c",
|
||||||
|
"#38bdf8",
|
||||||
|
"#7c3aed",
|
||||||
|
];
|
||||||
|
|
||||||
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
<div className="history-container">
|
<div className="history-container">
|
||||||
<div className="loading-container">
|
<h1 className="history-title">Historique des commandes</h1>
|
||||||
<div className="loading-spinner"><div className="spinner"></div></div>
|
|
||||||
<p className="loading-text">Chargement de l'historique...</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const poolNames = clientStats?.pool_names?.length ? clientStats.pool_names : appSettings.pool_names;
|
{/* Stats grid */}
|
||||||
const poolPoints = clientStats?.pool_points ?? [clientStats?.points ?? 0];
|
<div className="stats-grid">
|
||||||
const totalPoints = poolPoints.reduce((s, v) => s + (v || 0), 0);
|
{/* Total commandes */}
|
||||||
const penaltyCount = penalties?.total_penalty || clientStats?.penalties || 0;
|
<div className="stat-card2">
|
||||||
const poolIcons = [faCannabis, faPills, faFlask, faMortarPestle, faStar];
|
<div className="stat-icon icon-total-orders">
|
||||||
const poolIconColors = ['#10b981', '#e879f9', '#fb923c', '#38bdf8', '#7c3aed'];
|
<FontAwesomeIcon icon={faReceipt} />
|
||||||
|
</div>
|
||||||
|
<p className="stat-value">
|
||||||
|
{clientStats?.total_commands ?? orders.length}
|
||||||
|
</p>
|
||||||
|
<p className="stat-label">Commandes</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
return (
|
{/* Points */}
|
||||||
<>
|
{appSettings.points_enabled &&
|
||||||
<Navbar />
|
(poolNames.length <= 1 ? (
|
||||||
<div className="history-container">
|
<div className="stat-card2">
|
||||||
|
<div className="stat-icon icon-total">
|
||||||
|
<FontAwesomeIcon icon={faTrophy} />
|
||||||
|
</div>
|
||||||
|
<p className="stat-value">
|
||||||
|
{poolPoints[0] || 0}
|
||||||
|
</p>
|
||||||
|
<p className="stat-label">
|
||||||
|
Pts {poolNames[0] ?? "Points"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{poolNames.map((name, i) => (
|
||||||
|
<div key={i} className="stat-card2">
|
||||||
|
<div
|
||||||
|
className="stat-icon"
|
||||||
|
style={{
|
||||||
|
background: `linear-gradient(135deg, ${poolIconColors[i] ?? "#7c3aed"}cc, ${poolIconColors[i] ?? "#7c3aed"})`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={poolIcons[i] ?? faStar}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="stat-value">
|
||||||
|
{poolPoints[i] || 0}
|
||||||
|
</p>
|
||||||
|
<p className="stat-label">Pts {name}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{totalPoints > 0 && (
|
||||||
|
<div className="stat-card2">
|
||||||
|
<div className="stat-icon icon-total">
|
||||||
|
<FontAwesomeIcon icon={faTrophy} />
|
||||||
|
</div>
|
||||||
|
<p className="stat-value">
|
||||||
|
{totalPoints}
|
||||||
|
</p>
|
||||||
|
<p className="stat-label">
|
||||||
|
Total Points
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
|
||||||
<h1 className="history-title">Historique des commandes</h1>
|
{/* Score amendes */}
|
||||||
|
{appSettings.show_amende_score && (
|
||||||
{/* Stats grid */}
|
<div
|
||||||
<div className="stats-grid">
|
className={`stat-card2${penaltyCount >= 3 ? " stat-card-danger" : penaltyCount > 0 ? " stat-card-warning" : ""}`}
|
||||||
|
>
|
||||||
{/* Total commandes */}
|
<div
|
||||||
<div className="stat-card2">
|
className={`stat-icon ${penaltyCount >= 3 ? "icon-penalty-critical" : penaltyCount > 0 ? "icon-penalty-warning" : "icon-penalty-ok"}`}
|
||||||
<div className="stat-icon icon-total-orders">
|
>
|
||||||
<FontAwesomeIcon icon={faReceipt} />
|
<FontAwesomeIcon
|
||||||
</div>
|
icon={
|
||||||
<p className="stat-value">{clientStats?.total_commands ?? orders.length}</p>
|
penaltyCount > 0
|
||||||
<p className="stat-label">Commandes</p>
|
? faExclamationTriangle
|
||||||
</div>
|
: faShieldAlt
|
||||||
|
}
|
||||||
{/* Points */}
|
/>
|
||||||
{appSettings.points_enabled && (
|
</div>
|
||||||
poolNames.length <= 1 ? (
|
<p
|
||||||
<div className="stat-card2">
|
className={`stat-value ${penaltyCount >= 3 ? "value-danger" : penaltyCount > 0 ? "value-warning" : ""}`}
|
||||||
<div className="stat-icon icon-total">
|
>
|
||||||
<FontAwesomeIcon icon={faTrophy} />
|
{penaltyCount}
|
||||||
|
</p>
|
||||||
|
<p className="stat-label">Score amendes</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<p className="stat-value">{poolPoints[0] || 0}</p>
|
|
||||||
<p className="stat-label">Pts {poolNames[0] ?? 'Points'}</p>
|
{/* Bouton parrainage */}
|
||||||
</div>
|
{appSettings.referral_enabled && (
|
||||||
) : (
|
<div
|
||||||
<>
|
className="referral-btn-row"
|
||||||
{poolNames.map((name, i) => (
|
onClick={() => navigate("/user/parrainage")}
|
||||||
<div key={i} className="stat-card2">
|
>
|
||||||
<div className="stat-icon" style={{ background: `linear-gradient(135deg, ${poolIconColors[i] ?? '#7c3aed'}cc, ${poolIconColors[i] ?? '#7c3aed'})` }}>
|
<FontAwesomeIcon
|
||||||
<FontAwesomeIcon icon={poolIcons[i] ?? faStar} />
|
icon={faGift}
|
||||||
|
className="referral-btn-icon"
|
||||||
|
/>
|
||||||
|
<span className="referral-btn-text">
|
||||||
|
Parrainage
|
||||||
|
{referralBalance > 0
|
||||||
|
? ` — ${referralBalance.toFixed(2)} €`
|
||||||
|
: ""}
|
||||||
|
</span>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faChevronRight}
|
||||||
|
className="referral-btn-chevron"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p className="stat-value">{poolPoints[i] || 0}</p>
|
|
||||||
<p className="stat-label">Pts {name}</p>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
{totalPoints > 0 && (
|
|
||||||
<div className="stat-card2">
|
|
||||||
<div className="stat-icon icon-total">
|
|
||||||
<FontAwesomeIcon icon={faTrophy} />
|
|
||||||
</div>
|
|
||||||
<p className="stat-value">{totalPoints}</p>
|
|
||||||
<p className="stat-label">Total Points</p>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Score amendes */}
|
{error && (
|
||||||
{appSettings.show_amende_score && (
|
<div className="error-banner">
|
||||||
<div className={`stat-card2${penaltyCount >= 3 ? ' stat-card-danger' : penaltyCount > 0 ? ' stat-card-warning' : ''}`}>
|
<FontAwesomeIcon
|
||||||
<div className={`stat-icon ${penaltyCount >= 3 ? 'icon-penalty-critical' : penaltyCount > 0 ? 'icon-penalty-warning' : 'icon-penalty-ok'}`}>
|
icon={faExclamationTriangle}
|
||||||
<FontAwesomeIcon icon={penaltyCount > 0 ? faExclamationTriangle : faShieldAlt} />
|
size="2x"
|
||||||
</div>
|
/>
|
||||||
<p className={`stat-value ${penaltyCount >= 3 ? 'value-danger' : penaltyCount > 0 ? 'value-warning' : ''}`}>{penaltyCount}</p>
|
<p>{error}</p>
|
||||||
<p className="stat-label">Score amendes</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Bouton parrainage */}
|
|
||||||
{appSettings.referral_enabled && (
|
|
||||||
<div className="referral-btn-row" onClick={() => navigate('/user/parrainage')}>
|
|
||||||
<FontAwesomeIcon icon={faGift} className="referral-btn-icon" />
|
|
||||||
<span className="referral-btn-text">
|
|
||||||
Parrainage{referralBalance > 0 ? ` — ${referralBalance.toFixed(2)} €` : ''}
|
|
||||||
</span>
|
|
||||||
<FontAwesomeIcon icon={faChevronRight} className="referral-btn-chevron" />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{error && (
|
|
||||||
<div className="error-banner">
|
|
||||||
<FontAwesomeIcon icon={faExclamationTriangle} size="2x" />
|
|
||||||
<p>{error}</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{orders.length === 0 ? (
|
|
||||||
<div className="empty-history">
|
|
||||||
<FontAwesomeIcon icon={faHistory} className="empty-icon" />
|
|
||||||
<h2>Aucun historique</h2>
|
|
||||||
<p>Vos commandes terminées apparaîtront ici</p>
|
|
||||||
<button className="browse-button" onClick={() => navigate('/user/accueil')}>
|
|
||||||
Découvrir nos produits
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<p className="section-title">Historique des commandes</p>
|
|
||||||
<div className="orders-list">
|
|
||||||
{orders.map((order) => (
|
|
||||||
<div
|
|
||||||
key={order.id}
|
|
||||||
className="order-card"
|
|
||||||
onClick={() => viewOrderDetails(order)}
|
|
||||||
>
|
|
||||||
<div className="order-card-header">
|
|
||||||
<span className="order-card-number">
|
|
||||||
Commande #{(order.client_order_number ?? 0).toString().padStart(4, '0')}
|
|
||||||
</span>
|
|
||||||
<span className="order-card-badge">
|
|
||||||
<FontAwesomeIcon icon={faCheckCircle} style={{ marginRight: '0.35rem' }} />
|
|
||||||
Livrée
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="order-card-row">
|
|
||||||
<FontAwesomeIcon icon={faMapMarkerAlt} className="order-card-row-icon" />
|
|
||||||
<span className="order-card-row-text">
|
|
||||||
{order.adresse ? (order.adresse.length > 50 ? order.adresse.substring(0, 50) + '…' : order.adresse) : 'N/A'}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="order-card-row">
|
|
||||||
<FontAwesomeIcon icon={faClock} className="order-card-row-icon" />
|
|
||||||
<span className="order-card-row-text">
|
|
||||||
{formatDate(order.created_at)} · {getOrderAge(order.created_at)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{order.livreur_assign && (
|
|
||||||
<div className="order-card-row">
|
|
||||||
<FontAwesomeIcon icon={faBicycle} className="order-card-row-icon" />
|
|
||||||
<span className="order-card-row-text">{order.livreur_assign}</span>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="order-card-footer">
|
{orders.length === 0 ? (
|
||||||
<span className="order-card-total">{formatPrice(order.total_prix || 0)}</span>
|
<div className="empty-history">
|
||||||
<FontAwesomeIcon icon={faChevronRight} className="order-card-chevron" />
|
<FontAwesomeIcon
|
||||||
</div>
|
icon={faHistory}
|
||||||
</div>
|
className="empty-icon"
|
||||||
))}
|
/>
|
||||||
|
<h2>Aucun historique</h2>
|
||||||
|
<p>Vos commandes terminées apparaîtront ici</p>
|
||||||
|
<button
|
||||||
|
className="browse-button"
|
||||||
|
onClick={() => navigate("/user/accueil")}
|
||||||
|
>
|
||||||
|
Découvrir nos produits
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<p className="section-title">
|
||||||
|
Historique des commandes
|
||||||
|
</p>
|
||||||
|
<div className="orders-list">
|
||||||
|
{orders.map((order) => (
|
||||||
|
<div
|
||||||
|
key={order.id}
|
||||||
|
className="order-card"
|
||||||
|
onClick={() => viewOrderDetails(order)}
|
||||||
|
>
|
||||||
|
<div className="order-card-header">
|
||||||
|
<span className="order-card-number">
|
||||||
|
Commande #
|
||||||
|
{(order.client_order_number ?? 0)
|
||||||
|
.toString()
|
||||||
|
.padStart(4, "0")}
|
||||||
|
</span>
|
||||||
|
<span className="order-card-badge">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faCheckCircle}
|
||||||
|
style={{
|
||||||
|
marginRight: "0.35rem",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
Livrée
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="order-card-row">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faMapMarkerAlt}
|
||||||
|
className="order-card-row-icon"
|
||||||
|
/>
|
||||||
|
<span className="order-card-row-text">
|
||||||
|
{order.adresse
|
||||||
|
? order.adresse.length > 50
|
||||||
|
? order.adresse.substring(
|
||||||
|
0,
|
||||||
|
50,
|
||||||
|
) + "…"
|
||||||
|
: order.adresse
|
||||||
|
: "N/A"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="order-card-row">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faClock}
|
||||||
|
className="order-card-row-icon"
|
||||||
|
/>
|
||||||
|
<span className="order-card-row-text">
|
||||||
|
{formatDate(order.created_at)} ·{" "}
|
||||||
|
{getOrderAge(order.created_at)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{order.livreur_assign && (
|
||||||
|
<div className="order-card-row">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faBicycle}
|
||||||
|
className="order-card-row-icon"
|
||||||
|
/>
|
||||||
|
<span className="order-card-row-text">
|
||||||
|
{order.livreur_assign}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="order-card-footer">
|
||||||
|
<span className="order-card-total">
|
||||||
|
{formatPrice(order.total_prix || 0)}
|
||||||
|
</span>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faChevronRight}
|
||||||
|
className="order-card-chevron"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
);
|
||||||
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ConsultationHistorique;
|
export default ConsultationHistorique;
|
||||||
|
|||||||
Reference in New Issue
Block a user