/** * ========================================================================= * PLATEFORME ECO-PANNEAU.FR - VERSION 1.0.0 * Composant : Modale de paiement et tunnel Stripe (Checkout) * ========================================================================= */ const { useState } = React; window.ClientCheckoutModal = ({ managingPanneau, setManagingPanneau, data, myClientData, profileData, onClose, onBackToEditor, refreshData, showToast }) => { const XIcon = window.XIcon || (() => null); const AlertTriangleIcon = window.AlertTriangleIcon || (() => null); const PackageIcon = window.PackageIcon || (() => null); const LoaderIcon = window.LoaderIcon || (() => null); const CreditCardIcon = window.CreditCardIcon || (() => null); const StripeElements = window.StripeElements || (() => null); const ModalOverlay = window.ModalOverlay || (({ children }) =>
{children}
); // COMPOSANTS GLOBAUX NETTOYÉS const AlertBox = window.AlertBox; const Button = window.Button; const [step, setStep] = useState('select'); const [paymentData, setPaymentData] = useState(null); const [waiverAccepted, setWaiverAccepted] = useState(false); const [isSaving, setIsSaving] = useState(false); const isSuspended = myClientData.paymentStatus === 'suspended'; const purchasesAllowed = data.settings?.allow_new_purchases !== '0'; const pRental = data.prices?.rentalMo ?? 180; const pPurchase = data.prices?.purchase ?? 850; const pHosting = data.prices?.hostingYr ?? 1; const pBoardFirst = data.prices?.boardFirst ?? 250; const pBoardAdd = data.prices?.boardAdd ?? 150; const pNoAds = data.prices?.noAds ?? 150; const originalPanneau = data.panneaux?.find(p => p.id === managingPanneau?.id); const isActif = originalPanneau?.status === 'Actif'; const originalOfferType = originalPanneau?.offerType || 'rental'; const originalPanels = originalPanneau?.physicalPanels || 0; const originalHasNoAds = originalPanneau?.hasNoAds || false; const currentOfferType = managingPanneau?.offerType || 'rental'; const currentPanels = managingPanneau?.physicalPanels || 0; const currentHasNoAds = managingPanneau?.hasNoAds || false; let addedPanelsCost = 0; if (currentPanels > originalPanels) { const costNew = currentPanels > 0 ? pBoardFirst + (currentPanels - 1) * pBoardAdd : 0; const costOld = originalPanels > 0 ? pBoardFirst + (originalPanels - 1) * pBoardAdd : 0; addedPanelsCost = Math.max(0, costNew - costOld); } let upfrontHT = 0; if (!isActif) { upfrontHT = (currentPanels > 0 ? pBoardFirst + (currentPanels - 1) * pBoardAdd : 0) + (currentHasNoAds ? pNoAds : 0) + (currentOfferType === 'rental' ? pRental : pPurchase); } else { if (originalOfferType === 'rental' && currentOfferType === 'purchase') upfrontHT += pPurchase; if (currentHasNoAds && !originalHasNoAds) upfrontHT += pNoAds; upfrontHT += addedPanelsCost; } const discountPct = myClientData.discount || 0; const priceMultiplier = Math.max(0, (100 - discountPct) / 100); const platformHasTva = data.settings?.billing_has_tva !== '0'; const tvaMult = platformHasTva ? 1.20 : 1.00; const finalUpfrontTTC = upfrontHT * priceMultiplier * tvaMult; const finalMonthlyTTC = pRental * priceMultiplier * tvaMult; const remainingToPay = Math.max(0, finalUpfrontTTC - (myClientData.wallet_balance || 0)); const handleActivationRequest = async () => { if(isSuspended) return showToast("Votre compte est suspendu. Veuillez régulariser vos factures.", "error"); if(!purchasesAllowed) return showToast("Les nouvelles commandes sont suspendues.", "error"); if(!waiverAccepted) return showToast("Veuillez accepter la renonciation au délai de rétractation de 14 jours.", "error"); const payload = { panneau_id: managingPanneau.id, offer_type: managingPanneau.offerType, physical_panels: managingPanneau.physicalPanels, hasNoAds: managingPanneau.hasNoAds }; const d = await window.apiFetch('stripe/intent', { body: payload, setLoading: setIsSaving }); if (d) { if (d.data.free_activation_required) { const freeRes = await window.apiFetch('panneaux/activate_free', { body: { ...payload, id: managingPanneau.id, offerType: managingPanneau.offerType, physicalPanels: managingPanneau.physicalPanels, details: managingPanneau, name: managingPanneau.name }, successMessage: "Mise à jour et activation réussie !" }); if (freeRes) { onClose(); refreshData(); } } else { setPaymentData({ secret: d.data.clientSecret, subId: d.data.subscription_id, amountCents: d.data.amountCents }); setStep('payment'); } } }; const handlePaymentSuccess = async (pi_id) => { const payload = { payment_intent_id: pi_id, subscription_id: paymentData?.subId, id: managingPanneau.id, offerType: managingPanneau.offerType, currentRate: managingPanneau.currentRate, physicalPanels: managingPanneau.physicalPanels, details: managingPanneau, name: managingPanneau.name }; const d = await window.apiFetch('panneaux/activate_paid', { body: payload, setLoading: setIsSaving, successMessage: "Paiement validé ! Panneau activé." }); if (d) { onClose(); refreshData(); } }; if (step === 'payment' && paymentData && window.StripeElements) { return ( { setStep('select'); setPaymentData(null); }} preventClose={isSaving}>
e.stopPropagation()}>

Paiement sécurisé

{ setStep('select'); setPaymentData(null); }} className="text-slate-400 hover:text-white hover:bg-slate-800 p-2 rounded-xl transition cursor-pointer" title="Fermer">
Montant à régler : {(paymentData.amountCents / 100).toFixed(2)} €
); } return (
e.stopPropagation()}>

Détails de facturation

Configurez votre abonnement et commandez vos supports physiques.

{ if(!isSaving) onClose(); }} className={`p-2 rounded-xl transition ${isSaving ? 'text-slate-300 cursor-not-allowed' : 'text-slate-400 hover:text-white hover:bg-slate-800 cursor-pointer'}`} title="Fermer">
* Champs obligatoires
{(!purchasesAllowed) && ( La création de nouvelles commandes est temporairement suspendue par l'administrateur. )}

1. Formule d'abonnement

2. Panneaux physiques A1

Impression A1 (Akilux)

{pBoardFirst}€ / 1er panneau

Puis {pBoardAdd}€ l'unité supp.

Commandez vos panneaux physiques imprimés par nos soins et livrés sur votre chantier. (Tarif unique, impression et livraison incluses).

{ if(currentPanels > originalPanels) setManagingPanneau(p => ({...p, physicalPanels: Math.max(originalPanels, p.physicalPanels - 1)})) }} className={`w-10 h-10 flex items-center justify-center rounded-lg font-black transition ${currentPanels <= originalPanels ? 'bg-slate-100 text-slate-400 opacity-30 cursor-not-allowed' : 'bg-slate-100 hover:bg-slate-200 text-slate-600 cursor-pointer'}`}>-
{currentPanels} Panneau(x)
setManagingPanneau(p => ({...p, physicalPanels: p.physicalPanels + 1}))} className="w-10 h-10 flex items-center justify-center bg-slate-100 hover:bg-slate-200 rounded-lg text-slate-600 font-black transition cursor-pointer">+
{originalPanels > 0 &&

Vous avez déjà commandé {originalPanels} panneau(x) physique(s).

}
{currentPanels > originalPanels && (

Modifiez cette adresse si le lieu de livraison diffère de l'adresse de votre entreprise.

)}

Résumé de la commande (HT)

{!isActif && currentOfferType === 'rental' && (
Abonnement (Location 1er mois){pRental.toFixed(2)} €
)} {!isActif && currentOfferType === 'purchase' && ( <>
Achat définitif du panneau{pPurchase.toFixed(2)} €
Frais d'hébergement (1ère année)Offert
)} {isActif && originalOfferType === 'rental' && currentOfferType === 'purchase' && ( <>
Upgrade : Achat définitif{pPurchase.toFixed(2)} €
Frais d'hébergement (1ère année)Offert
)} {currentHasNoAds && !originalHasNoAds && (
Option marque blanche{pNoAds.toFixed(2)} €
)} {addedPanelsCost > 0 && (
Impression et livraison de {currentPanels - originalPanels} panneau(x) A1{addedPanelsCost.toFixed(2)} €
)}
{discountPct > 0 && (

Remise client applicable

Appliquée sur l'ensemble de la commande HT

-{discountPct}%
)} {myClientData.wallet_balance > 0 && (

Solde disponible (Avoir)

Sera déduit automatiquement de ce paiement

-{myClientData.wallet_balance.toFixed(2)} € TTC
)}

Total à régler {platformHasTva ? 'TTC' : 'HT'}

{remainingToPay.toFixed(2)} €
{platformHasTva &&

TVA (20%) incluse. Total initial HT : {(upfrontHT * priceMultiplier).toFixed(2)} €

}
{currentOfferType === 'rental' && (

Puis abonnement

{finalMonthlyTTC.toFixed(2)} € / mois {platformHasTva ? 'TTC' : 'HT'}

)}
); }; /* EOF ========== [_react/_clients_modals_checkout.jsx] */