('');
@@ -365,7 +365,7 @@ function ConsultationHistorique() {
className="clickable-row"
>
|
- #{order.id.toString().padStart(5, '0')}
+ #{(order.client_order_number ?? 0).toString().padStart(4, '0')}
|
diff --git a/frontend-prep/src/pages/User/ModalSuccess.css b/frontend-prep/src/pages/User/ModalSuccess.css
index 8a88c0be..04f82c5f 100644
--- a/frontend-prep/src/pages/User/ModalSuccess.css
+++ b/frontend-prep/src/pages/User/ModalSuccess.css
@@ -26,7 +26,7 @@
}
.modal2-success-container {
- background: linear-gradient(135deg, rgba(0, 0, 0, 0.95) 0%, rgba(26, 26, 26, 0.95) 100%);
+ background: var(--surface);
border: 1px solid rgba(124, 58, 237, 0.3);
border-radius: 20px;
padding: 52px 44px;
@@ -156,7 +156,7 @@
align-items: center;
font-size: 15px;
padding: 12px 0;
- border-bottom: 1px solid rgba(255, 255, 255, 0.04);
+ border-bottom: 1px solid var(--border);
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
@@ -172,7 +172,7 @@
}
.detail2-label {
- color: rgba(255, 255, 255, 0.6);
+ color: var(--text-muted);
font-weight: 600;
letter-spacing: 0.4px;
text-transform: uppercase;
diff --git a/frontend-prep/src/pages/User/OrderDetails.css b/frontend-prep/src/pages/User/OrderDetails.css
index f1127f1e..92ed513d 100644
--- a/frontend-prep/src/pages/User/OrderDetails.css
+++ b/frontend-prep/src/pages/User/OrderDetails.css
@@ -9,7 +9,7 @@
padding-top: calc(60px + clamp(1rem, 3vw, 2rem));
max-width: 1400px;
margin: 0 auto;
- background: linear-gradient(to bottom, #0a0a0a, #1a1a1a);
+ background: linear-gradient(to bottom, var(--bg), var(--surface));
}
/* ============================================
@@ -34,7 +34,7 @@
.spinner {
width: 100%;
height: 100%;
- border: 4px solid #1a1a1a;
+ border: 4px solid var(--surface);
border-top-color: #7c3aed;
border-radius: 50%;
animation: spin 1s linear infinite;
@@ -47,7 +47,7 @@
}
.loading-text {
- color: #9ca3af;
+ color: var(--text-muted);
font-size: 1.1rem;
margin: 0;
}
@@ -58,14 +58,14 @@
}
.error-container h2 {
- color: white;
+ color: var(--text);
font-size: 1.8rem;
margin: 0;
font-weight: 700;
}
.error-container p {
- color: #9ca3af;
+ color: var(--text-muted);
font-size: 1.1rem;
margin: 0;
text-align: center;
@@ -88,9 +88,9 @@
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1.5rem;
- background: #1a1a1a;
- color: white;
- border: 1px solid #333;
+ background: var(--surface);
+ color: var(--text);
+ border: 1px solid var(--border);
border-radius: 8px;
font-size: 1rem;
font-weight: 600;
@@ -101,7 +101,7 @@
}
.back-button:hover {
- background: #2a2a2a;
+ background: var(--surface-2);
border-color: #7c3aed;
transform: translateX(-4px);
}
@@ -167,8 +167,8 @@
}
.details-card {
- background: #000000;
- border: 1px solid #333;
+ background: var(--bg);
+ border: 1px solid var(--border);
border-radius: 16px;
overflow: hidden;
transition: all 0.3s ease;
@@ -186,8 +186,8 @@
align-items: center;
gap: 0.75rem;
padding: 1.5rem;
- background: #1a1a1a;
- border-bottom: 1px solid #333;
+ background: var(--surface);
+ border-bottom: 1px solid var(--border);
}
.card-header svg {
@@ -196,7 +196,7 @@
}
.card-header h2 {
- color: white;
+ color: var(--text);
font-size: 1.25rem;
margin: 0;
font-weight: 700;
@@ -240,7 +240,7 @@
}
.info-label {
- color: #9ca3af;
+ color: var(--text-muted);
font-size: 0.85rem;
font-weight: 500;
text-transform: uppercase;
@@ -248,7 +248,7 @@
}
.info-value {
- color: white;
+ color: var(--text);
font-size: 1rem;
font-weight: 600;
line-height: 1.4;
@@ -279,8 +279,8 @@
display: flex;
gap: 1rem;
padding: 1rem;
- background: #1a1a1a;
- border: 1px solid #333;
+ background: var(--surface);
+ border: 1px solid var(--border);
border-radius: 12px;
transition: all 0.2s ease;
}
@@ -295,8 +295,8 @@
height: 80px;
object-fit: cover;
border-radius: 8px;
- background: #0a0a0a;
- border: 1px solid #333;
+ background: var(--bg);
+ border: 1px solid var(--border);
flex-shrink: 0;
}
@@ -375,7 +375,7 @@
position: relative;
width: 100%;
max-width: 900px;
- background: #1a1a1a;
+ background: var(--surface);
border-radius: 16px;
overflow: hidden;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
@@ -446,7 +446,7 @@
}
.product-name {
- color: white;
+ color: var(--text);
font-size: 1.1rem;
margin: 0;
font-weight: 600;
@@ -468,13 +468,13 @@
}
.product-quantity {
- color: #9ca3af;
+ color: var(--text-muted);
font-size: 0.9rem;
font-weight: 500;
}
.product-price {
- color: white;
+ color: var(--text);
font-size: 0.9rem;
font-weight: 600;
}
@@ -497,19 +497,19 @@
}
.placeholder-icon {
- color: #4b5563;
+ color: var(--text-muted);
opacity: 0.5;
}
.products-placeholder p {
- color: white;
+ color: var(--text);
font-size: 1.1rem;
margin: 0;
font-weight: 600;
}
.placeholder-note {
- color: #6b7280;
+ color: var(--text-muted);
font-size: 0.9rem;
font-style: italic;
}
@@ -519,19 +519,19 @@
============================================ */
.summary-card {
- background: linear-gradient(135deg, #1a1a1a, #0a0a0a);
+ background: linear-gradient(135deg, var(--surface), var(--bg));
}
.summary-row {
display: flex;
justify-content: space-between;
align-items: center;
- color: #9ca3af;
+ color: var(--text-muted);
font-size: 1rem;
}
.summary-row span:last-child {
- color: white;
+ color: var(--text);
font-weight: 600;
}
@@ -542,7 +542,7 @@
.summary-divider {
height: 1px;
- background: linear-gradient(to right, transparent, #333, transparent);
+ background: linear-gradient(to right, transparent, var(--border), transparent);
margin: 0.5rem 0;
}
@@ -553,7 +553,7 @@
}
.total-row span:first-child {
- color: white;
+ color: var(--text);
}
.total-amount {
@@ -570,12 +570,12 @@
}
.delivery-notes {
- color: #d1d5db;
+ color: var(--text-muted);
font-size: 1rem;
line-height: 1.6;
margin: 0;
padding: 1rem;
- background: #1a1a1a;
+ background: var(--surface);
border-left: 3px solid #7c3aed;
border-radius: 8px;
}
@@ -585,15 +585,15 @@
============================================ */
.delivery-timeline {
- background: #000000;
- border: 1px solid #333;
+ background: var(--bg);
+ border: 1px solid var(--border);
border-radius: 16px;
padding: 2rem;
margin-top: 2rem;
}
.timeline-title {
- color: white;
+ color: var(--text);
font-size: 1.5rem;
margin: 0 0 2rem 0;
font-weight: 700;
@@ -629,8 +629,8 @@
top: 0;
width: 16px;
height: 16px;
- background: #1a1a1a;
- border: 3px solid #333;
+ background: var(--surface);
+ border: 3px solid var(--border);
border-radius: 50%;
z-index: 1;
transition: all 0.3s ease;
@@ -643,14 +643,14 @@
}
.timeline-content h3 {
- color: white;
+ color: var(--text);
font-size: 1.1rem;
margin: 0 0 0.5rem 0;
font-weight: 600;
}
.timeline-content p {
- color: #9ca3af;
+ color: var(--text-muted);
font-size: 0.95rem;
margin: 0;
}
diff --git a/frontend-prep/src/pages/User/OrderDetails.tsx b/frontend-prep/src/pages/User/OrderDetails.tsx
index 50bd06de..64f6eb04 100644
--- a/frontend-prep/src/pages/User/OrderDetails.tsx
+++ b/frontend-prep/src/pages/User/OrderDetails.tsx
@@ -1,9 +1,3 @@
-// ============================================
-// pages/OrderDetails.tsx
-// ============================================
-// Page de détails d'une commande spécifique
-// ✅ AJOUT: Vérification continue de l'authentification
-
import { useState, useEffect } from "react";
import { useParams, useNavigate } from "react-router-dom";
import Navbar from "../../components/Navbar";
@@ -251,7 +245,6 @@ function OrderDetails() {
}, [order?.products]);
const fetchOrderDetails = async (id: number) => {
- // ✅ Vérifier l'auth avant de charger les détails
if (!isUserAuthenticated()) {
console.log("❌ [fetchOrderDetails] Non authentifié");
navigate("/login/client", { replace: true });
@@ -276,6 +269,8 @@ function OrderDetails() {
const orderData: OrderDetailsData = {
// Infos de command_info
id: apiData.command_info?.id || id,
+ client_order_number:
+ apiData.command_info?.client_order_number || 0,
username: apiData.client_info?.username || "",
status: apiData.command_info?.command_status || "unknown",
adresse: apiData.command_info?.command_address || "",
@@ -302,11 +297,11 @@ function OrderDetails() {
id: item.id,
product_id: item.product_id,
name_product: item.produit,
- category: "Non spécifié", // Pas de catégorie dans command_items
+ category: "Non spécifié",
price: item.prix,
quantity: item.quantite,
status: item.status,
- image: item.image, // Si vous avez des images
+ image: item.image,
})) || [],
};
@@ -390,7 +385,10 @@ function OrderDetails() {
- Commande #{order.id.toString().padStart(5, "0")}
+ Commande #
+ {(order.client_order_number ?? 0)
+ .toString()
+ .padStart(4, "0")}
diff --git a/frontend-prep/src/pages/User/Parrainage.css b/frontend-prep/src/pages/User/Parrainage.css
index 04dfb788..008cb1c9 100644
--- a/frontend-prep/src/pages/User/Parrainage.css
+++ b/frontend-prep/src/pages/User/Parrainage.css
@@ -9,7 +9,7 @@
padding-top: calc(60px + clamp(1.5rem, 4vw, 2.5rem));
max-width: 900px;
margin: 0 auto;
- background: linear-gradient(to bottom, #0a0a0a, #1a1a1a);
+ background: linear-gradient(to bottom, var(--bg), var(--surface));
display: flex;
flex-direction: column;
gap: 2rem;
@@ -41,7 +41,7 @@
}
.parrainage-subtitle {
- color: #9ca3af;
+ color: var(--text-muted);
font-size: clamp(0.95rem, 2.5vw, 1.1rem);
margin: 0;
}
@@ -59,7 +59,7 @@
}
.balance-label {
- color: #9ca3af;
+ color: var(--text-muted);
font-size: 0.875rem;
text-transform: uppercase;
letter-spacing: 0.08em;
@@ -67,7 +67,7 @@
}
.balance-amount {
- color: #6b7280;
+ color: var(--text-muted);
font-size: clamp(2.5rem, 7vw, 3.5rem);
font-weight: 700;
line-height: 1;
@@ -79,7 +79,7 @@
}
.balance-loading {
- color: #6b7280;
+ color: var(--text-muted);
font-size: 1.1rem;
}
@@ -89,12 +89,59 @@
margin-top: 0.5rem;
}
+/* ============================================
+ RÉCOMPENSE PAR PARRAINAGE
+ ============================================ */
+
+.parrainage-reward-card {
+ display: flex;
+ gap: 1rem;
+ background: linear-gradient(135deg, rgba(139, 92, 246, 0.12), rgba(99, 102, 241, 0.08));
+ border: 1px solid rgba(139, 92, 246, 0.35);
+ border-radius: 14px;
+ padding: 1.5rem;
+ align-items: center;
+}
+
+.reward-icon {
+ font-size: 2.2rem;
+ flex-shrink: 0;
+ color: #8b5cf6;
+}
+
+.reward-content {
+ display: flex;
+ flex-direction: column;
+ gap: 0.25rem;
+}
+
+.reward-label {
+ color: var(--text-muted);
+ font-size: 0.8rem;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+}
+
+.reward-amount {
+ color: #8b5cf6;
+ font-size: clamp(1.8rem, 5vw, 2.4rem);
+ font-weight: 700;
+ line-height: 1.1;
+}
+
+.reward-hint {
+ color: var(--text-muted);
+ font-size: 0.82rem;
+ line-height: 1.5;
+ margin: 0.2rem 0 0;
+}
+
/* ============================================
ÉTAPES
============================================ */
.parrainage-section-title {
- color: #e5e7eb;
+ color: var(--text);
font-size: 1.2rem;
font-weight: 600;
margin: 0 0 1.25rem;
@@ -110,8 +157,8 @@
}
.step-card {
- background: #111115;
- border: 1px solid rgba(255, 255, 255, 0.07);
+ background: var(--surface);
+ border: 1px solid var(--border);
border-radius: 12px;
padding: 1.25rem 1rem;
text-align: center;
@@ -138,14 +185,14 @@
}
.step-title {
- color: #f4f4f5;
+ color: var(--text);
font-size: 0.95rem;
font-weight: 600;
margin: 0 0 0.5rem;
}
.step-desc {
- color: #9ca3af;
+ color: var(--text-muted);
font-size: 0.82rem;
line-height: 1.5;
margin: 0;
@@ -179,7 +226,7 @@
}
.warning-text {
- color: #d1d5db;
+ color: var(--text-muted);
font-size: 0.875rem;
line-height: 1.55;
margin: 0 0 0.75rem;
@@ -190,7 +237,7 @@
border-radius: 8px;
padding: 0.6rem 0.75rem;
font-size: 0.85rem;
- color: #e5e7eb;
+ color: var(--text);
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
@@ -213,7 +260,7 @@
}
.cta-text {
- color: #9ca3af;
+ color: var(--text-muted);
font-size: 0.9rem;
margin: 0 0 1.25rem;
}
diff --git a/frontend-prep/src/pages/User/Parrainage.tsx b/frontend-prep/src/pages/User/Parrainage.tsx
index 5e963f48..c5cf9b5e 100644
--- a/frontend-prep/src/pages/User/Parrainage.tsx
+++ b/frontend-prep/src/pages/User/Parrainage.tsx
@@ -2,6 +2,7 @@ import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import Navbar from '../../components/Navbar';
import { getReferralBalance, isUserAuthenticated, getPublicSettings } from '../../api/api';
+import type { PublicSettings } from '../../api/api';
import './Parrainage.css';
const TELEGRAM_URL = 'https://t.me/';
@@ -37,6 +38,7 @@ export default function Parrainage() {
const navigate = useNavigate();
const [balance, setBalance] = useState(0);
const [loading, setLoading] = useState(true);
+ const [settings, setSettings] = useState(null);
useEffect(() => {
if (!isUserAuthenticated()) {
@@ -48,6 +50,7 @@ export default function Parrainage() {
navigate('/user/accueil', { replace: true });
return;
}
+ setSettings(s);
getReferralBalance().then((res) => {
if (res.success) setBalance(res.balance);
setLoading(false);
@@ -85,6 +88,21 @@ export default function Parrainage() {
)}
+ {/* Montant par parrainage */}
+ {settings && settings.referral_amount > 0 && (
+
+
+
+ Crédit par filleul parrainé
+ {settings.referral_amount.toFixed(2)} €
+
+ Vous recevrez ce montant sur votre solde dès que votre filleul
+ effectue sa première commande validée.
+
+
+
+ )}
+
{/* Étapes */}
Comment ça marche ?
diff --git a/frontend-prep/src/pages/User/ProductDetail.css b/frontend-prep/src/pages/User/ProductDetail.css
index 4adaa910..f41d75c6 100644
--- a/frontend-prep/src/pages/User/ProductDetail.css
+++ b/frontend-prep/src/pages/User/ProductDetail.css
@@ -9,14 +9,14 @@
padding: clamp(1rem, 3vw, 2rem);
padding-top: calc(60px + clamp(1rem, 3vw, 2rem));
box-sizing: border-box;
- background: linear-gradient(135deg, #0f0f0f 0%, #1a1a1a 100%);
+ background: var(--bg);
}
/* Back Button */
.product-detail-container > .back-button {
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%);
- color: white;
- border: 1px solid rgba(255, 255, 255, 0.1);
+ background: var(--surface-2);
+ color: var(--text);
+ border: 1px solid var(--border);
border-radius: 12px;
padding: clamp(0.75rem, 2vw, 1rem) clamp(1.5rem, 3vw, 2rem);
font-size: clamp(0.95rem, 3vw, 1.05rem);
@@ -33,10 +33,10 @@
}
.product-detail-container > .back-button:hover {
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.04) 100%);
- border-color: rgba(255, 255, 255, 0.2);
+ background: var(--surface);
+ border-color: var(--border);
transform: translateY(-2px);
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
}
.product-detail-container > .back-button:active {
@@ -71,9 +71,9 @@
border-radius: 20px;
overflow: hidden;
display: flex;
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.03) 0%, rgba(255, 255, 255, 0.01) 100%);
- border: 1px solid rgba(255, 255, 255, 0.08);
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
+ background: var(--surface);
+ border: 1px solid var(--border);
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
backdrop-filter: blur(8px);
transition: all 0.3s ease;
}
@@ -140,15 +140,12 @@
}
.product-detail-name {
- color: white;
+ color: var(--text);
font-size: clamp(2rem, 7vw, 3.5rem);
margin: 0;
font-weight: 700;
line-height: 1.1;
- background: linear-gradient(135deg, #ffffff 0%, #e0e0e0 100%);
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
+ -webkit-text-fill-color: unset;
letter-spacing: -1px;
}
@@ -175,8 +172,8 @@
/* Description */
.product-description {
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.03) 0%, rgba(255, 255, 255, 0.01) 100%);
- border: 1px solid rgba(255, 255, 255, 0.08);
+ background: var(--surface);
+ border: 1px solid var(--border);
border-left: 3px solid var(--cat-color, #7c3aed);
border-radius: 12px;
padding: clamp(1.25rem, 3vw, 1.75rem);
@@ -191,7 +188,7 @@
}
.product-description h3 {
- color: rgba(255, 255, 255, 0.9);
+ color: var(--text);
font-size: clamp(1.1rem, 4vw, 1.3rem);
margin: 0 0 1rem 0;
font-weight: 600;
@@ -200,7 +197,7 @@
}
.product-description p {
- color: rgba(255, 255, 255, 0.7);
+ color: var(--text-muted);
font-size: clamp(1rem, 3vw, 1.1rem);
margin: 0;
line-height: 1.7;
@@ -213,9 +210,9 @@
gap: clamp(1rem, 3vw, 1.5rem);
flex-wrap: wrap;
padding: clamp(1rem, 3vw, 1.5rem);
- background: rgba(255, 255, 255, 0.02);
+ background: var(--surface);
border-radius: 12px;
- border: 1px solid rgba(255, 255, 255, 0.05);
+ border: 1px solid var(--border);
}
/* Grams Selector */
@@ -228,7 +225,7 @@
}
.grams-selector label {
- color: rgba(255, 255, 255, 0.9);
+ color: var(--text);
font-size: clamp(1rem, 3vw, 1.15rem);
font-weight: 600;
white-space: nowrap;
@@ -236,9 +233,9 @@
.grams-dropdown {
flex: 1;
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%);
- color: white;
- border: 1px solid rgba(255, 255, 255, 0.1);
+ background: var(--surface-2);
+ color: var(--text);
+ border: 1px solid var(--border);
border-radius: 10px;
padding: clamp(0.75rem, 2vw, 1rem) clamp(1rem, 3vw, 1.25rem);
font-size: clamp(1rem, 3vw, 1.1rem);
@@ -275,17 +272,17 @@
/* Styles des options - Supprimer le hover natif */
.grams-dropdown option {
- background-color: #1a1a1a;
- color: white;
+ background-color: var(--surface);
+ color: var(--text);
padding: 1rem;
font-size: 1rem;
font-weight: 600;
}
.grams-dropdown option:hover {
- background-color: #1a1a1a !important;
- background: #1a1a1a !important;
- color: white !important;
+ background-color: var(--surface) !important;
+ background: var(--surface) !important;
+ color: var(--text) !important;
}
.grams-dropdown option:checked {
@@ -295,7 +292,7 @@
}
.grams-dropdown option:focus {
- background-color: #1a1a1a !important;
+ background-color: var(--surface) !important;
outline: none !important;
}
@@ -303,7 +300,7 @@
.grams-dropdown option:hover,
.grams-dropdown option:focus,
.grams-dropdown option:active {
- background-color: #1a1a1a !important;
+ background-color: var(--surface) !important;
background-image: none !important;
box-shadow: none !important;
}
@@ -311,7 +308,7 @@
/* Pour Firefox */
@-moz-document url-prefix() {
.grams-dropdown option:hover {
- background-color: #1a1a1a !important;
+ background-color: var(--surface) !important;
}
}
@@ -386,8 +383,8 @@
}
.add-to-cart-button.disabled {
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.05) 100%);
- color: rgba(255, 255, 255, 0.4);
+ background: var(--surface-2);
+ color: var(--text-muted);
cursor: not-allowed;
box-shadow: none;
}
@@ -407,7 +404,7 @@
background: linear-gradient(135deg, rgba(239, 68, 68, 0.1) 0%, rgba(239, 68, 68, 0.05) 100%);
border: 1px solid rgba(239, 68, 68, 0.3);
border-radius: 16px;
- color: white;
+ color: var(--text);
animation: slideUp 0.5s ease-out;
}
@@ -418,9 +415,9 @@
}
.error-message .back-button {
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%);
- color: white;
- border: 1px solid rgba(255, 255, 255, 0.1);
+ background: var(--surface-2);
+ color: var(--text);
+ border: 1px solid var(--border);
border-radius: 10px;
padding: clamp(0.75rem, 2vw, 1rem) clamp(1.5rem, 3vw, 2rem);
font-size: clamp(1rem, 3vw, 1.1rem);
@@ -431,8 +428,8 @@
}
.error-message .back-button:hover {
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.04) 100%);
- border-color: rgba(255, 255, 255, 0.2);
+ background: var(--surface);
+ border-color: var(--border);
transform: translateY(-2px);
}
@@ -449,13 +446,13 @@
padding: clamp(3rem, 8vw, 5rem);
text-align: center;
min-height: 400px;
- color: white;
+ color: var(--text);
animation: slideUp 0.5s ease-out;
}
.loading-container p {
font-size: clamp(1rem, 3vw, 1.2rem);
- color: rgba(255, 255, 255, 0.7);
+ color: var(--text-muted);
margin-top: 1.5rem;
}
diff --git a/frontend-prep/src/pages/User/ProfilePage.css b/frontend-prep/src/pages/User/ProfilePage.css
index ccffbd1b..83413ae4 100644
--- a/frontend-prep/src/pages/User/ProfilePage.css
+++ b/frontend-prep/src/pages/User/ProfilePage.css
@@ -33,13 +33,13 @@
.profile-title {
font-size: 1.6rem;
font-weight: 700;
- color: #f0f0f0;
+ color: var(--text);
margin: 0;
}
.profile-username {
font-size: 0.9rem;
- color: #9ca3af;
+ color: var(--text-muted);
margin: 0.2rem 0 0;
}
@@ -66,8 +66,8 @@
/* Cards */
.profile-card {
- background: #1e1e2e;
- border: 1px solid #2d2d40;
+ background: var(--surface);
+ border: 1px solid var(--border);
border-radius: 12px;
padding: 1.5rem;
margin-bottom: 1.2rem;
@@ -76,7 +76,7 @@
.profile-card-title {
font-size: 1rem;
font-weight: 600;
- color: #e2e8f0;
+ color: var(--text);
margin: 0 0 1rem;
display: flex;
align-items: center;
@@ -86,10 +86,11 @@
.profile-card-icon { color: #7c3aed; }
.profile-card-icon--address { color: #10b981; }
.profile-card-icon--phone { color: #3b82f6; }
+.profile-card-icon--telegram { color: #2AABEE; }
.profile-hint {
font-size: 0.82rem;
- color: #6b7280;
+ color: var(--text-muted);
margin: -0.5rem 0 1rem;
line-height: 1.5;
}
@@ -108,15 +109,15 @@
.profile-group label {
font-size: 0.82rem;
font-weight: 500;
- color: #9ca3af;
+ color: var(--text-muted);
}
.profile-group input {
- background: #12121f;
- border: 1px solid #2d2d40;
+ background: var(--bg);
+ border: 1px solid var(--border);
border-radius: 8px;
padding: 0.65rem 0.9rem;
- color: #e2e8f0;
+ color: var(--text);
font-size: 0.9rem;
outline: none;
transition: border-color 0.2s;
@@ -125,7 +126,7 @@
}
.profile-group input:focus { border-color: #7c3aed; }
-.profile-group input::placeholder { color: #4b5563; }
+.profile-group input::placeholder { color: var(--text-muted); }
/* Buttons */
.profile-btn {
@@ -145,14 +146,141 @@
}
.profile-btn--secondary {
- background: #1a3a5c;
+ background: var(--surface-2);
color: #60a5fa;
- border: 1px solid #2563eb44;
+ border: 1px solid rgba(37, 99, 235, 0.27);
}
.profile-btn:hover { opacity: 0.85; }
.profile-btn:disabled { opacity: 0.5; cursor: not-allowed; }
+.profile-btn--telegram {
+ background: #2AABEE;
+}
+
+.profile-btn--danger {
+ background: transparent;
+ border: 1px solid #ef444466;
+ color: #ef4444;
+}
+
+.profile-telegram-linked {
+ display: flex;
+ flex-direction: column;
+ gap: 0.8rem;
+}
+
+.profile-telegram-status {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ color: #10b981;
+ font-size: 0.88rem;
+ font-weight: 500;
+}
+
@media (max-width: 480px) {
.profile-row { grid-template-columns: 1fr; }
}
+
+/* Modal confirmation */
+.profile-modal-overlay {
+ position: fixed;
+ inset: 0;
+ background: rgba(0, 0, 0, 0.6);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1000;
+ padding: 1rem;
+ backdrop-filter: blur(2px);
+}
+
+.profile-modal {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: 14px;
+ padding: 2rem 1.8rem 1.6rem;
+ max-width: 400px;
+ width: 100%;
+ position: relative;
+ text-align: center;
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
+}
+
+.profile-modal-close {
+ position: absolute;
+ top: 0.8rem;
+ right: 0.9rem;
+ background: transparent;
+ border: none;
+ color: var(--text-muted);
+ font-size: 1rem;
+ cursor: pointer;
+ padding: 0.3rem 0.5rem;
+ border-radius: 6px;
+ transition: color 0.2s;
+}
+.profile-modal-close:hover { color: var(--text); }
+
+.profile-modal-icon {
+ width: 52px;
+ height: 52px;
+ border-radius: 50%;
+ background: rgba(37, 99, 235, 0.15);
+ border: 1px solid rgba(37, 99, 235, 0.3);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 1.3rem;
+ color: #60a5fa;
+ margin: 0 auto 1.1rem;
+}
+
+.profile-modal-title {
+ font-size: 1.05rem;
+ font-weight: 700;
+ color: var(--text);
+ margin: 0 0 0.6rem;
+}
+
+.profile-modal-body {
+ font-size: 0.85rem;
+ color: var(--text-muted);
+ line-height: 1.55;
+ margin: 0 0 1.5rem;
+}
+
+.profile-modal-actions {
+ display: flex;
+ gap: 0.8rem;
+ justify-content: center;
+}
+
+.profile-modal-btn {
+ flex: 1;
+ padding: 0.65rem 1rem;
+ border-radius: 8px;
+ font-size: 0.88rem;
+ font-weight: 600;
+ cursor: pointer;
+ border: none;
+ transition: opacity 0.2s;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.4rem;
+}
+.profile-modal-btn:hover { opacity: 0.85; }
+
+.profile-modal-btn--cancel {
+ background: var(--bg);
+ border: 1px solid var(--border);
+ color: var(--text-muted);
+}
+
+.profile-modal-btn--confirm {
+ background: var(--surface-2);
+ border: 1px solid rgba(37, 99, 235, 0.27);
+ color: #60a5fa;
+}
diff --git a/frontend-prep/src/pages/User/ProfilePage.tsx b/frontend-prep/src/pages/User/ProfilePage.tsx
index 1509e8c5..6df65bbd 100644
--- a/frontend-prep/src/pages/User/ProfilePage.tsx
+++ b/frontend-prep/src/pages/User/ProfilePage.tsx
@@ -1,11 +1,11 @@
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import Navbar from '../../components/Navbar';
-import { isUserAuthenticated, extractUsernameFromToken, getMyProfile, updateMyProfile } from '../../api/api';
+import { isUserAuthenticated, extractUsernameFromToken, getMyProfile, updateMyProfile, getTelegramStatus, generateTelegramLinkToken, unlinkTelegram } from '../../api/api';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faUser, faMapMarkerAlt, faPhone, faCommentDots,
- faSave, faCheckCircle, faExclamationTriangle,
+ faSave, faCheckCircle, faExclamationTriangle, faPaperPlane, faUnlink, faTimes, faLock,
} from '@fortawesome/free-solid-svg-icons';
import './ProfilePage.css';
@@ -32,6 +32,14 @@ export default function ProfilePage() {
const [successMsg, setSuccessMsg] = useState('');
const [errorMsg, setErrorMsg] = useState('');
+ // Telegram
+ const [tgLinked, setTgLinked] = useState(false);
+ const [tgEnabled, setTgEnabled] = useState(false);
+ const [tgLoading, setTgLoading] = useState(false);
+
+ // Modal confirmation infos par défaut
+ const [showSaveModal, setShowSaveModal] = useState(false);
+
const username = extractUsernameFromToken() ?? '';
useEffect(() => {
@@ -44,6 +52,9 @@ export default function ProfilePage() {
setDefaultPhone(localStorage.getItem(STORAGE_PHONE) ?? '');
setSignalPseudo(localStorage.getItem(STORAGE_SIGNAL) || username);
+ // Statut Telegram
+ getTelegramStatus().then((s) => { setTgLinked(s.linked); setTgEnabled(s.enabled); });
+
// Charger depuis backend
getMyProfile().then((res) => {
if (res.success && res.client) {
@@ -74,9 +85,28 @@ export default function ProfilePage() {
localStorage.setItem(STORAGE_ADDRESS, defaultAddress.trim());
localStorage.setItem(STORAGE_PHONE, defaultPhone.trim());
localStorage.setItem(STORAGE_SIGNAL, signalPseudo.trim());
+ setShowSaveModal(false);
showSuccess('Informations par défaut enregistrées');
};
+ const handleLinkTelegram = async () => {
+ setTgLoading(true);
+ const res = await generateTelegramLinkToken();
+ setTgLoading(false);
+ if (res.error || !res.link_url) {
+ showError(res.error || 'Service Telegram non disponible');
+ return;
+ }
+ window.open(res.link_url, '_blank');
+ };
+
+ const handleUnlinkTelegram = async () => {
+ if (!window.confirm('Délier votre compte Telegram ? Vous ne recevrez plus de notifications.')) return;
+ await unlinkTelegram();
+ setTgLinked(false);
+ showSuccess('Compte Telegram délié');
+ };
+
const saveContact = async () => {
setSavingContact(true);
const res = await updateMyProfile({ nom: nom.trim(), prenom: prenom.trim(), telephone: telephone.trim() });
@@ -165,6 +195,9 @@ export default function ProfilePage() {
{savingContact ? ' Enregistrement...' : ' Enregistrer le compte'}
+
{/* Section adresse par défaut */}
@@ -217,11 +250,63 @@ export default function ProfilePage() {
placeholder="@votre.pseudo.signal"
/>
-
+ {/* Section Telegram */}
+ {tgEnabled && (
+
+
+
+ Notifications Telegram
+
+
+ Recevez vos notifications sur Telegram, même quand le site est fermé.
+
+ {tgLinked ? (
+
+
+ Compte Telegram lié
+
+
+ Délier Telegram
+
+
+ ) : (
+
+
+ {tgLoading ? ' Génération du lien...' : ' Lier mon compte Telegram'}
+
+ )}
+
+ )}
+
+ {showSaveModal && (
+ setShowSaveModal(false)}>
+ e.stopPropagation()}>
+ setShowSaveModal(false)}>
+
+
+
+
+
+ Enregistrer les infos par défaut ?
+
+ Adresse, téléphone de livraison et pseudo Signal seront sauvegardés localement et pré-remplis lors de vos prochaines commandes.
+
+
+ setShowSaveModal(false)}>
+ Annuler
+
+
+ Confirmer
+
+
+
+
+ )}
>
);
}
diff --git a/frontend-prep/src/pages/User/SuiviLivraison.css b/frontend-prep/src/pages/User/SuiviLivraison.css
index 2b1d2242..3f0cfcd5 100644
--- a/frontend-prep/src/pages/User/SuiviLivraison.css
+++ b/frontend-prep/src/pages/User/SuiviLivraison.css
@@ -9,8 +9,8 @@
padding-top: calc(60px + clamp(1.5rem, 4vw, 2.5rem));
max-width: 860px;
margin: 0 auto;
- background: #0d0d0d;
- color: white;
+ background: var(--bg);
+ color: var(--text);
}
/* ===== HEADER ===== */
@@ -21,14 +21,14 @@
.suivi-header h1 {
font-size: clamp(1.6rem, 5vw, 2.2rem);
- color: #fff;
+ color: var(--text);
margin: 0 0 0.3rem 0;
letter-spacing: -0.5px;
}
.suivi-header p {
font-size: clamp(0.85rem, 2.5vw, 0.95rem);
- color: rgba(255, 255, 255, 0.4);
+ color: var(--text-muted);
margin: 0;
}
@@ -88,7 +88,7 @@
}
.loading-state p {
- color: rgba(255, 255, 255, 0.45);
+ color: var(--text-muted);
font-size: 0.95rem;
}
@@ -96,26 +96,26 @@
.empty-state {
text-align: center;
padding: clamp(3rem, 8vw, 5rem) 2rem;
- border: 1px solid rgba(255, 255, 255, 0.06);
+ border: 1px solid var(--border);
border-radius: 20px;
- background: rgba(255, 255, 255, 0.02);
+ background: var(--surface);
}
.empty-state-icon {
font-size: 3.5rem;
- color: rgba(255, 255, 255, 0.15);
+ color: var(--text-muted);
margin-bottom: 1.5rem;
}
.empty-state h2 {
font-size: 1.3rem;
font-weight: 700;
- color: rgba(255, 255, 255, 0.8);
+ color: var(--text);
margin: 0 0 0.5rem 0;
}
.empty-state p {
- color: rgba(255, 255, 255, 0.4);
+ color: var(--text-muted);
font-size: 0.95rem;
margin: 0 0 2rem 0;
}
@@ -149,8 +149,8 @@
/* ===== ORDER CARD ===== */
.order-card {
- background: #161616;
- border: 1px solid rgba(255, 255, 255, 0.07);
+ background: var(--surface);
+ border: 1px solid var(--border);
border-radius: 18px;
overflow: hidden;
transition:
@@ -196,7 +196,7 @@
}
.order-header:hover {
- background: rgba(255, 255, 255, 0.02);
+ background: var(--surface-2);
}
.order-header-left {
@@ -217,7 +217,7 @@
.order-id {
font-size: 1rem;
font-weight: 700;
- color: #fff;
+ color: var(--text);
}
.status-badge {
@@ -300,7 +300,7 @@
.order-date {
font-size: 0.8rem;
- color: rgba(255, 255, 255, 0.35);
+ color: var(--text-muted);
}
.order-header-right {
@@ -323,8 +323,8 @@
width: 28px;
height: 28px;
border-radius: 8px;
- background: rgba(255, 255, 255, 0.05);
- color: rgba(255, 255, 255, 0.4);
+ background: var(--surface-2);
+ color: var(--text-muted);
font-size: 0.75rem;
transition: all 0.2s ease;
}
@@ -336,7 +336,7 @@
/* ===== EXPANDED DETAILS ===== */
.order-details {
- border-top: 1px solid rgba(255, 255, 255, 0.05);
+ border-top: 1px solid var(--border);
animation: expandDown 0.3s ease-out;
overflow: hidden;
}
@@ -383,7 +383,7 @@
left: calc(-50% + 14px);
right: calc(50% + 14px);
height: 2px;
- background: rgba(255, 255, 255, 0.08);
+ background: var(--border);
z-index: 0;
}
@@ -404,9 +404,9 @@
align-items: center;
justify-content: center;
font-size: 0.7rem;
- border: 2px solid rgba(255, 255, 255, 0.1);
- background: #1e1e1e;
- color: rgba(255, 255, 255, 0.3);
+ border: 2px solid var(--border);
+ background: var(--surface-2);
+ color: var(--text-muted);
transition: all 0.3s ease;
z-index: 1;
position: relative;
@@ -427,7 +427,7 @@
.timeline-label {
font-size: 0.62rem;
- color: rgba(255, 255, 255, 0.3);
+ color: var(--text-muted);
margin-top: 0.4rem;
text-align: center;
line-height: 1.3;
@@ -440,7 +440,7 @@
}
.timeline-step.done .timeline-label {
- color: rgba(255, 255, 255, 0.5);
+ color: var(--text-muted);
}
/* ===== DETAIL SECTIONS ===== */
@@ -452,7 +452,7 @@
.detail-section {
padding: 1rem 1.4rem;
- border-top: 1px solid rgba(255, 255, 255, 0.04);
+ border-top: 1px solid var(--border);
}
.detail-section:first-child {
@@ -467,13 +467,13 @@
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.8px;
- color: rgba(255, 255, 255, 0.35);
+ color: var(--text-muted);
font-weight: 700;
}
.detail-section p {
margin: 0;
- color: rgba(255, 255, 255, 0.85);
+ color: var(--text);
font-size: 0.95rem;
line-height: 1.5;
}
@@ -481,16 +481,16 @@
.detail-section small {
display: block;
margin-top: 0.35rem;
- color: rgba(255, 255, 255, 0.35);
+ color: var(--text-muted);
font-size: 0.8rem;
}
.address {
font-weight: 600;
- color: #fff;
+ color: var(--text);
}
.contact {
- color: rgba(255, 255, 255, 0.5);
+ color: var(--text-muted);
font-size: 0.85rem;
margin-top: 0.25rem;
}
@@ -574,7 +574,7 @@
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.7px;
- color: rgba(255, 255, 255, 0.4);
+ color: var(--text-muted);
font-weight: 700;
margin: 0 0 0.2rem 0;
}
@@ -593,7 +593,7 @@
.eta-card-sub {
font-size: 0.8rem;
- color: rgba(255, 255, 255, 0.4);
+ color: var(--text-muted);
margin: 0.2rem 0 0 0;
}
@@ -609,13 +609,13 @@
justify-content: space-between;
align-items: center;
padding: 0.6rem 0.9rem;
- background: rgba(255, 255, 255, 0.025);
+ background: var(--surface-2);
border-radius: 9px;
- border: 1px solid rgba(255, 255, 255, 0.04);
+ border: 1px solid var(--border);
}
.item-name {
- color: rgba(255, 255, 255, 0.8);
+ color: var(--text);
font-size: 0.9rem;
}
@@ -637,8 +637,8 @@
/* ===== ACTIONS ===== */
.order-actions {
padding: 1.2rem 1.4rem;
- border-top: 1px solid rgba(255, 255, 255, 0.05);
- background: rgba(0, 0, 0, 0.15);
+ border-top: 1px solid var(--border);
+ background: var(--surface-2);
}
.action-buttons {
@@ -668,7 +668,7 @@
.notice-title {
font-size: 1rem;
font-weight: 700;
- color: #fff;
+ color: var(--text);
margin: 0 0 0.3rem 0;
display: flex;
align-items: center;
@@ -678,7 +678,7 @@
.notice-subtitle {
font-size: 0.85rem;
- color: rgba(255, 255, 255, 0.5);
+ color: var(--text-muted);
margin: 0;
}
@@ -727,15 +727,15 @@
.btn-secondary,
.btn-cancel {
- background: rgba(255, 255, 255, 0.06);
- color: rgba(255, 255, 255, 0.7);
- border: 1px solid rgba(255, 255, 255, 0.1);
+ background: var(--surface-2);
+ color: var(--text-muted);
+ border: 1px solid var(--border);
}
.btn-secondary:hover,
.btn-cancel:hover {
- background: rgba(255, 255, 255, 0.09);
- color: #fff;
+ background: var(--surface);
+ color: var(--text);
}
.btn-danger,
@@ -754,7 +754,7 @@
.btn-confirm-delivery:disabled,
.btn-cancel-order:disabled,
.btn-danger:disabled {
- background: rgba(255, 255, 255, 0.07);
+ background: var(--surface-2);
cursor: not-allowed;
box-shadow: none;
opacity: 0.5;
@@ -791,10 +791,10 @@
margin-top: 2rem;
text-align: center;
padding: 1rem;
- background: rgba(255, 255, 255, 0.02);
- border: 1px solid rgba(255, 255, 255, 0.05);
+ background: var(--surface);
+ border: 1px solid var(--border);
border-radius: 12px;
- color: rgba(255, 255, 255, 0.3);
+ color: var(--text-muted);
font-size: 0.8rem;
}
@@ -826,8 +826,8 @@
}
.confirm-dialog {
- background: #1a1a1a;
- border: 1px solid rgba(255, 255, 255, 0.12);
+ background: var(--surface);
+ border: 1px solid var(--border);
border-radius: 20px;
max-width: 480px;
width: 90%;
@@ -856,14 +856,14 @@
.confirm-dialog-header {
padding: 1.4rem 1.5rem;
- border-bottom: 1px solid rgba(255, 255, 255, 0.07);
+ border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.confirm-dialog-header h3 {
margin: 0;
font-size: 1.1rem;
- color: white;
+ color: var(--text);
font-weight: 700;
display: flex;
align-items: center;
@@ -872,7 +872,7 @@
.confirm-dialog-body {
padding: 1.5rem;
- color: rgba(255, 255, 255, 0.75);
+ color: var(--text);
overflow-y: auto;
flex: 1;
-webkit-overflow-scrolling: touch;
@@ -932,7 +932,7 @@
display: flex;
gap: 0.75rem;
flex-shrink: 0;
- border-top: 1px solid rgba(255, 255, 255, 0.06);
+ border-top: 1px solid var(--border);
}
.confirm-dialog-actions .btn-cancel,
@@ -958,16 +958,16 @@
.cancel-form label {
font-weight: 600;
- color: rgba(255, 255, 255, 0.8);
+ color: var(--text);
font-size: 0.9rem;
}
.cancel-form textarea {
- background: rgba(255, 255, 255, 0.04);
- border: 1px solid rgba(255, 255, 255, 0.1);
+ background: var(--bg);
+ border: 1px solid var(--border);
border-radius: 10px;
padding: 0.75rem;
- color: white;
+ color: var(--text);
font-family: inherit;
resize: vertical;
min-height: 90px;
@@ -982,7 +982,7 @@
}
.cancel-form small {
- color: rgba(255, 255, 255, 0.35);
+ color: var(--text-muted);
font-size: 0.8rem;
text-align: right;
}
@@ -997,7 +997,7 @@
align-items: flex-start;
font-size: 0.88rem;
line-height: 1.5;
- color: rgba(255, 255, 255, 0.6);
+ color: var(--text-muted);
}
.info-message svg {
@@ -1041,15 +1041,15 @@
}
.warning-details {
- background: rgba(255, 255, 255, 0.04);
+ background: var(--surface-2);
padding: 0.9rem;
border-radius: 10px;
- border: 1px solid rgba(255, 255, 255, 0.08);
+ border: 1px solid var(--border);
}
.warning-details p {
margin: 0.4rem 0;
- color: rgba(255, 255, 255, 0.7);
+ color: var(--text);
font-size: 0.9rem;
}
@@ -1068,14 +1068,14 @@
}
.penalty-message {
- color: rgba(255, 255, 255, 0.65);
+ color: var(--text-muted);
text-align: center;
margin-bottom: 1rem;
font-size: 0.9rem;
}
.penalty-scale {
- background: rgba(255, 255, 255, 0.03);
+ background: var(--surface-2);
padding: 0.9rem;
border-radius: 8px;
}
@@ -1092,9 +1092,9 @@
}
.penalty-scale li {
padding: 0.4rem 0;
- border-bottom: 1px solid rgba(255, 255, 255, 0.05);
+ border-bottom: 1px solid var(--border);
font-size: 0.85rem;
- color: rgba(255, 255, 255, 0.65);
+ color: var(--text-muted);
}
.penalty-scale li:last-child {
border-bottom: none;
@@ -1103,7 +1103,7 @@
.warning-question {
font-size: 0.95rem;
font-weight: 700;
- color: rgba(255, 255, 255, 0.85);
+ color: var(--text);
text-align: center;
margin-top: 0.5rem;
}
diff --git a/frontend-prep/src/pages/User/SuiviLivraison.tsx b/frontend-prep/src/pages/User/SuiviLivraison.tsx
index 1b38e74e..c74e0a29 100644
--- a/frontend-prep/src/pages/User/SuiviLivraison.tsx
+++ b/frontend-prep/src/pages/User/SuiviLivraison.tsx
@@ -675,7 +675,7 @@ function SuiviLivraison() {
- Commande #{order.id}
+ Commande #{order.client_order_number}
|