{% extends 'base.html.twig' %}
{% block title %}Abonnements — Journal Officiel de l'Union des Comores
{# ================================================================
MODAL CHECKOUT — Standard & Premium
================================================================ #}
<div id="checkout-modal"
class="fixed inset-0 z-50 hidden items-center justify-center p-4"
role="dialog" aria-modal="true" aria-labelledby="modal-title">
<!-- Overlay -->
<div id="modal-overlay"
class="absolute inset-0 bg-black/60 backdrop-blur-sm"
onclick="closeCheckoutModal()"></div>
<!-- Panel -->
<div class="relative bg-white rounded-2xl shadow-2xl w-full max-w-lg max-h-[90vh] overflow-y-auto z-10 animate-modal">
<!-- Header -->
<div id="modal-header" class="sticky top-0 z-20 bg-white border-b border-gray-100 px-6 py-4 flex items-center justify-between rounded-t-2xl">
<div class="flex items-center gap-3">
<!-- Étapes pills -->
<div class="flex items-center gap-1 text-xs" id="modal-steps">
<span class="modal-step-pill active w-6 h-6 rounded-full bg-[#006633] text-white flex items-center justify-center font-black text-[10px]" data-step="1">1</span>
<div class="w-4 h-px bg-gray-200"></div>
<span class="modal-step-pill w-6 h-6 rounded-full bg-gray-200 text-gray-400 flex items-center justify-center font-black text-[10px]" data-step="2">2</span>
<div class="w-4 h-px bg-gray-200"></div>
<span class="modal-step-pill w-6 h-6 rounded-full bg-gray-200 text-gray-400 flex items-center justify-center font-black text-[10px]" data-step="3">3</span>
</div>
<span class="text-sm font-semibold text-gray-600" id="modal-step-label">Récapitulatif</span>
</div>
<button type="button" onclick="closeCheckoutModal()"
class="w-8 h-8 rounded-full bg-gray-100 hover:bg-gray-200 flex items-center justify-center text-gray-500 transition">
<i class="fas fa-times text-xs"></i>
</button>
</div>
<!-- Corps du modal -->
<div class="px-6 py-6">
{# ââ ÉTAPE 1 : Récapitulatif ââ #}
<div id="modal-step-1" class="modal-step-content">
<!-- Badge plan sélectionné -->
<div id="modal-plan-badge" class="rounded-xl p-4 mb-5 flex items-center gap-3">
<div id="modal-plan-icon" class="w-10 h-10 rounded-xl flex items-center justify-center flex-shrink-0">
<i class="fas fa-building text-white"></i>
</div>
<div>
<p class="text-xs font-bold uppercase tracking-wider" id="modal-plan-sublabel">Abonnement</p>
<p class="font-black text-lg" id="modal-plan-name">Standard</p>
</div>
<div class="ml-auto text-right">
<p class="font-black text-xl" id="modal-plan-price">40 000 KMF</p>
<p class="text-xs opacity-70" id="modal-plan-period">/ an · 1ère année</p>
</div>
</div>
<!-- Durée -->
<div class="mb-5">
<label class="block text-sm font-bold text-gray-700 mb-3">Durée</label>
<div class="grid grid-cols-2 gap-3">
<label class="cursor-pointer">
<input type="radio" name="modal-duree" value="annuel" class="sr-only" checked>
<div class="modal-dur-card border-2 border-[#006633] bg-emerald-50/50 rounded-xl p-3 text-center transition-all">
<p class="text-xs font-bold text-gray-700 mb-1">Annuel <span class="bg-[#006633] text-white text-[9px] px-1.5 py-0.5 rounded-full ml-1">−20%</span></p>
<p class="font-black text-[#006633] text-base modal-dur-price" data-std-annuel="40 000" data-pre-annuel="72 000" data-std-mensuel="4 500" data-pre-mensuel="8 000"></p>
<p class="text-[10px] text-gray-400">KMF / an</p>
</div>
</label>
<label class="cursor-pointer">
<input type="radio" name="modal-duree" value="mensuel" class="sr-only">
<div class="modal-dur-card border-2 border-gray-200 bg-white rounded-xl p-3 text-center transition-all hover:border-gray-300">
<p class="text-xs font-bold text-gray-700 mb-1">Mensuel</p>
<p class="font-black text-gray-800 text-base modal-dur-mensuel-price"></p>
<p class="text-[10px] text-gray-400">KMF / mois</p>
</div>
</label>
</div>
</div>
<!-- Informations -->
<div class="space-y-3 mb-5">
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block text-xs text-gray-500 mb-1">Prénom <span class="text-red-400">*</span></label>
<input type="text" id="m-prenom" placeholder="Mohammed"
class="w-full border border-gray-200 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-[#006633]/40 focus:border-[#006633]">
</div>
<div>
<label class="block text-xs text-gray-500 mb-1">Nom <span class="text-red-400">*</span></label>
<input type="text" id="m-nom" placeholder="Said"
class="w-full border border-gray-200 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-[#006633]/40 focus:border-[#006633]">
</div>
</div>
<div>
<label class="block text-xs text-gray-500 mb-1">E-mail <span class="text-red-400">*</span></label>
<input type="email" id="m-email" placeholder="votre@email.com"
class="w-full border border-gray-200 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-[#006633]/40 focus:border-[#006633]">
</div>
<div>
<label class="block text-xs text-gray-500 mb-1">Organisation <span class="text-gray-400">(optionnel)</span></label>
<input type="text" id="m-org" placeholder="Ministère, cabinet, entreprise..."
class="w-full border border-gray-200 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-[#006633]/40 focus:border-[#006633]">
</div>
</div>
<button type="button" onclick="modalGoStep(2)"
class="w-full bg-gradient-to-r from-[#006633] to-[#008040] text-white py-3.5 rounded-xl font-bold text-sm hover:from-[#004d26] transition shadow-md flex items-center justify-center gap-2">
Continuer vers le paiement <i class="fas fa-arrow-right"></i>
</button>
</div>
{# ââ ÉTAPE 2 : Paiement ââ #}
<div id="modal-step-2" class="modal-step-content hidden">
<button type="button" onclick="modalGoStep(1)"
class="flex items-center gap-2 text-gray-400 hover:text-gray-600 text-xs mb-5 transition">
<i class="fas fa-arrow-left"></i> Retour
</button>
<h3 class="text-base font-black text-gray-800 mb-4">Mode de paiement</h3>
<div class="space-y-3 mb-5">
<!-- Huri Money -->
<label class="cursor-pointer block">
<input type="radio" name="modal-methode" value="huri_money" class="sr-only" checked>
<div class="modal-pay-card border-2 border-orange-400 bg-orange-50/40 rounded-xl p-3.5 flex items-center gap-3 transition-all">
<div class="w-10 h-10 bg-orange-500 rounded-xl flex items-center justify-center flex-shrink-0">
<i class="fas fa-mobile-alt text-white"></i>
</div>
<div class="flex-1">
<p class="font-bold text-gray-800 text-sm">Huri Money</p>
<p class="text-xs text-gray-500">Mobile Money · Comores Telecom</p>
</div>
<div class="w-4 h-4 rounded-full border-2 border-orange-400 flex items-center justify-center modal-radio-dot">
<div class="w-2 h-2 rounded-full bg-orange-400"></div>
</div>
</div>
</label>
<!-- Mvola -->
<label class="cursor-pointer block">
<input type="radio" name="modal-methode" value="mvola" class="sr-only">
<div class="modal-pay-card border-2 border-gray-200 bg-white rounded-xl p-3.5 flex items-center gap-3 transition-all hover:border-gray-300">
<div class="w-10 h-10 bg-green-600 rounded-xl flex items-center justify-center flex-shrink-0">
<i class="fas fa-mobile-alt text-white"></i>
</div>
<div class="flex-1">
<p class="font-bold text-gray-800 text-sm">Mvola</p>
<p class="text-xs text-gray-500">Mobile Money · Telma Comores</p>
</div>
<div class="w-4 h-4 rounded-full border-2 border-gray-300 flex items-center justify-center modal-radio-dot"></div>
</div>
</label>
<!-- Holo -->
<label class="cursor-pointer block">
<input type="radio" name="modal-methode" value="holo" class="sr-only">
<div class="modal-pay-card border-2 border-gray-200 bg-white rounded-xl p-3.5 flex items-center gap-3 transition-all hover:border-gray-300">
<div class="w-10 h-10 bg-blue-600 rounded-xl flex items-center justify-center flex-shrink-0">
<i class="fas fa-mobile-alt text-white"></i>
</div>
<div class="flex-1">
<p class="font-bold text-gray-800 text-sm">Holo</p>
<p class="text-xs text-gray-500">Mobile Money · Holo Comores</p>
</div>
<div class="w-4 h-4 rounded-full border-2 border-gray-300 flex items-center justify-center modal-radio-dot"></div>
</div>
</label>
<!-- Visa désactivé -->
<div class="border-2 border-dashed border-gray-200 rounded-xl p-3.5 flex items-center gap-3 opacity-50 cursor-not-allowed">
<div class="w-10 h-10 bg-indigo-100 rounded-xl flex items-center justify-center flex-shrink-0">
<i class="fas fa-credit-card text-indigo-400"></i>
</div>
<div class="flex-1">
<p class="font-bold text-gray-500 text-sm">Visa / Mastercard</p>
<p class="text-xs text-gray-400">Bientôt disponible</p>
</div>
<span class="text-[10px] bg-gray-100 text-gray-400 px-2 py-0.5 rounded-full font-semibold">À venir</span>
</div>
</div>
<!-- Numéro téléphone -->
<div class="bg-gray-50 border border-gray-200 rounded-xl p-4 mb-5">
<label class="block text-sm font-bold text-gray-700 mb-2">
Numéro <span id="modal-provider-label" class="text-[#006633]">Huri Money</span>
</label>
<div class="flex gap-2">
<div class="flex items-center gap-1.5 bg-white border border-gray-200 rounded-xl px-3 py-2.5 flex-shrink-0">
<img src="https://flagcdn.com/w20/km.png" alt="+269" class="w-4 rounded-sm">
<span class="text-sm text-gray-600 font-semibold">+269</span>
</div>
<input type="tel" id="m-phone" placeholder="321 12 34" maxlength="10"
class="flex-1 border border-gray-200 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-[#006633]/40 focus:border-[#006633]">
</div>
<p class="text-[10px] text-gray-400 mt-1.5">
<i class="fas fa-info-circle mr-1"></i> Vous recevrez une notification pour confirmer.
</p>
</div>
<!-- Récapitulatif mini -->
<div class="bg-gray-50 border border-gray-100 rounded-xl p-3.5 mb-5 flex items-center justify-between text-sm">
<div>
<p class="font-semibold text-gray-700" id="modal-recap-plan">Standard · Annuel</p>
<p class="text-xs text-gray-400">1ère année — remise −20% appliquée</p>
</div>
<p class="font-black text-[#006633] text-lg" id="modal-recap-prix">40 000 KMF</p>
</div>
<!-- CGU -->
<label class="flex items-start gap-2.5 cursor-pointer mb-5">
<input type="checkbox" id="m-cgu"
class="mt-0.5 w-4 h-4 rounded border-gray-300 text-[#006633] focus:ring-[#006633] flex-shrink-0">
<span class="text-xs text-gray-500 leading-relaxed">
J'accepte les
<a href="#" class="text-[#006633] font-semibold hover:underline">CGU</a>
et la
<a href="#" class="text-[#006633] font-semibold hover:underline">Politique de confidentialité</a>.
</span>
</label>
<button type="button" id="modal-btn-pay"
class="w-full bg-gradient-to-r from-[#006633] to-[#008040] text-white py-4 rounded-xl font-black text-base hover:from-[#004d26] transition shadow-lg flex items-center justify-center gap-2">
<i class="fas fa-lock text-sm"></i>
<span id="modal-btn-pay-label">Payer 40 000 KMF</span>
</button>
<p class="text-center text-[10px] text-gray-400 mt-2">
<i class="fas fa-shield-alt mr-1 text-[#006633]"></i> Paiement sécurisé
</p>
</div>
{# ââ ÉTAPE 3 : Confirmation ââ #}
<div id="modal-step-3" class="modal-step-content hidden text-center py-4">
<div class="w-16 h-16 bg-emerald-100 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-check-circle text-3xl text-[#006633]"></i>
</div>
<h3 class="text-xl font-black text-gray-800 mb-1">Abonnement activé !</h3>
<p class="text-gray-500 text-sm mb-1">
Votre abonnement <strong id="modal-confirm-plan" class="text-gray-800">Standard</strong> est actif.
</p>
<p class="text-xs text-gray-400 mb-5">
Réf : <span id="modal-confirm-ref" class="font-mono font-semibold text-gray-600"></span>
</p>
<div class="bg-gray-50 rounded-xl border border-gray-100 p-4 text-left text-sm mb-5 space-y-2">
<div class="flex justify-between">
<span class="text-gray-500">Plan</span>
<span class="font-semibold text-gray-800" id="modal-conf-plan2">Standard</span>
</div>
<div class="flex justify-between">
<span class="text-gray-500">Durée</span>
<span class="font-semibold text-gray-800" id="modal-conf-duree">Annuel</span>
</div>
<div class="flex justify-between">
<span class="text-gray-500">Montant</span>
<span class="font-bold text-[#006633]" id="modal-conf-montant">40 000 KMF</span>
</div>
<div class="flex justify-between">
<span class="text-gray-500">Renouvellement</span>
<span class="font-semibold text-gray-800" id="modal-conf-renouvellement">—</span>
</div>
</div>
<div class="flex flex-col gap-3">
<a href="{{ path('app_dashboard') }}"
class="block w-full bg-[#006633] text-white py-3 rounded-xl font-bold text-sm hover:bg-[#004d26] transition">
<i class="fas fa-tachometer-alt mr-2"></i> Accéder à mon espace
</a>
<button type="button" onclick="closeCheckoutModal()"
class="block w-full border border-gray-200 text-gray-600 py-3 rounded-xl font-semibold text-sm hover:bg-gray-50 transition">
Fermer
</button>
</div>
</div>
</div>
</div>
</div>
<style>
@keyframes modalIn {
from { opacity: 0; transform: scale(0.96) translateY(10px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
.animate-modal { animation: modalIn 0.25s ease-out; }
</style>
<script>
(function () {
const PRIX = {
standard: { annuel: 40000, mensuel: 4500, plein: 50000 },
premium: { annuel: 72000, mensuel: 8000, plein: 90000 },
};
const LABELS = { standard: 'Standard', premium: 'Premium' };
const PROVIDERS = { huri_money: 'Huri Money', mvola: 'Mvola', holo: 'Holo' };
let currentPlan = 'standard';
let currentDuree = 'annuel';
// ââ Ouvrir / fermer ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
window.openCheckoutModal = function (plan) {
currentPlan = plan || 'standard';
currentDuree = 'annuel';
modalGoStep(1);
updateModalPlanUI();
updatePrices();
const modal = document.getElementById('checkout-modal');
modal.classList.remove('hidden');
modal.classList.add('flex');
document.body.style.overflow = 'hidden';
};
window.closeCheckoutModal = function () {
const modal = document.getElementById('checkout-modal');
modal.classList.add('hidden');
modal.classList.remove('flex');
document.body.style.overflow = '';
};
// Fermer avec Escape
document.addEventListener('keydown', e => {
if (e.key === 'Escape') closeCheckoutModal();
});
// ââ Navigation étapes ââââââââââââââââââââââââââââââââââââââââââââââââââââââ
window.modalGoStep = function (n) {
if (n === 2) {
const prenom = document.getElementById('m-prenom')?.value.trim();
const nom = document.getElementById('m-nom')?.value.trim();
const email = document.getElementById('m-email')?.value.trim();
if (!prenom || !nom) { alert('Veuillez renseigner votre prénom et nom.'); return; }
if (!email || !email.includes('@')) { alert('Adresse e-mail invalide.'); return; }
}
document.querySelectorAll('.modal-step-content').forEach(s => s.classList.add('hidden'));
document.getElementById('modal-step-' + n)?.classList.remove('hidden');
// Étapes pills
const pills = document.querySelectorAll('.modal-step-pill');
pills.forEach(pill => {
const s = parseInt(pill.dataset.step);
if (s < n) {
pill.className = 'modal-step-pill w-6 h-6 rounded-full bg-[#006633] text-white flex items-center justify-center font-black text-[10px]';
pill.innerHTML = '<i class="fas fa-check text-[9px]"></i>';
} else if (s === n) {
pill.className = 'modal-step-pill w-6 h-6 rounded-full bg-[#006633] text-white flex items-center justify-center font-black text-[10px]';
pill.textContent = s;
} else {
pill.className = 'modal-step-pill w-6 h-6 rounded-full bg-gray-200 text-gray-400 flex items-center justify-center font-black text-[10px]';
pill.textContent = s;
}
});
const labels = { 1: 'Récapitulatif', 2: 'Paiement', 3: 'Confirmation' };
const labelEl = document.getElementById('modal-step-label');
if (labelEl) labelEl.textContent = labels[n];
};
// ââ UI selon le plan âââââââââââââââââââââââââââââââââââââââââââââââââââââââ
function updateModalPlanUI() {
const isPremium = currentPlan === 'premium';
const badge = document.getElementById('modal-plan-badge');
const icon = document.getElementById('modal-plan-icon');
const sub = document.getElementById('modal-plan-sublabel');
const name = document.getElementById('modal-plan-name');
if (isPremium) {
badge.className = 'rounded-xl p-4 mb-5 flex items-center gap-3 bg-gradient-to-r from-[#00391a] to-[#006633] text-white';
icon.className = 'w-10 h-10 bg-white/20 rounded-xl flex items-center justify-center flex-shrink-0';
icon.innerHTML = '<i class="fas fa-crown text-amber-400"></i>';
sub.className = 'text-xs font-bold uppercase tracking-wider text-emerald-300';
name.className = 'font-black text-lg text-white';
} else {
badge.className = 'rounded-xl p-4 mb-5 flex items-center gap-3 bg-emerald-50 border border-emerald-200';
icon.className = 'w-10 h-10 bg-emerald-100 rounded-xl flex items-center justify-center flex-shrink-0';
icon.innerHTML = '<i class="fas fa-building text-[#006633]"></i>';
sub.className = 'text-xs font-bold uppercase tracking-wider text-[#006633]';
name.className = 'font-black text-lg text-gray-800';
}
if (name) name.textContent = LABELS[currentPlan];
}
// ââ Mise à jour prix âââââââââââââââââââââââââââââââââââââââââââââââââââââââ
function updatePrices() {
const prix = PRIX[currentPlan][currentDuree];
const isPremium = currentPlan === 'premium';
// Badge header
const priceEl = document.getElementById('modal-plan-price');
const periodEl = document.getElementById('modal-plan-period');
if (priceEl) priceEl.textContent = prix.toLocaleString('fr-FR') + ' KMF';
if (periodEl) periodEl.textContent = currentDuree === 'annuel' ? '/ an · 1ère année' : '/ mois';
// Cards durée
const annuelPriceEl = document.querySelector('.modal-dur-price');
const mensuelPriceEl = document.querySelector('.modal-dur-mensuel-price');
if (annuelPriceEl) annuelPriceEl.textContent = PRIX[currentPlan].annuel.toLocaleString('fr-FR');
if (mensuelPriceEl) mensuelPriceEl.textContent = PRIX[currentPlan].mensuel.toLocaleString('fr-FR');
// Récap étape 2
const recapPlan = document.getElementById('modal-recap-plan');
const recapPrix = document.getElementById('modal-recap-prix');
if (recapPlan) recapPlan.textContent = LABELS[currentPlan] + ' · ' + (currentDuree === 'annuel' ? 'Annuel' : 'Mensuel');
if (recapPrix) recapPrix.textContent = prix.toLocaleString('fr-FR') + ' KMF';
// Bouton payer
const btnLabel = document.getElementById('modal-btn-pay-label');
if (btnLabel) btnLabel.textContent = 'Payer ' + prix.toLocaleString('fr-FR') + ' KMF';
// Couleur bouton payer si premium
const btnPay = document.getElementById('modal-btn-pay');
if (btnPay) {
if (isPremium) {
btnPay.className = btnPay.className.replace('from-[#006633] to-[#008040]', 'from-amber-500 to-amber-400').replace('hover:from-[#004d26]', 'hover:from-amber-600');
} else {
btnPay.className = btnPay.className.replace('from-amber-500 to-amber-400', 'from-[#006633] to-[#008040]').replace('hover:from-amber-600', 'hover:from-[#004d26]');
}
}
}
// ââ Changement durée ââââââââââââââââââââââââââââââââââââââââââââââââââââââ
document.querySelectorAll('input[name="modal-duree"]').forEach(radio => {
radio.addEventListener('change', function () {
currentDuree = this.value;
updatePrices();
document.querySelectorAll('.modal-dur-card').forEach(c => {
c.className = c.className
.replace('border-[#006633] bg-emerald-50/50', 'border-gray-200 bg-white')
.replace('border-gray-200 bg-white', 'border-gray-200 bg-white');
});
const active = this.closest('label').querySelector('.modal-dur-card');
active.className = active.className.replace('border-gray-200 bg-white', 'border-[#006633] bg-emerald-50/50');
});
});
// ââ Changement méthode paiement âââââââââââââââââââââââââââââââââââââââââââ
const COLORS = { huri_money: ['orange-400', 'orange-50/40'], mvola: ['green-600', 'green-50/40'], holo: ['blue-600', 'blue-50/40'] };
document.querySelectorAll('input[name="modal-methode"]').forEach(radio => {
radio.addEventListener('change', function () {
document.querySelectorAll('.modal-pay-card').forEach(c => {
c.className = 'modal-pay-card border-2 border-gray-200 bg-white rounded-xl p-3.5 flex items-center gap-3 transition-all hover:border-gray-300';
});
document.querySelectorAll('.modal-radio-dot').forEach(d => d.innerHTML = '');
const [border, bg] = COLORS[this.value] || ['gray-400', 'gray-50'];
const card = this.closest('label').querySelector('.modal-pay-card');
card.className = `modal-pay-card border-2 border-${border} bg-${bg} rounded-xl p-3.5 flex items-center gap-3 transition-all`;
const dot = this.closest('label').querySelector('.modal-radio-dot');
dot.innerHTML = `<div class="w-2 h-2 rounded-full bg-${border}"></div>`;
dot.className = `w-4 h-4 rounded-full border-2 border-${border} flex items-center justify-center modal-radio-dot`;
const label = document.getElementById('modal-provider-label');
if (label) label.textContent = PROVIDERS[this.value] || this.value;
});
});
// ââ Bouton payer âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
document.getElementById('modal-btn-pay')?.addEventListener('click', async function () {
const cgu = document.getElementById('m-cgu')?.checked;
const phone = document.getElementById('m-phone')?.value.trim().replace(/\s/g, '');
if (!cgu) { alert('Veuillez accepter les CGU.'); return; }
if (phone.length < 7) { alert('Numéro de téléphone invalide.'); return; }
this.disabled = true;
this.innerHTML = '<svg class="animate-spin w-4 h-4" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path></svg> Traitement…';
// TODO : remplacer par l'appel API de paiement réel
await new Promise(r => setTimeout(r, 1800));
// Remplir confirmation
const ref = 'JO-' + Date.now().toString(36).toUpperCase();
const prix = PRIX[currentPlan][currentDuree];
const date = new Date();
currentDuree === 'annuel' ? date.setFullYear(date.getFullYear() + 1) : date.setMonth(date.getMonth() + 1);
document.getElementById('modal-confirm-plan').textContent = LABELS[currentPlan];
document.getElementById('modal-confirm-ref').textContent = ref;
document.getElementById('modal-conf-plan2').textContent = LABELS[currentPlan];
document.getElementById('modal-conf-duree').textContent = currentDuree === 'annuel' ? 'Annuel' : 'Mensuel';
document.getElementById('modal-conf-montant').textContent = prix.toLocaleString('fr-FR') + ' KMF';
document.getElementById('modal-conf-renouvellement').textContent = date.toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric' });
modalGoStep(3);
});
})();
</script>
{% endblock %}
{% block body %}
{# ================================================================
PAGE ABONNEMENT — CDC conforme
Gratuit / Standard 50 000 KMF / Premium 90 000 KMF
Remise -20% première année sur les offres payantes
Paiement : Huri Money, Mvola, Holo, Visa/Mastercard
================================================================ #}
<!-- Hero -->
<section class="relative bg-gradient-to-br from-[#00391a] via-[#006633] to-[#008040] text-white overflow-hidden">
<div class="absolute inset-0 pointer-events-none opacity-10">
<svg class="w-full h-full" xmlns="http://www.w3.org/2000/svg">
<pattern id="dots" x="0" y="0" width="30" height="30" patternUnits="userSpaceOnUse">
<circle cx="2" cy="2" r="1.5" fill="white"/>
</pattern>
<rect width="100%" height="100%" fill="url(#dots)"/>
</svg>
</div>
<div class="absolute top-0 right-0 w-96 h-96 bg-[#00994d] rounded-full blur-3xl opacity-20 -translate-y-1/2 translate-x-1/4"></div>
<div class="container mx-auto px-4 py-20 relative z-10 text-center">
<div class="inline-flex items-center gap-2 bg-white/15 backdrop-blur-sm border border-white/20 rounded-full px-5 py-2 mb-6 text-sm font-medium">
<i class="fas fa-shield-alt text-emerald-300"></i>
Accès officiel au Journal Officiel de l'Union des Comores
</div>
<h1 class="text-4xl md:text-5xl font-black mb-4 leading-tight">
Choisissez votre accès
</h1>
<p class="text-white/75 max-w-xl mx-auto text-base leading-relaxed mb-8">
De la consultation gratuite à la recherche enrichie par intelligence artificielle —
un abonnement adapté à chaque besoin institutionnel, juridique ou citoyen.
</p>
<!-- Toggle Annuel / Mensuel -->
<div class="inline-flex items-center bg-white/10 border border-white/20 rounded-full p-1 gap-1">
<button id="btn-annuel"
class="px-5 py-2 rounded-full text-sm font-semibold bg-white text-[#006633] transition-all duration-200">
Annuel <span class="ml-1 text-xs bg-emerald-500 text-white px-1.5 py-0.5 rounded-full">−20%</span>
</button>
<button id="btn-mensuel"
class="px-5 py-2 rounded-full text-sm font-semibold text-white/70 hover:text-white transition-all duration-200">
Mensuel
</button>
</div>
</div>
<div class="absolute bottom-0 left-0 right-0">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 60" class="w-full">
<path fill="#f9fafb" fill-opacity="1" d="M0,30L360,50L720,20L1080,50L1440,30L1440,60L0,60Z"></path>
</svg>
</div>
</section>
<!-- Cartes tarifs -->
<section class="py-16 bg-gray-50" id="tarifs">
<div class="container mx-auto px-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 max-w-6xl mx-auto items-stretch">
<!-- ââ GRATUIT âââââââââââââââââââââââââââââââââââââââ -->
<div class="bg-white rounded-2xl border border-gray-200 shadow-sm flex flex-col overflow-hidden hover:shadow-md transition-shadow duration-300">
<div class="p-7 flex-1">
<div class="flex items-center gap-3 mb-5">
<div class="w-10 h-10 bg-gray-100 rounded-xl flex items-center justify-center">
<i class="fas fa-user text-gray-500"></i>
</div>
<div>
<p class="text-xs font-bold text-gray-400 uppercase tracking-widest">Accès</p>
<h2 class="text-lg font-black text-gray-800">Gratuit</h2>
</div>
</div>
<div class="mb-6">
<span class="text-4xl font-black text-gray-800">0</span>
<span class="text-gray-400 text-sm ml-1">KMF / an</span>
</div>
<p class="text-gray-500 text-sm mb-6">
Accès en lecture aux publications officielles et moteur de recherche par filtres.
</p>
<ul class="space-y-3 text-sm">
{% set gratuit_features = [
{ok: true, label: 'Consultation numéros complets (PDF)'},
{ok: true, label: 'Moteur de recherche par filtres'},
{ok: true, label: 'Accès aux derniers actes publiés'},
{ok: false, label: 'Alertes & veille juridique'},
{ok: false, label: 'Textes isolés (< 5 ans)'},
{ok: false, label: 'Archives & réquisitions foncières'},
{ok: false, label: 'Recherche Ibunas.IA (OCR + IA)'},
{ok: false, label: 'Alertes personnalisées par thème'},
] %}
{% for f in gratuit_features %}
<li class="flex items-start gap-3">
{% if f.ok %}
<i class="fas fa-check-circle text-[#006633] mt-0.5 flex-shrink-0"></i>
<span class="text-gray-700">{{ f.label }}</span>
{% else %}
<i class="fas fa-times-circle text-gray-300 mt-0.5 flex-shrink-0"></i>
<span class="text-gray-400">{{ f.label }}</span>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
<div class="p-7 pt-0">
{% if app.user %}
<a href="{{ path('app_dashboard') }}"
class="block w-full text-center border-2 border-gray-200 text-gray-600 py-3 rounded-xl text-sm font-semibold hover:border-gray-300 hover:bg-gray-50 transition">
Votre accès actuel
</a>
{% else %}
<a href=""
class="block w-full text-center border-2 border-gray-200 text-gray-600 py-3 rounded-xl text-sm font-semibold hover:border-gray-300 hover:bg-gray-50 transition">
Créer un compte gratuit
</a>
{% endif %}
</div>
</div>
<!-- ââ STANDARD ââââââââââââââââââââââââââââââââââââââ -->
<div class="bg-white rounded-2xl border-2 border-[#006633]/30 shadow-lg flex flex-col overflow-hidden hover:shadow-xl transition-shadow duration-300 relative">
<!-- Badge populaire -->
<div class="absolute top-4 right-4">
<span class="bg-[#006633] text-white text-xs font-bold px-3 py-1 rounded-full">
Populaire
</span>
</div>
<div class="h-1.5 bg-gradient-to-r from-[#006633] to-[#00994d]"></div>
<div class="p-7 flex-1">
<div class="flex items-center gap-3 mb-5">
<div class="w-10 h-10 bg-emerald-100 rounded-xl flex items-center justify-center">
<i class="fas fa-building text-[#006633]"></i>
</div>
<div>
<p class="text-xs font-bold text-[#006633] uppercase tracking-widest">Abonnement</p>
<h2 class="text-lg font-black text-gray-800">Standard</h2>
</div>
</div>
<!-- Prix annuel -->
<div class="mb-1 price-block" data-annuel="true">
<div class="flex items-baseline gap-2">
<span class="text-4xl font-black text-gray-800 price-value" data-annuel="40000" data-mensuel="4500">40 000</span>
<span class="text-gray-400 text-sm price-unit">KMF / an</span>
</div>
<p class="text-xs text-emerald-600 font-semibold mt-1">
<i class="fas fa-tag mr-1"></i>
<span class="price-promo">−20% la 1ère année · au lieu de 50 000 KMF</span>
</p>
</div>
<p class="text-gray-500 text-sm mb-6 mt-4">
Pour les professionnels du droit, entreprises et administrations ayant besoin d'un suivi régulier.
</p>
<ul class="space-y-3 text-sm">
{% set standard_features = [
{ok: true, label: 'Consultation numéros complets (PDF)'},
{ok: true, label: 'Moteur de recherche par filtres'},
{ok: true, label: 'Alertes & veille juridique'},
{ok: true, label: 'Textes isolés (actes < 5 ans)'},
{ok: false, label: 'Archives historiques (> 5 ans)'},
{ok: false, label: 'Réquisitions & actes fonciers'},
{ok: false, label: 'Recherche Ibunas.IA (OCR + IA)'},
{ok: false, label: 'Alertes personnalisées par thème'},
] %}
{% for f in standard_features %}
<li class="flex items-start gap-3">
{% if f.ok %}
<i class="fas fa-check-circle text-[#006633] mt-0.5 flex-shrink-0"></i>
<span class="text-gray-700">{{ f.label }}</span>
{% else %}
<i class="fas fa-times-circle text-gray-300 mt-0.5 flex-shrink-0"></i>
<span class="text-gray-400">{{ f.label }}</span>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
<div class="p-7 pt-0">
<button type="button" onclick="openCheckoutModal('standard')"
class="block w-full text-center bg-gradient-to-r from-[#006633] to-[#008040] text-white py-3 rounded-xl text-sm font-bold hover:from-[#004d26] hover:to-[#006633] transition shadow-md hover:shadow-lg">
<i class="fas fa-arrow-right mr-2"></i> Choisir Standard
</button>
<p class="text-center text-xs text-gray-400 mt-2">Sans engagement · Résiliable à tout moment</p>
</div>
</div>
<!-- ââ PREMIUM âââââââââââââââââââââââââââââââââââââââ -->
<div class="bg-gradient-to-br from-[#00391a] to-[#006633] rounded-2xl shadow-xl flex flex-col overflow-hidden hover:shadow-2xl transition-shadow duration-300 relative text-white">
<!-- Badge IA -->
<div class="absolute top-4 right-4">
<span class="bg-amber-400 text-amber-900 text-xs font-black px-3 py-1 rounded-full flex items-center gap-1">
<i class="fas fa-microchip text-[10px]"></i> Ibunas.IA
</span>
</div>
<div class="p-7 flex-1">
<div class="flex items-center gap-3 mb-5">
<div class="w-10 h-10 bg-white/20 rounded-xl flex items-center justify-center">
<i class="fas fa-crown text-amber-400"></i>
</div>
<div>
<p class="text-xs font-bold text-emerald-300 uppercase tracking-widest">Abonnement</p>
<h2 class="text-lg font-black text-white">Premium</h2>
</div>
</div>
<div class="mb-1">
<div class="flex items-baseline gap-2">
<span class="text-4xl font-black text-white price-value" data-annuel="72000" data-mensuel="8000">72 000</span>
<span class="text-white/60 text-sm price-unit">KMF / an</span>
</div>
<p class="text-xs text-amber-300 font-semibold mt-1">
<i class="fas fa-tag mr-1"></i>
<span class="price-promo">−20% la 1ère année · au lieu de 90 000 KMF</span>
</p>
</div>
<p class="text-white/65 text-sm mb-6 mt-4">
Accès complet aux archives, réquisitions foncières et moteur Ibunas.IA avec recherche OCR dans le contenu des actes.
</p>
<ul class="space-y-3 text-sm">
{% set premium_features = [
{label: 'Consultation numéros complets (PDF)'},
{label: 'Moteur de recherche par filtres'},
{label: 'Alertes & veille juridique avancée'},
{label: 'Textes isolés (actes < 5 ans)'},
{label: 'Archives historiques (> 5 ans)'},
{label: 'Réquisitions & actes fonciers'},
{label: 'Recherche Ibunas.IA · OCR + IA'},
{label: 'Alertes personnalisées par thème'},
] %}
{% for f in premium_features %}
<li class="flex items-start gap-3">
<i class="fas fa-check-circle text-amber-400 mt-0.5 flex-shrink-0"></i>
<span class="text-white/90">{{ f.label }}</span>
</li>
{% endfor %}
</ul>
</div>
<div class="p-7 pt-0">
<button type="button" onclick="openCheckoutModal('premium')"
class="block w-full text-center bg-amber-400 text-amber-900 py-3 rounded-xl text-sm font-black hover:bg-amber-300 transition shadow-md hover:shadow-lg">
<i class="fas fa-crown mr-2"></i> Choisir Premium
</button>
<p class="text-center text-xs text-white/40 mt-2">Sans engagement · Résiliable à tout moment</p>
</div>
</div>
</div>
<!-- Note remise -->
<p class="text-center text-xs text-gray-400 mt-6">
<i class="fas fa-info-circle mr-1"></i>
La remise de −20% s'applique uniquement lors de la 1ère année de souscription.
Le tarif plein est appliqué au renouvellement.
</p>
</div>
</section>
<!-- Moyens de paiement -->
<section class="py-12 bg-white border-t border-gray-100">
<div class="container mx-auto px-4">
<div class="max-w-3xl mx-auto text-center">
<p class="text-xs font-bold text-gray-400 uppercase tracking-widest mb-5">
Moyens de paiement acceptés
</p>
<div class="flex flex-wrap justify-center items-center gap-6">
<div class="flex items-center gap-2.5 bg-gray-50 border border-gray-200 rounded-xl px-5 py-3">
<div class="w-8 h-8 bg-orange-500 rounded-lg flex items-center justify-center">
<i class="fas fa-mobile-alt text-white text-sm"></i>
</div>
<div class="text-left">
<p class="text-xs font-bold text-gray-800">Huri Money</p>
<p class="text-[10px] text-gray-400">Mobile Money</p>
</div>
</div>
<div class="flex items-center gap-2.5 bg-gray-50 border border-gray-200 rounded-xl px-5 py-3">
<div class="w-8 h-8 bg-green-600 rounded-lg flex items-center justify-center">
<i class="fas fa-mobile-alt text-white text-sm"></i>
</div>
<div class="text-left">
<p class="text-xs font-bold text-gray-800">Mvola</p>
<p class="text-[10px] text-gray-400">Mobile Money</p>
</div>
</div>
<div class="flex items-center gap-2.5 bg-gray-50 border border-gray-200 rounded-xl px-5 py-3">
<div class="w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center">
<i class="fas fa-mobile-alt text-white text-sm"></i>
</div>
<div class="text-left">
<p class="text-xs font-bold text-gray-800">Holo</p>
<p class="text-[10px] text-gray-400">Mobile Money</p>
</div>
</div>
<div class="flex items-center gap-2.5 bg-gray-50 border border-gray-200 rounded-xl px-5 py-3 opacity-60">
<div class="w-8 h-8 bg-indigo-600 rounded-lg flex items-center justify-center">
<i class="fas fa-credit-card text-white text-sm"></i>
</div>
<div class="text-left">
<p class="text-xs font-bold text-gray-800">Visa / Mastercard</p>
<p class="text-[10px] text-gray-400">Bientôt disponible</p>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Tableau comparatif complet -->
<section class="py-16 bg-gray-50">
<div class="container mx-auto px-4">
<div class="max-w-5xl mx-auto">
<h2 class="text-2xl font-black text-gray-800 text-center mb-2">Comparaison détaillée</h2>
<p class="text-gray-500 text-center text-sm mb-10">Toutes les fonctionnalités, offre par offre</p>
<div class="bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-sm min-w-[560px]">
<thead>
<tr class="border-b border-gray-100">
<th class="text-left p-4 text-gray-500 font-semibold w-1/2">Fonctionnalité</th>
<th class="text-center p-4 text-gray-600 font-bold">Gratuit</th>
<th class="text-center p-4 text-[#006633] font-bold">Standard</th>
<th class="text-center p-4 font-bold">
<span class="text-[#006633]">Premium</span>
<span class="ml-1 text-[10px] bg-amber-100 text-amber-700 px-1.5 py-0.5 rounded-full font-bold">IA</span>
</th>
</tr>
</thead>
<tbody>
{% set rows = [
{cat: true, label: 'Consultation'},
{cat: false, label: 'Accès numéros complets (PDF)', g: true, s: true, p: true},
{cat: false, label: 'Consultation en ligne HTML responsive', g: true, s: true, p: true},
{cat: false, label: 'Textes isolés — actes récents (< 5 ans)', g: false, s: true, p: true},
{cat: false, label: 'Archives historiques (> 5 ans)', g: false, s: false, p: true},
{cat: false, label: 'Réquisitions & actes fonciers', g: false, s: false, p: true},
{cat: true, label: 'Recherche'},
{cat: false, label: 'Moteur de recherche par filtres', g: true, s: true, p: true},
{cat: false, label: 'Recherche par institution émettrice', g: true, s: true, p: true},
{cat: false, label: 'Filtrage chronologique (année / plage)', g: true, s: true, p: true},
{cat: false, label: 'Filtrage par type d\'acte', g: true, s: true, p: true},
{cat: false, label: 'Recherche Ibunas.IA (contenu OCR + IA)', g: false, s: false, p: true},
{cat: false, label: 'Résumé automatique des actes', g: false, s: false, p: true},
{cat: true, label: 'Alertes & veille'},
{cat: false, label: 'Notifications de nouvelles publications', g: false, s: true, p: true},
{cat: false, label: 'Veille juridique (domaines généraux)', g: false, s: true, p: true},
{cat: false, label: 'Alertes personnalisées par thème', g: false, s: false, p: true},
{cat: false, label: 'Mémentos juridiques (à venir)', g: false, s: false, p: true},
] %}
{% for row in rows %}
{% if row.cat %}
<tr class="bg-gray-50 border-t border-gray-100">
<td colspan="4" class="px-5 py-3 text-xs font-black text-gray-500 uppercase tracking-widest">
{{ row.label }}
</td>
</tr>
{% else %}
<tr class="border-t border-gray-50 hover:bg-gray-50/50 transition-colors">
<td class="p-4 px-5 text-gray-700">{{ row.label }}</td>
<td class="p-4 text-center">
{% if row.g %}
<i class="fas fa-check text-[#006633]"></i>
{% else %}
<i class="fas fa-minus text-gray-300"></i>
{% endif %}
</td>
<td class="p-4 text-center">
{% if row.s %}
<i class="fas fa-check text-[#006633]"></i>
{% else %}
<i class="fas fa-minus text-gray-300"></i>
{% endif %}
</td>
<td class="p-4 text-center">
{% if row.p %}
<i class="fas fa-check text-amber-500"></i>
{% else %}
<i class="fas fa-minus text-gray-300"></i>
{% endif %}
</td>
</tr>
{% endif %}
{% endfor %}
<!-- Ligne tarif -->
<tr class="border-t-2 border-gray-200 bg-gray-50">
<td class="p-4 font-black text-gray-800">Tarif annuel</td>
<td class="p-4 text-center font-black text-gray-800">Gratuit</td>
<td class="p-4 text-center font-black text-[#006633]">
50 000 KMF<br>
<span class="text-xs font-semibold text-emerald-600">40 000 KMF la 1ère année</span>
</td>
<td class="p-4 text-center font-black text-[#006633]">
90 000 KMF<br>
<span class="text-xs font-semibold text-amber-600">72 000 KMF la 1ère année</span>
</td>
</tr>
<tr class="border-t border-gray-100">
<td class="p-4"></td>
<td class="p-4 text-center">
<a href=""
class="inline-block border border-gray-200 text-gray-600 text-xs font-semibold px-4 py-2 rounded-lg hover:bg-gray-50 transition">
Créer un compte
</a>
</td>
<td class="p-4 text-center">
<button type="button" onclick="openCheckoutModal('standard')"
class="inline-block bg-[#006633] text-white text-xs font-bold px-4 py-2 rounded-lg hover:bg-[#004d26] transition">
Choisir Standard
</button>
</td>
<td class="p-4 text-center">
<button type="button" onclick="openCheckoutModal('premium')"
class="inline-block bg-amber-400 text-amber-900 text-xs font-black px-4 py-2 rounded-lg hover:bg-amber-300 transition">
Choisir Premium
</button>
</td>
</tr>
</tbody>
</table>
</div> {# ← ferme overflow-x-auto #}
</div>
</div>
</div>
</div>
</section>
<!-- FAQ -->
<section class="py-16 bg-white">
<div class="container mx-auto px-4">
<div class="max-w-2xl mx-auto">
<h2 class="text-2xl font-black text-gray-800 text-center mb-2">Questions fréquentes</h2>
<p class="text-gray-500 text-sm text-center mb-10">Tout ce que vous devez savoir avant de vous abonner</p>
<div class="space-y-3" id="faq-list">
{% set faqs = [
{
q: 'Comment fonctionne la remise de −20% ?',
r: 'La remise s\'applique uniquement lors de votre première année d\'abonnement, que ce soit Standard ou Premium. À partir de la deuxième année, le tarif plein s\'applique automatiquement (50 000 KMF ou 90 000 KMF selon le plan).'
},
{
q: 'Puis-je résilier à tout moment ?',
r: 'Oui. Vous pouvez résilier votre abonnement à tout moment depuis votre espace personnel. Votre accès reste actif jusqu\'à la fin de la période payée, sans frais de résiliation.'
},
{
q: 'Qu\'est-ce que la recherche Ibunas.IA ?',
r: 'Ibunas.IA est notre moteur de recherche enrichi par intelligence artificielle. Il analyse le contenu textuel des actes grâce à l\'OCR (reconnaissance de caractères) et vous permet de rechercher des termes précis à l\'intérieur même des documents, pas seulement dans les titres et résumés.'
},
{
q: 'Quels moyens de paiement sont acceptés ?',
r: 'Nous acceptons les paiements Mobile Money comoriens : Huri Money, Mvola et Holo. Le paiement par carte Visa/Mastercard sera disponible prochainement, sous validation de la Banque Centrale des Comores.'
},
{
q: 'Les abonnements peuvent-ils être partagés ?',
r: 'Non, chaque abonnement est nominatif et lié à un seul compte utilisateur. Pour les institutions nécessitant plusieurs accès simultanés, contactez-nous pour un devis multi-utilisateurs.'
},
{
q: 'Comment accéder aux archives historiques ?',
r: 'Les archives antérieures à 5 ans sont exclusivement réservées aux abonnés Premium. Elles incluent les numérisations des anciens journaux officiels, indexées et rendues recherchables via notre système OCR.'
},
] %}
{% for faq in faqs %}
<div class="faq-item bg-gray-50 rounded-xl border border-gray-100 overflow-hidden">
<button type="button"
class="faq-trigger w-full flex items-center justify-between p-5 text-left hover:bg-gray-100 transition-colors duration-200">
<span class="font-semibold text-gray-800 text-sm pr-4">{{ faq.q }}</span>
<i class="fas fa-chevron-down text-gray-400 text-xs flex-shrink-0 transition-transform duration-300 faq-icon"></i>
</button>
<div class="faq-answer hidden px-5 pb-5">
<p class="text-gray-600 text-sm leading-relaxed">{{ faq.r }}</p>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</section>
<!-- CTA final -->
<section class="py-16 bg-gradient-to-br from-[#006633] to-[#004d26] text-white">
<div class="container mx-auto px-4 text-center">
<div class="w-14 h-14 bg-white/15 rounded-2xl flex items-center justify-center mx-auto mb-5">
<i class="fas fa-file-contract text-2xl text-white"></i>
</div>
<h2 class="text-2xl font-black mb-3">Besoin d'un accès institutionnel ?</h2>
<p class="text-white/70 max-w-md mx-auto text-sm mb-7">
Ministères, juridictions, cabinets d'avocats, universités —
contactez-nous pour un devis multi-utilisateurs adapté à votre structure.
</p>
<a href="mailto:contact@journalofficiel.km"
class="inline-flex items-center gap-2 bg-white text-[#006633] px-7 py-3 rounded-xl font-bold text-sm hover:bg-gray-50 transition shadow-lg">
<i class="fas fa-envelope"></i> Nous contacter
</a>
</div>
</section>
<script>
document.addEventListener('DOMContentLoaded', function () {
// ââ Toggle annuel / mensuel ââââââââââââââââââââââââââââââââââââââââââââââââ
const btnAnnuel = document.getElementById('btn-annuel');
const btnMensuel = document.getElementById('btn-mensuel');
const priceValues = document.querySelectorAll('.price-value');
const priceUnits = document.querySelectorAll('.price-unit');
const pricePromos = document.querySelectorAll('.price-promo');
let isAnnuel = true;
function updatePrices() {
priceValues.forEach(el => {
const val = isAnnuel ? el.dataset.annuel : el.dataset.mensuel;
el.textContent = parseInt(val).toLocaleString('fr-FR');
});
priceUnits.forEach(el => {
el.textContent = isAnnuel ? 'KMF / an' : 'KMF / mois';
});
pricePromos.forEach(el => {
if (isAnnuel) {
el.closest('p')?.classList.remove('hidden');
} else {
el.closest('p')?.classList.add('hidden');
}
});
}
btnAnnuel?.addEventListener('click', () => {
isAnnuel = true;
btnAnnuel.className = 'px-5 py-2 rounded-full text-sm font-semibold bg-white text-[#006633] transition-all duration-200';
btnMensuel.className = 'px-5 py-2 rounded-full text-sm font-semibold text-white/70 hover:text-white transition-all duration-200';
updatePrices();
});
btnMensuel?.addEventListener('click', () => {
isAnnuel = false;
btnMensuel.className = 'px-5 py-2 rounded-full text-sm font-semibold bg-white text-[#006633] transition-all duration-200';
btnAnnuel.className = 'px-5 py-2 rounded-full text-sm font-semibold text-white/70 hover:text-white transition-all duration-200';
updatePrices();
});
// ââ FAQ accordion ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
document.querySelectorAll('.faq-trigger').forEach(btn => {
btn.addEventListener('click', () => {
const item = btn.closest('.faq-item');
const answer = item.querySelector('.faq-answer');
const icon = item.querySelector('.faq-icon');
const isOpen = !answer.classList.contains('hidden');
// Fermer tous
document.querySelectorAll('.faq-answer').forEach(a => a.classList.add('hidden'));
document.querySelectorAll('.faq-icon').forEach(i => i.style.transform = 'rotate(0deg)');
// Ouvrir si était fermé
if (!isOpen) {
answer.classList.remove('hidden');
icon.style.transform = 'rotate(180deg)';
}
});
});
});
</script>
{# ================================================================
MODAL CHECKOUT — Standard & Premium
================================================================ #}
<div id="checkout-modal"
class="fixed inset-0 z-50 hidden items-center justify-center p-4"
role="dialog" aria-modal="true" aria-labelledby="modal-title">
<!-- Overlay -->
<div id="modal-overlay"
class="absolute inset-0 bg-black/60 backdrop-blur-sm"
onclick="closeCheckoutModal()"></div>
<!-- Panel -->
<div class="relative bg-white rounded-2xl shadow-2xl w-full max-w-lg max-h-[90vh] overflow-y-auto z-10 animate-modal">
<!-- Header -->
<div id="modal-header" class="sticky top-0 z-20 bg-white border-b border-gray-100 px-6 py-4 flex items-center justify-between rounded-t-2xl">
<div class="flex items-center gap-3">
<!-- Étapes pills -->
<div class="flex items-center gap-1 text-xs" id="modal-steps">
<span class="modal-step-pill active w-6 h-6 rounded-full bg-[#006633] text-white flex items-center justify-center font-black text-[10px]" data-step="1">1</span>
<div class="w-4 h-px bg-gray-200"></div>
<span class="modal-step-pill w-6 h-6 rounded-full bg-gray-200 text-gray-400 flex items-center justify-center font-black text-[10px]" data-step="2">2</span>
<div class="w-4 h-px bg-gray-200"></div>
<span class="modal-step-pill w-6 h-6 rounded-full bg-gray-200 text-gray-400 flex items-center justify-center font-black text-[10px]" data-step="3">3</span>
</div>
<span class="text-sm font-semibold text-gray-600" id="modal-step-label">Récapitulatif</span>
</div>
<button type="button" onclick="closeCheckoutModal()"
class="w-8 h-8 rounded-full bg-gray-100 hover:bg-gray-200 flex items-center justify-center text-gray-500 transition">
<i class="fas fa-times text-xs"></i>
</button>
</div>
<!-- Corps du modal -->
<div class="px-6 py-6">
{# ââ ÉTAPE 1 : Récapitulatif ââ #}
<div id="modal-step-1" class="modal-step-content">
<!-- Badge plan sélectionné -->
<div id="modal-plan-badge" class="rounded-xl p-4 mb-5 flex items-center gap-3">
<div id="modal-plan-icon" class="w-10 h-10 rounded-xl flex items-center justify-center flex-shrink-0">
<i class="fas fa-building text-white"></i>
</div>
<div>
<p class="text-xs font-bold uppercase tracking-wider" id="modal-plan-sublabel">Abonnement</p>
<p class="font-black text-lg" id="modal-plan-name">Standard</p>
</div>
<div class="ml-auto text-right">
<p class="font-black text-xl" id="modal-plan-price">40 000 KMF</p>
<p class="text-xs opacity-70" id="modal-plan-period">/ an · 1ère année</p>
</div>
</div>
<!-- Durée -->
<div class="mb-5">
<label class="block text-sm font-bold text-gray-700 mb-3">Durée</label>
<div class="grid grid-cols-2 gap-3">
<label class="cursor-pointer">
<input type="radio" name="modal-duree" value="annuel" class="sr-only" checked>
<div class="modal-dur-card border-2 border-[#006633] bg-emerald-50/50 rounded-xl p-3 text-center transition-all">
<p class="text-xs font-bold text-gray-700 mb-1">Annuel <span class="bg-[#006633] text-white text-[9px] px-1.5 py-0.5 rounded-full ml-1">−20%</span></p>
<p class="font-black text-[#006633] text-base modal-dur-price" data-std-annuel="40 000" data-pre-annuel="72 000" data-std-mensuel="4 500" data-pre-mensuel="8 000"></p>
<p class="text-[10px] text-gray-400">KMF / an</p>
</div>
</label>
<label class="cursor-pointer">
<input type="radio" name="modal-duree" value="mensuel" class="sr-only">
<div class="modal-dur-card border-2 border-gray-200 bg-white rounded-xl p-3 text-center transition-all hover:border-gray-300">
<p class="text-xs font-bold text-gray-700 mb-1">Mensuel</p>
<p class="font-black text-gray-800 text-base modal-dur-mensuel-price"></p>
<p class="text-[10px] text-gray-400">KMF / mois</p>
</div>
</label>
</div>
</div>
<!-- Informations -->
<div class="space-y-3 mb-5">
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block text-xs text-gray-500 mb-1">Prénom <span class="text-red-400">*</span></label>
<input type="text" id="m-prenom" placeholder="Mohammed"
class="w-full border border-gray-200 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-[#006633]/40 focus:border-[#006633]">
</div>
<div>
<label class="block text-xs text-gray-500 mb-1">Nom <span class="text-red-400">*</span></label>
<input type="text" id="m-nom" placeholder="Said"
class="w-full border border-gray-200 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-[#006633]/40 focus:border-[#006633]">
</div>
</div>
<div>
<label class="block text-xs text-gray-500 mb-1">E-mail <span class="text-red-400">*</span></label>
<input type="email" id="m-email" placeholder="votre@email.com"
class="w-full border border-gray-200 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-[#006633]/40 focus:border-[#006633]">
</div>
<div>
<label class="block text-xs text-gray-500 mb-1">Organisation <span class="text-gray-400">(optionnel)</span></label>
<input type="text" id="m-org" placeholder="Ministère, cabinet, entreprise..."
class="w-full border border-gray-200 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-[#006633]/40 focus:border-[#006633]">
</div>
</div>
<button type="button" onclick="modalGoStep(2)"
class="w-full bg-gradient-to-r from-[#006633] to-[#008040] text-white py-3.5 rounded-xl font-bold text-sm hover:from-[#004d26] transition shadow-md flex items-center justify-center gap-2">
Continuer vers le paiement <i class="fas fa-arrow-right"></i>
</button>
</div>
{# ââ ÉTAPE 2 : Paiement ââ #}
<div id="modal-step-2" class="modal-step-content hidden">
<button type="button" onclick="modalGoStep(1)"
class="flex items-center gap-2 text-gray-400 hover:text-gray-600 text-xs mb-5 transition">
<i class="fas fa-arrow-left"></i> Retour
</button>
<h3 class="text-base font-black text-gray-800 mb-4">Mode de paiement</h3>
<div class="space-y-3 mb-5">
<!-- Huri Money -->
<label class="cursor-pointer block">
<input type="radio" name="modal-methode" value="huri_money" class="sr-only" checked>
<div class="modal-pay-card border-2 border-orange-400 bg-orange-50/40 rounded-xl p-3.5 flex items-center gap-3 transition-all">
<div class="w-10 h-10 bg-orange-500 rounded-xl flex items-center justify-center flex-shrink-0">
<i class="fas fa-mobile-alt text-white"></i>
</div>
<div class="flex-1">
<p class="font-bold text-gray-800 text-sm">Huri Money</p>
<p class="text-xs text-gray-500">Mobile Money · Comores Telecom</p>
</div>
<div class="w-4 h-4 rounded-full border-2 border-orange-400 flex items-center justify-center modal-radio-dot">
<div class="w-2 h-2 rounded-full bg-orange-400"></div>
</div>
</div>
</label>
<!-- Mvola -->
<label class="cursor-pointer block">
<input type="radio" name="modal-methode" value="mvola" class="sr-only">
<div class="modal-pay-card border-2 border-gray-200 bg-white rounded-xl p-3.5 flex items-center gap-3 transition-all hover:border-gray-300">
<div class="w-10 h-10 bg-green-600 rounded-xl flex items-center justify-center flex-shrink-0">
<i class="fas fa-mobile-alt text-white"></i>
</div>
<div class="flex-1">
<p class="font-bold text-gray-800 text-sm">Mvola</p>
<p class="text-xs text-gray-500">Mobile Money · Telma Comores</p>
</div>
<div class="w-4 h-4 rounded-full border-2 border-gray-300 flex items-center justify-center modal-radio-dot"></div>
</div>
</label>
<!-- Holo -->
<label class="cursor-pointer block">
<input type="radio" name="modal-methode" value="holo" class="sr-only">
<div class="modal-pay-card border-2 border-gray-200 bg-white rounded-xl p-3.5 flex items-center gap-3 transition-all hover:border-gray-300">
<div class="w-10 h-10 bg-blue-600 rounded-xl flex items-center justify-center flex-shrink-0">
<i class="fas fa-mobile-alt text-white"></i>
</div>
<div class="flex-1">
<p class="font-bold text-gray-800 text-sm">Holo</p>
<p class="text-xs text-gray-500">Mobile Money · Holo Comores</p>
</div>
<div class="w-4 h-4 rounded-full border-2 border-gray-300 flex items-center justify-center modal-radio-dot"></div>
</div>
</label>
<!-- Visa désactivé -->
<div class="border-2 border-dashed border-gray-200 rounded-xl p-3.5 flex items-center gap-3 opacity-50 cursor-not-allowed">
<div class="w-10 h-10 bg-indigo-100 rounded-xl flex items-center justify-center flex-shrink-0">
<i class="fas fa-credit-card text-indigo-400"></i>
</div>
<div class="flex-1">
<p class="font-bold text-gray-500 text-sm">Visa / Mastercard</p>
<p class="text-xs text-gray-400">Bientôt disponible</p>
</div>
<span class="text-[10px] bg-gray-100 text-gray-400 px-2 py-0.5 rounded-full font-semibold">À venir</span>
</div>
</div>
<!-- Numéro téléphone -->
<div class="bg-gray-50 border border-gray-200 rounded-xl p-4 mb-5">
<label class="block text-sm font-bold text-gray-700 mb-2">
Numéro <span id="modal-provider-label" class="text-[#006633]">Huri Money</span>
</label>
<div class="flex gap-2">
<div class="flex items-center gap-1.5 bg-white border border-gray-200 rounded-xl px-3 py-2.5 flex-shrink-0">
<img src="https://flagcdn.com/w20/km.png" alt="+269" class="w-4 rounded-sm">
<span class="text-sm text-gray-600 font-semibold">+269</span>
</div>
<input type="tel" id="m-phone" placeholder="321 12 34" maxlength="10"
class="flex-1 border border-gray-200 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-[#006633]/40 focus:border-[#006633]">
</div>
<p class="text-[10px] text-gray-400 mt-1.5">
<i class="fas fa-info-circle mr-1"></i> Vous recevrez une notification pour confirmer.
</p>
</div>
<!-- Récapitulatif mini -->
<div class="bg-gray-50 border border-gray-100 rounded-xl p-3.5 mb-5 flex items-center justify-between text-sm">
<div>
<p class="font-semibold text-gray-700" id="modal-recap-plan">Standard · Annuel</p>
<p class="text-xs text-gray-400">1ère année — remise −20% appliquée</p>
</div>
<p class="font-black text-[#006633] text-lg" id="modal-recap-prix">40 000 KMF</p>
</div>
<!-- CGU -->
<label class="flex items-start gap-2.5 cursor-pointer mb-5">
<input type="checkbox" id="m-cgu"
class="mt-0.5 w-4 h-4 rounded border-gray-300 text-[#006633] focus:ring-[#006633] flex-shrink-0">
<span class="text-xs text-gray-500 leading-relaxed">
J'accepte les
<a href="#" class="text-[#006633] font-semibold hover:underline">CGU</a>
et la
<a href="#" class="text-[#006633] font-semibold hover:underline">Politique de confidentialité</a>.
</span>
</label>
<button type="button" id="modal-btn-pay"
class="w-full bg-gradient-to-r from-[#006633] to-[#008040] text-white py-4 rounded-xl font-black text-base hover:from-[#004d26] transition shadow-lg flex items-center justify-center gap-2">
<i class="fas fa-lock text-sm"></i>
<span id="modal-btn-pay-label">Payer 40 000 KMF</span>
</button>
<p class="text-center text-[10px] text-gray-400 mt-2">
<i class="fas fa-shield-alt mr-1 text-[#006633]"></i> Paiement sécurisé
</p>
</div>
{# ââ ÉTAPE 3 : Confirmation ââ #}
<div id="modal-step-3" class="modal-step-content hidden text-center py-4">
<div class="w-16 h-16 bg-emerald-100 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-check-circle text-3xl text-[#006633]"></i>
</div>
<h3 class="text-xl font-black text-gray-800 mb-1">Abonnement activé !</h3>
<p class="text-gray-500 text-sm mb-1">
Votre abonnement <strong id="modal-confirm-plan" class="text-gray-800">Standard</strong> est actif.
</p>
<p class="text-xs text-gray-400 mb-5">
Réf : <span id="modal-confirm-ref" class="font-mono font-semibold text-gray-600"></span>
</p>
<div class="bg-gray-50 rounded-xl border border-gray-100 p-4 text-left text-sm mb-5 space-y-2">
<div class="flex justify-between">
<span class="text-gray-500">Plan</span>
<span class="font-semibold text-gray-800" id="modal-conf-plan2">Standard</span>
</div>
<div class="flex justify-between">
<span class="text-gray-500">Durée</span>
<span class="font-semibold text-gray-800" id="modal-conf-duree">Annuel</span>
</div>
<div class="flex justify-between">
<span class="text-gray-500">Montant</span>
<span class="font-bold text-[#006633]" id="modal-conf-montant">40 000 KMF</span>
</div>
<div class="flex justify-between">
<span class="text-gray-500">Renouvellement</span>
<span class="font-semibold text-gray-800" id="modal-conf-renouvellement">—</span>
</div>
</div>
<div class="flex flex-col gap-3">
<a href="{{ path('app_dashboard') }}"
class="block w-full bg-[#006633] text-white py-3 rounded-xl font-bold text-sm hover:bg-[#004d26] transition">
<i class="fas fa-tachometer-alt mr-2"></i> Accéder à mon espace
</a>
<button type="button" onclick="closeCheckoutModal()"
class="block w-full border border-gray-200 text-gray-600 py-3 rounded-xl font-semibold text-sm hover:bg-gray-50 transition">
Fermer
</button>
</div>
</div>
</div>
</div>
</div>
<style>
@keyframes modalIn {
from { opacity: 0; transform: scale(0.96) translateY(10px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
.animate-modal { animation: modalIn 0.25s ease-out; }
</style>
<script>
(function () {
const PRIX = {
standard: { annuel: 40000, mensuel: 4500, plein: 50000 },
premium: { annuel: 72000, mensuel: 8000, plein: 90000 },
};
const LABELS = { standard: 'Standard', premium: 'Premium' };
const PROVIDERS = { huri_money: 'Huri Money', mvola: 'Mvola', holo: 'Holo' };
let currentPlan = 'standard';
let currentDuree = 'annuel';
// ââ Ouvrir / fermer ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
window.openCheckoutModal = function (plan) {
currentPlan = plan || 'standard';
currentDuree = 'annuel';
modalGoStep(1);
updateModalPlanUI();
updatePrices();
const modal = document.getElementById('checkout-modal');
modal.classList.remove('hidden');
modal.classList.add('flex');
document.body.style.overflow = 'hidden';
};
window.closeCheckoutModal = function () {
const modal = document.getElementById('checkout-modal');
modal.classList.add('hidden');
modal.classList.remove('flex');
document.body.style.overflow = '';
};
// Fermer avec Escape
document.addEventListener('keydown', e => {
if (e.key === 'Escape') closeCheckoutModal();
});
// ââ Navigation étapes ââââââââââââââââââââââââââââââââââââââââââââââââââââââ
window.modalGoStep = function (n) {
if (n === 2) {
const prenom = document.getElementById('m-prenom')?.value.trim();
const nom = document.getElementById('m-nom')?.value.trim();
const email = document.getElementById('m-email')?.value.trim();
if (!prenom || !nom) { alert('Veuillez renseigner votre prénom et nom.'); return; }
if (!email || !email.includes('@')) { alert('Adresse e-mail invalide.'); return; }
}
document.querySelectorAll('.modal-step-content').forEach(s => s.classList.add('hidden'));
document.getElementById('modal-step-' + n)?.classList.remove('hidden');
// Étapes pills
const pills = document.querySelectorAll('.modal-step-pill');
pills.forEach(pill => {
const s = parseInt(pill.dataset.step);
if (s < n) {
pill.className = 'modal-step-pill w-6 h-6 rounded-full bg-[#006633] text-white flex items-center justify-center font-black text-[10px]';
pill.innerHTML = '<i class="fas fa-check text-[9px]"></i>';
} else if (s === n) {
pill.className = 'modal-step-pill w-6 h-6 rounded-full bg-[#006633] text-white flex items-center justify-center font-black text-[10px]';
pill.textContent = s;
} else {
pill.className = 'modal-step-pill w-6 h-6 rounded-full bg-gray-200 text-gray-400 flex items-center justify-center font-black text-[10px]';
pill.textContent = s;
}
});
const labels = { 1: 'Récapitulatif', 2: 'Paiement', 3: 'Confirmation' };
const labelEl = document.getElementById('modal-step-label');
if (labelEl) labelEl.textContent = labels[n];
};
// ââ UI selon le plan âââââââââââââââââââââââââââââââââââââââââââââââââââââââ
function updateModalPlanUI() {
const isPremium = currentPlan === 'premium';
const badge = document.getElementById('modal-plan-badge');
const icon = document.getElementById('modal-plan-icon');
const sub = document.getElementById('modal-plan-sublabel');
const name = document.getElementById('modal-plan-name');
if (isPremium) {
badge.className = 'rounded-xl p-4 mb-5 flex items-center gap-3 bg-gradient-to-r from-[#00391a] to-[#006633] text-white';
icon.className = 'w-10 h-10 bg-white/20 rounded-xl flex items-center justify-center flex-shrink-0';
icon.innerHTML = '<i class="fas fa-crown text-amber-400"></i>';
sub.className = 'text-xs font-bold uppercase tracking-wider text-emerald-300';
name.className = 'font-black text-lg text-white';
} else {
badge.className = 'rounded-xl p-4 mb-5 flex items-center gap-3 bg-emerald-50 border border-emerald-200';
icon.className = 'w-10 h-10 bg-emerald-100 rounded-xl flex items-center justify-center flex-shrink-0';
icon.innerHTML = '<i class="fas fa-building text-[#006633]"></i>';
sub.className = 'text-xs font-bold uppercase tracking-wider text-[#006633]';
name.className = 'font-black text-lg text-gray-800';
}
if (name) name.textContent = LABELS[currentPlan];
}
// ââ Mise à jour prix âââââââââââââââââââââââââââââââââââââââââââââââââââââââ
function updatePrices() {
const prix = PRIX[currentPlan][currentDuree];
const isPremium = currentPlan === 'premium';
// Badge header
const priceEl = document.getElementById('modal-plan-price');
const periodEl = document.getElementById('modal-plan-period');
if (priceEl) priceEl.textContent = prix.toLocaleString('fr-FR') + ' KMF';
if (periodEl) periodEl.textContent = currentDuree === 'annuel' ? '/ an · 1ère année' : '/ mois';
// Cards durée
const annuelPriceEl = document.querySelector('.modal-dur-price');
const mensuelPriceEl = document.querySelector('.modal-dur-mensuel-price');
if (annuelPriceEl) annuelPriceEl.textContent = PRIX[currentPlan].annuel.toLocaleString('fr-FR');
if (mensuelPriceEl) mensuelPriceEl.textContent = PRIX[currentPlan].mensuel.toLocaleString('fr-FR');
// Récap étape 2
const recapPlan = document.getElementById('modal-recap-plan');
const recapPrix = document.getElementById('modal-recap-prix');
if (recapPlan) recapPlan.textContent = LABELS[currentPlan] + ' · ' + (currentDuree === 'annuel' ? 'Annuel' : 'Mensuel');
if (recapPrix) recapPrix.textContent = prix.toLocaleString('fr-FR') + ' KMF';
// Bouton payer
const btnLabel = document.getElementById('modal-btn-pay-label');
if (btnLabel) btnLabel.textContent = 'Payer ' + prix.toLocaleString('fr-FR') + ' KMF';
// Couleur bouton payer si premium
const btnPay = document.getElementById('modal-btn-pay');
if (btnPay) {
if (isPremium) {
btnPay.className = btnPay.className.replace('from-[#006633] to-[#008040]', 'from-amber-500 to-amber-400').replace('hover:from-[#004d26]', 'hover:from-amber-600');
} else {
btnPay.className = btnPay.className.replace('from-amber-500 to-amber-400', 'from-[#006633] to-[#008040]').replace('hover:from-amber-600', 'hover:from-[#004d26]');
}
}
}
// ââ Changement durée ââââââââââââââââââââââââââââââââââââââââââââââââââââââ
document.querySelectorAll('input[name="modal-duree"]').forEach(radio => {
radio.addEventListener('change', function () {
currentDuree = this.value;
updatePrices();
document.querySelectorAll('.modal-dur-card').forEach(c => {
c.className = c.className
.replace('border-[#006633] bg-emerald-50/50', 'border-gray-200 bg-white')
.replace('border-gray-200 bg-white', 'border-gray-200 bg-white');
});
const active = this.closest('label').querySelector('.modal-dur-card');
active.className = active.className.replace('border-gray-200 bg-white', 'border-[#006633] bg-emerald-50/50');
});
});
// ââ Changement méthode paiement âââââââââââââââââââââââââââââââââââââââââââ
const COLORS = { huri_money: ['orange-400', 'orange-50/40'], mvola: ['green-600', 'green-50/40'], holo: ['blue-600', 'blue-50/40'] };
document.querySelectorAll('input[name="modal-methode"]').forEach(radio => {
radio.addEventListener('change', function () {
document.querySelectorAll('.modal-pay-card').forEach(c => {
c.className = 'modal-pay-card border-2 border-gray-200 bg-white rounded-xl p-3.5 flex items-center gap-3 transition-all hover:border-gray-300';
});
document.querySelectorAll('.modal-radio-dot').forEach(d => d.innerHTML = '');
const [border, bg] = COLORS[this.value] || ['gray-400', 'gray-50'];
const card = this.closest('label').querySelector('.modal-pay-card');
card.className = `modal-pay-card border-2 border-${border} bg-${bg} rounded-xl p-3.5 flex items-center gap-3 transition-all`;
const dot = this.closest('label').querySelector('.modal-radio-dot');
dot.innerHTML = `<div class="w-2 h-2 rounded-full bg-${border}"></div>`;
dot.className = `w-4 h-4 rounded-full border-2 border-${border} flex items-center justify-center modal-radio-dot`;
const label = document.getElementById('modal-provider-label');
if (label) label.textContent = PROVIDERS[this.value] || this.value;
});
});
// ââ Bouton payer âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
document.getElementById('modal-btn-pay')?.addEventListener('click', async function () {
const cgu = document.getElementById('m-cgu')?.checked;
const phone = document.getElementById('m-phone')?.value.trim().replace(/\s/g, '');
if (!cgu) { alert('Veuillez accepter les CGU.'); return; }
if (phone.length < 7) { alert('Numéro de téléphone invalide.'); return; }
this.disabled = true;
this.innerHTML = '<svg class="animate-spin w-4 h-4" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path></svg> Traitement…';
// TODO : remplacer par l'appel API de paiement réel
await new Promise(r => setTimeout(r, 1800));
// Remplir confirmation
const ref = 'JO-' + Date.now().toString(36).toUpperCase();
const prix = PRIX[currentPlan][currentDuree];
const date = new Date();
currentDuree === 'annuel' ? date.setFullYear(date.getFullYear() + 1) : date.setMonth(date.getMonth() + 1);
document.getElementById('modal-confirm-plan').textContent = LABELS[currentPlan];
document.getElementById('modal-confirm-ref').textContent = ref;
document.getElementById('modal-conf-plan2').textContent = LABELS[currentPlan];
document.getElementById('modal-conf-duree').textContent = currentDuree === 'annuel' ? 'Annuel' : 'Mensuel';
document.getElementById('modal-conf-montant').textContent = prix.toLocaleString('fr-FR') + ' KMF';
document.getElementById('modal-conf-renouvellement').textContent = date.toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric' });
modalGoStep(3);
});
})();
</script>
{% endblock %}