feat(PagesController): Ajoute la vérification de disponibilité du slug.

Ajoute une route pour vérifier la disponibilité d'un slug d'EPage.
Utilise EpageService pour vérifier si le slug est disponible.
Retourne une réponse JSON indiquant la disponibilité et le slug.
```
This commit is contained in:
Serreau Jovann
2025-12-26 13:31:23 +01:00
parent 4f08db7541
commit 80e4eaa907
6 changed files with 467 additions and 442 deletions

2
.env
View File

@@ -56,7 +56,7 @@ VAPID_PK=DsOg7jToRSD-VpNSV1Gt3YAhSwz4l-nqeu7yFvzbSxg
VAPID_PC=BKz0kdcsG6kk9KxciPpkfP8kEDAd408inZecij5kBDbQ1ZGZSNwS4KZ8FerC28LFXvgSqpDXtor3ePo0zBCdNqo VAPID_PC=BKz0kdcsG6kk9KxciPpkfP8kEDAd408inZecij5kBDbQ1ZGZSNwS4KZ8FerC28LFXvgSqpDXtor3ePo0zBCdNqo
CLOUDFLARE_ZONE_ID=a26d2ecd33d18c984f348eeb060ed5b3 CLOUDFLARE_ZONE_ID=a26d2ecd33d18c984f348eeb060ed5b3
CLOUDFLARE_API_TOKEN=zhpO0bBO8wdogBrDuePbpGzMRrY6pItGhPSmhQ-h CLOUDFLARE_API_TOKEN=Kq_hpaH_ng-hAeGsJo6KhQb2TxYW1v6lRGE84aOR
MARCHAND_ID=5685183792 MARCHAND_ID=5685183792
###> google/apiclient ### ###> google/apiclient ###
GOOGLE_API_KEY= GOOGLE_API_KEY=

View File

@@ -75,8 +75,8 @@ vich_uploader:
delete_on_update: true delete_on_update: true
delete_on_remove: true delete_on_remove: true
epage_avatar: epage_avatar:
uri_prefix: /epage_avatar/events uri_prefix: /storage/epage/
upload_destination: '%kernel.project_dir%/public/storage/epage_avatar' upload_destination: '%kernel.project_dir%/public/storage/epage'
namer: App\VichUploader\Namer\Epage\AvatarNamer # Replaced namer namer: App\VichUploader\Namer\Epage\AvatarNamer # Replaced namer
directory_namer: App\VichUploader\DirectoryNamer\Epage\DirectoryNamer directory_namer: App\VichUploader\DirectoryNamer\Epage\DirectoryNamer
inject_on_load: true inject_on_load: true

View File

@@ -5,6 +5,7 @@ namespace App\Controller;
use App\Entity\OnBoaringEpage; use App\Entity\OnBoaringEpage;
use App\Form\EPageOnboard; use App\Form\EPageOnboard;
use App\Repository\AbonementsRepository; use App\Repository\AbonementsRepository;
use App\Service\Epage\EpageService;
use Cocur\Slugify\Slugify; use Cocur\Slugify\Slugify;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@@ -23,6 +24,15 @@ class PagesController extends AbstractController
]); ]);
} }
#[Route(path: '/pages/check', name: 'app_pages_check', options: ['sitemap' => false], methods: ['GET','POST'])]
public function check(Request $request,EpageService $epageService): Response
{
$s = new Slugify();
$g = $request->get('q',null);
$slug = $s->slugify($g);
$isAvailable = $epageService->checkDispo($slug);
return $this->json(['available' => $isAvailable, 'slug' => $slug]);
}
#[Route(path: '/pages/discover', name: 'app_pages_discover', options: ['sitemap' => false], methods: ['GET','POST'])] #[Route(path: '/pages/discover', name: 'app_pages_discover', options: ['sitemap' => false], methods: ['GET','POST'])]
public function discover(): Response public function discover(): Response
{ {

View File

@@ -0,0 +1,71 @@
<?php
namespace App\Service\Epage;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class EpageService
{
const EPAGE_ROOT= ".e-cosplay.fr";
private mixed $zoneId;
private mixed $apiToken;
public function __construct(private readonly HttpClientInterface $httpClient,private readonly TranslatorInterface $translator)
{
// Les variables sont injectées via le conteneur de services (services.yaml)
$this->zoneId = $_ENV['CLOUDFLARE_ZONE_ID'];
$this->apiToken = $_ENV['CLOUDFLARE_API_TOKEN'];
}
public function checkDispo(string $dns): bool
{
$finalDomain = $dns . self::EPAGE_ROOT;
try {
$response = $this->httpClient->request('GET', "https://api.cloudflare.com/client/v4/zones/{$this->zoneId}/dns_records", [
'headers' => [
'Authorization' => 'Bearer ' . $this->apiToken,
'Content-Type' => 'application/json',
],
'query' => [
'name' => $finalDomain, // On filtre directement par le nom complet
],
]);
$data = $response->toArray();
// Cloudflare retourne un tableau 'result'.
// S'il est vide, l'enregistrement n'existe pas, donc c'est disponible (true).
return empty($data['result']);
} catch (\Exception $e) {
// En cas d'erreur API, on considère par sécurité que ce n'est pas disponible
// ou vous pouvez logger l'erreur selon votre politique.
return false;
}
}
public function createDns(string $dns) : array
{
$final = $dns.self::EPAGE_ROOT;
}
public function deleteDns(string $dns) : array
{
$final = $dns.self::EPAGE_ROOT;
}
public function updateDns(string $dns) : array
{
$final = $dns.self::EPAGE_ROOT;
}
public function addCustomDns()
{
}
public function deleteCustomDns()
{
}
}

View File

@@ -5,145 +5,207 @@
{% block canonical_url %}<link rel="canonical" href="{{ url('app_pages_onboaring',{type:app.request.get('abo','M1')}) }}" />{% endblock %} {% block canonical_url %}<link rel="canonical" href="{{ url('app_pages_onboaring',{type:app.request.get('abo','M1')}) }}" />{% endblock %}
{% block body %} {% block body %}
{{ form_start(form) }} <div class="min-h-screen bg-[#f0f0f0] py-12 px-4 italic">
<!-- Conteneur principal de la carte --> {{ form_start(form) }}
<div class="mt-2 mb-2 w-full max-w-4xl mx-auto mt-2 bg-white shadow-xl rounded-2xl p-6 md:p-10 border border-gray-100"> <div class="max-w-4xl mx-auto">
<h1 class="text-3xl font-bold text-gray-800 mb-8 text-center">{{ 'onboarding.form.title'|trans }}</h1> {# EN-TÊTE DU FORMULAIRE #}
<div class="mb-12 text-center">
<h1 class="inline-block text-4xl md:text-6xl font-black bg-gray-900 text-white p-6 border-8 border-gray-900 shadow-[12px_12px_0px_rgba(239,68,68,1)] uppercase tracking-tighter">
{{ 'onboarding.form.title'|trans }}
</h1>
</div>
<!-- Contenu des Étapes (Formulaire) - Tous affichés en colonnes --> <div class="space-y-12">
<div class="space-y-6">
<!-- Étape 1 Contenu --> {# SECTION 1 : INFORMATIONS PERSONNELLES #}
<div class="form-section"> <div class="bg-white border-8 border-gray-900 p-8 shadow-[12px_12px_0px_#4f46e5]">
<div class="p-6 bg-indigo-50 rounded-xl border border-indigo-200 shadow-sm"> <h2 class="text-3xl font-black text-indigo-700 mb-2 uppercase flex items-center tracking-tighter">
<h2 class="text-2xl font-bold text-indigo-700 mb-4 border-b border-indigo-300 pb-2 flex items-center"> <span class="bg-indigo-700 text-white px-3 mr-3 border-4 border-gray-900 shadow-[4px_4px_0px_rgba(0,0,0,1)]">1</span>
<svg class="w-6 h-6 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path></svg>
{{ 'onboarding.form.section1.title'|trans }} {{ 'onboarding.form.section1.title'|trans }}
</h2> </h2>
<p class="text-indigo-600 mb-6">{{ 'onboarding.form.section1.description'|trans }}</p> <p class="text-xs font-bold text-gray-500 uppercase tracking-widest mb-8 border-b-4 border-indigo-100 pb-2">
// {{ 'onboarding.form.section1.description'|trans }}
</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 form-input-group"> <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<!-- Nom --> <div class="neubrutal-input">{{ form_row(form.name) }}</div>
<div> <div class="neubrutal-input">{{ form_row(form.surname) }}</div>
{{ form_row(form.name) }} <div class="neubrutal-input">{{ form_row(form.email) }}</div>
<div class="neubrutal-input">{{ form_row(form.birdth) }}</div>
</div>
</div>
{# SECTION 2 : PROFIL COSPLAY + CHECK DISPO #}
<div class="bg-white border-8 border-gray-900 p-8 shadow-[12px_12px_0px_#eab308]">
<h2 class="text-3xl font-black text-yellow-600 mb-2 uppercase flex items-center tracking-tighter">
<span class="bg-yellow-400 text-black px-3 mr-3 border-4 border-gray-900 shadow-[4px_4px_0px_rgba(0,0,0,1)]">2</span>
{{ 'onboarding.form.section2.title'|trans }}
</h2>
<p class="text-xs font-bold text-gray-500 uppercase tracking-widest mb-8 border-b-4 border-yellow-100 pb-2">
// {{ 'onboarding.form.section2.description'|trans }}
</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div class="md:col-span-2 neubrutal-input relative">
{{ form_row(form.nameCosplayer) }}
{# Le feedback JS sera injecté ici #}
</div> </div>
<!-- Prénom --> <div class="md:col-span-2 neubrutal-input">{{ form_row(form.description)}}</div>
<div> <div class="md:col-span-2">{{ form_row(form.epage) }}</div>
{{ form_row(form.surname) }} </div>
</div>
{# SECTION 3 : RÉSEAUX SOCIAUX #}
<div class="bg-white border-8 border-gray-900 p-8 shadow-[12px_12px_0px_#22c55e]">
<h2 class="text-3xl font-black text-green-700 mb-2 uppercase flex items-center tracking-tighter">
<span class="bg-green-500 text-white px-3 mr-3 border-4 border-gray-900 shadow-[4px_4px_0px_rgba(0,0,0,1)]">3</span>
{{ 'onboarding.form.section3.title'|trans }}
</h2>
<p class="text-xs font-bold text-gray-500 uppercase tracking-widest mb-8 border-b-4 border-green-100 pb-2">
// {{ 'onboarding.form.section3.description'|trans }}
</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div class="neubrutal-input">{{ form_row(form.linkFacebook) }}</div>
<div class="neubrutal-input">{{ form_row(form.linkInstagram) }}</div>
<div class="neubrutal-input">{{ form_row(form.linkTiktok) }}</div>
<div class="neubrutal-input">{{ form_row(form.linkX) }}</div>
</div>
</div>
{# SECTION 4 : LIEN PERSONNALISÉ #}
<div class="bg-white border-8 border-gray-900 p-8 shadow-[12px_12px_0px_#3b82f6]">
<h2 class="text-3xl font-black text-blue-700 mb-2 uppercase flex items-center tracking-tighter">
<span class="bg-blue-600 text-white px-3 mr-3 border-4 border-gray-900 shadow-[4px_4px_0px_rgba(0,0,0,1)]">4</span>
{{ 'onboarding.form.section4.title'|trans }}
</h2>
<div class="mt-8 space-y-6">
<div class="p-4 bg-blue-50 border-4 border-blue-200 font-bold uppercase text-sm">
{{ form_row(form.useDomain) }}
</div> </div>
<!-- Email -->
<div class="md:col-span-1"> <div id="custom-domain-group" class="hidden transition-all duration-300 neubrutal-input p-6 bg-gray-900 text-white border-8 border-gray-900 shadow-[8px_8px_0px_#3b82f6]">
{{ form_row(form.email) }} {{ form_row(form.domain) }}
</div>
<!-- Date de naissance -->
<div class="md:col-span-1">
{{ form_row(form.birdth) }}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- Étape 2 Contenu --> {# BOUTON SOUMISSION #}
<div class="p-6 bg-yellow-50 rounded-xl border border-yellow-200 shadow-sm"> <div class="mt-16 flex justify-center pb-20">
<h2 class="text-2xl font-bold text-yellow-700 mb-4 border-b border-yellow-300 pb-2 flex items-center"> <button type="submit" class="group relative px-12 py-6 bg-indigo-600 text-white border-8 border-gray-900 text-3xl font-black uppercase tracking-widest shadow-[12px_12px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-x-2 hover:translate-y-2 transition-all active:scale-95">
<svg class="w-6 h-6 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 10h4.764a2 2 0 011.789 2.894l-3.5 7A2 2 0 0115.263 21h-4.639a2 2 0 01-1.789-2.894l3.5-7z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 9H2.236a2 2 0 01-1.789-2.894l3.5-7A2 2 0 014.737 3h4.636a2 2 0 011.789 2.894l-3.5 7z"></path></svg> {{ 'onboarding.form.submit_button'|trans }}
{{ 'onboarding.form.section2.title'|trans }} <i class="fas fa-rocket ml-4 group-hover:-translate-y-2 transition-transform"></i>
</h2> </button>
<p class="text-yellow-600 mb-6">{{ 'onboarding.form.section2.description'|trans }}</p>
<!-- Simulation du contenu du formulaire -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 form-input-group">
<div class="md:col-span-2">
{{ form_row(form.nameCosplayer) }}
</div>
<div class="md:col-span-2">
{{ form_row(form.description)}}
</div>
{{ form_row(form.epage) }}
</div>
</div> </div>
<!-- Étape 3 Contenu -->
<div class="p-6 bg-green-50 rounded-xl border border-green-200 shadow-sm">
<h2 class="text-2xl font-bold text-green-700 mb-4 border-b border-green-300 pb-2 flex items-center">
<svg class="w-6 h-6 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.886l2.273 2.273.744-.744-2.273-2.273z"></path></svg>
{{ 'onboarding.form.section3.title'|trans }}
</h2>
<p class="text-green-600 mb-6">{{ 'onboarding.form.section3.description'|trans }}</p>
<div class="grid grid-cols-2 md:grid-cols-2 gap-6 form-input-group">
<div>
{{ form_row(form.linkFacebook) }}
</div>
<div>
{{ form_row(form.linkInstagram) }}
</div>
<div>
{{ form_row(form.linkTiktok) }}
</div>
<div>
{{ form_row(form.linkX) }}
</div>
</div>
</div>
<!-- Étape 4 Contenu -->
<div class="p-6 bg-blue-50 rounded-xl border border-blue-200 shadow-sm">
<h2 class="text-2xl font-bold text-blue-700 mb-4 border-b border-blue-200 pb-2 flex items-center">
<svg class="w-6 h-6 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.5 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.5-3-9s1.343-9 3-9m-9 9h.01"></path></svg>
{{ 'onboarding.form.section4.title'|trans }}
</h2>
<div class="grid grid-cols-1 gap-6 form-input-group">
<!-- Checkbox for Custom Domain (form.useDomain) -->
<div class="mt-4 flex items-center">
{{ form_row(form.useDomain) }}
</div>
<!-- Custom Domain Input (form.domain) - Hidden by default -->
<div id="custom-domain-group" class="hidden transition-all duration-300 pt-4 border-t border-blue-200 mt-4">
{{ form_row(form.domain) }}
</div>
</div>
</div>
</div> </div>
{{ form_end(form) }}
<!-- Bouton unique de soumission -->
<div class="mt-8 flex justify-center">
<button class="px-8 py-3 text-lg font-semibold rounded-lg text-white bg-indigo-600 hover:bg-indigo-700 transition duration-150 shadow-lg shadow-indigo-200">
{{ 'onboarding.form.submit_button'|trans }}
</button>
</div>
</div> </div>
{{ form_end(form) }}
<style>
/* Design Neubrutaliste pour les inputs Symfony */
.neubrutal-input input,
.neubrutal-input textarea,
.neubrutal-input select {
width: 100%;
padding: 1rem;
border: 4px solid #111827 !important;
background: white;
font-weight: 900;
text-transform: uppercase;
box-shadow: 4px 4px 0px #111827;
transition: all 0.2s;
}
.neubrutal-input input:focus {
box-shadow: none;
transform: translate(2px, 2px);
outline: none;
border-color: #4f46e5 !important;
}
.neubrutal-input label {
display: block;
font-weight: 900;
text-transform: uppercase;
font-size: 0.75rem;
margin-bottom: 0.5rem;
letter-spacing: 0.1em;
}
/* Classes pour le Check Pseudo */
.check-success { border-color: #22c55e !important; box-shadow: 4px 4px 0px #15803d !important; }
.check-error { border-color: #ef4444 !important; box-shadow: 4px 4px 0px #b91c1c !important; }
</style>
<script> <script>
document.addEventListener('turbo:load', () => { document.addEventListener('turbo:load', () => {
// --- LOGIQUE DOMAINE PERSONNALISÉ ---
const useDomainCheckbox = document.getElementById('e_page_onboard_useDomain'); const useDomainCheckbox = document.getElementById('e_page_onboard_useDomain');
const customDomainGroup = document.getElementById('custom-domain-group'); const customDomainGroup = document.getElementById('custom-domain-group');
const customDomainInput = document.getElementById('e_page_onboard_domain'); const customDomainInput = document.getElementById('e_page_onboard_domain');
function toggleDomainFields() { function toggleDomainFields() {
if (useDomainCheckbox.checked) { if (useDomainCheckbox && useDomainCheckbox.checked) {
// Show custom domain field
customDomainGroup.classList.remove('hidden'); customDomainGroup.classList.remove('hidden');
customDomainInput.setAttribute('required', 'required'); customDomainInput.setAttribute('required', 'required');
} else if (useDomainCheckbox) {
} else {
// Hide custom domain field
customDomainGroup.classList.add('hidden'); customDomainGroup.classList.add('hidden');
customDomainInput.removeAttribute('required'); customDomainInput.removeAttribute('required');
customDomainInput.value = ''; // Clear custom domain value customDomainInput.value = '';
} }
} }
// Initial state setup (in case of browser refresh retaining checkbox state) if (useDomainCheckbox) {
toggleDomainFields(); toggleDomainFields();
useDomainCheckbox.addEventListener('change', toggleDomainFields);
}
// Event listener for the checkbox // --- LOGIQUE CHECK PSEUDO (DEBOUNCED) ---
useDomainCheckbox.addEventListener('change', toggleDomainFields); const pseudoInput = document.getElementById('e_page_onboard_nameCosplayer');
let timeout = null;
if (pseudoInput) {
// Création du message de feedback
const feedbackMsg = document.createElement('div');
feedbackMsg.className = 'text-[10px] font-black uppercase mt-2 tracking-widest hidden';
pseudoInput.parentNode.appendChild(feedbackMsg);
pseudoInput.addEventListener('keyup', () => {
const value = pseudoInput.value.trim();
if (value.length < 2) {
resetInputState(pseudoInput, feedbackMsg);
return;
}
clearTimeout(timeout);
timeout = setTimeout(() => {
fetch(`/pages/check?q=${encodeURIComponent(value)}`)
.then(response => response.json())
.then(data => {
if (data.available === true) {
pseudoInput.classList.remove('check-error');
pseudoInput.classList.add('check-success');
feedbackMsg.textContent = "DISPONIBLE // READY TO SYNC";
feedbackMsg.className = 'text-[10px] font-black uppercase mt-2 tracking-widest text-green-600 block';
} else {
pseudoInput.classList.remove('check-success');
pseudoInput.classList.add('check-error');
feedbackMsg.textContent = "NON DISPONIBLE // ALREADY TAKEN";
feedbackMsg.className = 'text-[10px] font-black uppercase mt-2 tracking-widest text-red-600 block';
}
})
.catch(() => console.error("API Check Error"));
}, 500); // 500ms debounce
});
}
function resetInputState(el, msg) {
el.classList.remove('check-success', 'check-error');
msg.classList.add('hidden');
}
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -1,410 +1,318 @@
{% extends 'base.twig' %} {% extends 'base.twig' %}
{# --- METADATA & SCHEMA --- #} {# --- METADATA & SCHEMA --- #}
{% block title %}{{'page.presentation.title'|trans}}{% endblock %} {% block title %}{{ 'page.presentation.title'|trans }}{% endblock %}
{% block meta_description %}{{'page.presentation.description'|trans}}{% endblock %} {% block meta_description %}{{ 'page.presentation.description'|trans }}{% endblock %}
{% block canonical_url %}
<link rel="canonical" href="{{ url('app_pages') }}" />
{% endblock %}
{% block canonical_url %}<link rel="canonical" href="{{ url('app_pages') }}" />{% endblock %}
{% block breadcrumb_schema %} {% block breadcrumb_schema %}
<script type="application/ld+json"> <script type="application/ld+json">
{ {
"@context": "https://schema.org", "@context": "https://schema.org",
"@type": "BreadcrumbList", "@type": "BreadcrumbList",
"itemListElement": [ "itemListElement": [
{ {
"@type": "ListItem", "@type": "ListItem",
"position": 1, "position": 1,
"name": "{{ 'breadcrumb.home'|trans }}", "name": "{{ 'breadcrumb.home'|trans }}",
"item": "{{ app.request.schemeAndHttpHost }}" "item": "{{ app.request.schemeAndHttpHost }}"
}, },
{ {
"@type": "ListItem", "@type": "ListItem",
"position": 2, "position": 2,
"name": "{{ 'page_presentation.breadcrumb'|trans }}", "name": "{{ 'page_presentation.breadcrumb'|trans }}",
"item": "{{ app.request.schemeAndHttpHost }}{{ app.request.pathInfo }}" "item": "{{ app.request.schemeAndHttpHost }}{{ app.request.pathInfo }}"
} }
] ]
} }
</script> </script>
{% endblock %} {% endblock %}
{# --- BODY --- #} {# --- BODY --- #}
{% block body %} {% block body %}
<main class="py-16 bg-gray-100/50 min-h-screen"> <div class="py-16 bg-[#f0f0f0] min-h-screen italic font-bold">
{# Wrapper global pour centrer le contenu et gérer le padding mobile #}
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{# Titre Style Moderne/Anime Épuré #} {# Titre Neubrutaliste #}
<h1 class="text-5xl md:text-6xl font-extrabold text-center mb-12 relative <div class="text-center mb-20">
tracking-tight pb-2 text-gray-900"> <h1 class="inline-block text-5xl md:text-7xl font-black bg-white border-8 border-gray-900 p-6 shadow-[12px_12px_0px_rgba(0,0,0,1)] uppercase tracking-tighter">
<span class="bg-clip-text text-transparent bg-gradient-to-r from-yellow-500 to-red-600">EPage</span> - {{ 'page.presentation.header'|trans }} <span class="text-transparent bg-clip-text bg-gradient-to-r from-yellow-500 to-red-600">EPage</span>
<span class="block w-24 h-1 mx-auto mt-2 bg-gradient-to-r from-red-500 to-yellow-500 rounded-full"></span> <span class="text-gray-900">// {{ 'page.presentation.header'|trans }}</span>
</h1> </h1>
</div>
{# Conteneur des Fonctionnalités #} {# Conteneur des Fonctionnalités #}
<div class="bg-white p-6 sm:p-8 md:p-14 rounded-3xl shadow-[0_20px_40px_-10px_rgba(0,0,0,0.2)] border-t-8 border-yellow-500/80"> <div class="bg-white border-8 border-gray-900 p-8 md:p-14 shadow-[16px_16px_0px_rgba(0,0,0,1)] mb-16">
<h2 class="text-3xl font-bold text-gray-800 mb-8 text-center"> <h2 class="text-4xl font-black text-gray-900 mb-10 uppercase underline decoration-yellow-500 decoration-8 underline-offset-8">
{{ 'page.presentation.subtitle'|trans }} {{ 'page.presentation.subtitle'|trans }}
</h2> </h2>
<p class="text-xl text-gray-600 mb-6 leading-relaxed text-center font-medium">
{{ 'page.presentation.intro_paragraph_1'|trans }}<span class="bg-clip-text text-transparent bg-gradient-to-r from-yellow-500 to-red-600">EPage</span> {{ 'page.presentation.intro_paragraph_1_2'|trans }} <p class="text-2xl text-gray-800 mb-8 leading-tight font-black uppercase tracking-tight">
{{ 'page.presentation.intro_paragraph_1'|trans }}
<span class="bg-yellow-400 px-2 text-black">EPage</span>
{{ 'page.presentation.intro_paragraph_1_2'|trans }}
</p> </p>
{# Clarification du Rôle de l'EPage #} {# Alerte Rôle EPage #}
<p class="text-lg sm:text-xl text-gray-700 mb-10 leading-relaxed text-center font-medium border-l-4 border-yellow-500 pl-4 sm:pl-6 py-3 bg-yellow-50 rounded-lg italic"> <div class="bg-gray-900 text-white p-6 border-l-[16px] border-red-500 mb-12 shadow-[8px_8px_0px_rgba(239,68,68,0.3)]">
{{ 'page.presentation.intro_paragraph_2'|trans({ <p class="text-lg md:text-xl font-bold leading-relaxed">
'page_span': '<span class="bg-clip-text text-transparent bg-gradient-to-r from-yellow-500 to-red-600">EPage</span>', {{ 'page.presentation.intro_paragraph_2'|trans({
'strong_tag': '<strong>', 'page_span': '<span class="text-yellow-400 uppercase font-black">EPage</span>',
'strong_end_tag': '</strong>', 'strong_tag': '<span class="text-white">',
'warning_tag': '<strong class="text-red-600/90 block mt-2">' 'strong_end_tag': '</span>',
})|raw }} 'warning_tag': '<span class="block mt-4 text-red-400 uppercase tracking-widest text-sm underline font-black">'
</p> })|raw }}
</p>
</div>
{# GRILLE DES FONCTIONNALITÉS (devient 1 colonne sur mobile, 2 sur md, 3 sur lg) #} {# GRILLE DES FONCTIONNALITÉS #}
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-10 text-gray-700"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 text-gray-900">
{# Bloc 1: Visibilité Maximale (Loupe) #} {# Bloc 1: SEO #}
<div class="p-6 border border-gray-200 rounded-xl hover:shadow-xl transition duration-500 transform hover:-translate-y-1 bg-white"> <div class="group p-8 border-4 border-gray-900 bg-white shadow-[8px_8px_0px_rgba(0,0,0,1)] hover:translate-x-1 hover:translate-y-1 hover:shadow-none transition-all duration-200">
<div class="flex items-center space-x-4 mb-3"> <div class="flex items-center mb-4">
<span class="text-red-500 text-3xl flex-shrink-0 p-2 bg-red-100 rounded-lg"> <div class="p-3 bg-red-500 border-4 border-gray-900 text-white mr-4 shadow-[4px_4px_0px_rgba(0,0,0,1)]">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-search"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
</span> </div>
<h3 class="font-extrabold text-xl text-gray-900">{{ 'page.presentation.feature.seo.title'|trans }}</h3> <h3 class="font-black text-xl uppercase leading-none">{{ 'page.presentation.feature.seo.title'|trans }}</h3>
</div> </div>
<p class="text-lg">{{ 'page.presentation.feature.seo.description'|trans({ <p class="font-bold text-gray-700 leading-snug">{{ 'page.presentation.feature.seo.description'|trans({
'page_span': '<span class="bg-clip-text text-transparent bg-gradient-to-r from-yellow-500 to-red-600">EPage</span>' 'page_span': '<span class="text-red-600 font-black">EPage</span>'
})|raw }}</p> })|raw }}</p>
</div> </div>
{# Bloc 2: Centralisation de Contenu (Chaîne) #} {# Bloc 2: Centralisation #}
<div class="p-6 border border-gray-200 rounded-xl hover:shadow-xl transition duration-500 transform hover:-translate-y-1 bg-white"> <div class="group p-8 border-4 border-gray-900 bg-white shadow-[8px_8px_0px_rgba(0,0,0,1)] hover:translate-x-1 hover:translate-y-1 hover:shadow-none transition-all duration-200">
<div class="flex items-center space-x-4 mb-3"> <div class="flex items-center mb-4">
<span class="text-yellow-500 text-3xl flex-shrink-0 p-2 bg-yellow-100 rounded-lg"> <div class="p-3 bg-yellow-400 border-4 border-gray-900 text-black mr-4 shadow-[4px_4px_0px_rgba(0,0,0,1)]">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-link-2"><path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3"/><path d="M9 17H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"/><line x1="8" x2="16" y1="12" y2="12"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3"/><path d="M9 17H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"/><line x1="8" x2="16" y1="12" y2="12"/></svg>
</span> </div>
<h3 class="font-extrabold text-xl text-gray-900">{{ 'page.presentation.feature.nexus.title'|trans }}</h3> <h3 class="font-black text-xl uppercase leading-none">{{ 'page.presentation.feature.nexus.title'|trans }}</h3>
</div> </div>
<p class="text-lg">{{ 'page.presentation.feature.nexus.description'|trans({ <p class="font-bold text-gray-700 leading-snug">{{ 'page.presentation.feature.nexus.description'|trans({
'strong_tag': '<strong>', 'strong_tag': '<span class="text-black underline decoration-yellow-400 decoration-4">',
'strong_end_tag': '</strong>' 'strong_end_tag': '</span>'
})|raw }}</p> })|raw }}</p>
</div> </div>
{# Bloc 3: Annonces & Événements (Calendrier) #} {# Bloc 3: Événements #}
<div class="p-6 border border-gray-200 rounded-xl hover:shadow-xl transition duration-500 transform hover:-translate-y-1 bg-white"> <div class="group p-8 border-4 border-gray-900 bg-white shadow-[8px_8px_0px_rgba(0,0,0,1)] hover:translate-x-1 hover:translate-y-1 hover:shadow-none transition-all duration-200">
<div class="flex items-center space-x-4 mb-3"> <div class="flex items-center mb-4">
<span class="text-red-500 text-3xl flex-shrink-0 p-2 bg-red-100 rounded-lg"> <div class="p-3 bg-red-500 border-4 border-gray-900 text-white mr-4 shadow-[4px_4px_0px_rgba(0,0,0,1)]">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-calendar-days"><rect width="18" height="18" x="3" y="4" rx="2" ry="2"/><line x1="16" x2="16" y1="2" y2="6"/><line x1="8" x2="8" y1="2" y2="6"/><line x1="3" x2="21" y1="10" y2="10"/><path d="M8 14h.01"/><path d="M12 14h.01"/><path d="M16 14h.01"/><path d="M8 18h.01"/><path d="M12 18h.01"/><path d="M16 18h.01"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="4" rx="2" ry="2"/><line x1="16" x2="16" y1="2" y2="6"/><line x1="8" x2="8" y1="2" y2="6"/><line x1="3" x2="21" y1="10" y2="10"/><path d="M8 14h.01"/><path d="M12 14h.01"/><path d="M16 14h.01"/><path d="M8 18h.01"/><path d="M12 18h.01"/><path d="M16 18h.01"/></svg>
</span> </div>
<h3 class="font-extrabold text-xl text-gray-900">{{ 'page.presentation.feature.convention.title'|trans }}</h3> <h3 class="font-black text-xl uppercase leading-none">{{ 'page.presentation.feature.convention.title'|trans }}</h3>
</div> </div>
<p class="text-lg">{{ 'page.presentation.feature.convention.description'|trans }}</p> <p class="font-bold text-gray-700 leading-snug">{{ 'page.presentation.feature.convention.description'|trans }}</p>
</div> </div>
{# Bloc 4: Intégration E-Cosplay (Cœur) #} {# Bloc 4: Intégration #}
<div class="p-6 border border-gray-200 rounded-xl hover:shadow-xl transition duration-500 transform hover:-translate-y-1 bg-white"> <div class="group p-8 border-4 border-gray-900 bg-white shadow-[8px_8px_0px_rgba(0,0,0,1)] hover:translate-x-1 hover:translate-y-1 hover:shadow-none transition-all duration-200">
<div class="flex items-center space-x-4 mb-3"> <div class="flex items-center mb-4">
<span class="text-yellow-500 text-3xl flex-shrink-0 p-2 bg-yellow-100 rounded-lg"> <div class="p-3 bg-yellow-400 border-4 border-gray-900 text-black mr-4 shadow-[4px_4px_0px_rgba(0,0,0,1)]">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-hand-heart"><path d="M11 14h2a2 2 0 0 0 2-2V7.5l-3.24-3.24a1 1 0 0 0-1.42 0L8 7.5V12a2 2 0 0 0 2 2h2"/><path d="M10 10l.02.02"/><path d="M14 10l.02.02"/><path d="M20 16c0 4.42-3.58 8-8 8s-8-3.58-8-8 8-16 8-16 8 11.58 8 16z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M11 14h2a2 2 0 0 0 2-2V7.5l-3.24-3.24a1 1 0 0 0-1.42 0L8 7.5V12a2 2 0 0 0 2 2h2"/><path d="M10 10l.02.02"/><path d="M14 10l.02.02"/><path d="M20 16c0 4.42-3.58 8-8 8s-8-3.58-8-8 8-16 8-16 8 11.58 8 16z"/></svg>
</span> </div>
<h3 class="font-extrabold text-xl text-gray-900">{{ 'page.presentation.feature.approval.title'|trans }}</h3> <h3 class="font-black text-xl uppercase leading-none">{{ 'page.presentation.feature.approval.title'|trans }}</h3>
</div> </div>
<p class="text-lg">{{ 'page.presentation.feature.approval.description'|trans({ <p class="font-bold text-gray-700 leading-snug">{{ 'page.presentation.feature.approval.description'|trans({
'strong_tag': '<strong>', 'strong_tag': '<span class="text-black underline decoration-red-500 decoration-4">',
'strong_end_tag': '</strong>' 'strong_end_tag': '</span>'
})|raw }}</p> })|raw }}</p>
</div> </div>
{# Bloc 5: Modération et Sécurité (Bouclier) #} {# Bloc 5: Sécurité #}
<div class="p-6 border border-gray-200 rounded-xl hover:shadow-xl transition duration-500 transform hover:-translate-y-1 bg-white"> <div class="group p-8 border-4 border-gray-900 bg-white shadow-[8px_8px_0px_rgba(0,0,0,1)] hover:translate-x-1 hover:translate-y-1 hover:shadow-none transition-all duration-200">
<div class="flex items-center space-x-4 mb-3"> <div class="flex items-center mb-4">
<span class="text-red-500 text-3xl flex-shrink-0 p-2 bg-red-100 rounded-lg"> <div class="p-3 bg-red-500 border-4 border-gray-900 text-white mr-4 shadow-[4px_4px_0px_rgba(0,0,0,1)]">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-shield-check"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10"/><path d="m9 12 2 2 4-4"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10"/><path d="m9 12 2 2 4-4"/></svg>
</span> </div>
<h3 class="font-extrabold text-xl text-gray-900">{{ 'page.presentation.feature.security.title'|trans }}</h3> <h3 class="font-black text-xl uppercase leading-none">{{ 'page.presentation.feature.security.title'|trans }}</h3>
</div>
<div class="font-bold text-gray-700 leading-tight space-y-2">
<p>{{ 'page.presentation.feature.security.description'|trans({'page_span': 'EPage', 'strong_tag': '<b>', 'strong_end_tag': '</b>'})|raw }}</p>
<p class="text-xs uppercase bg-gray-100 p-1">{{ 'page.presentation.feature.security.encrypted_data'|trans({'strong_tag': '', 'strong_end_tag': ''}) }}</p>
</div> </div>
<p class="text-lg">
{{ 'page.presentation.feature.security.description'|trans({
'page_span': '<span class="bg-clip-text text-transparent bg-gradient-to-r from-yellow-500 to-red-600">EPage</span>',
'strong_tag': '<strong>',
'strong_end_tag': '</strong>'
})|raw }}
</p>
<p class="text-lg mt-2">
{{ 'page.presentation.feature.security.encrypted_data'|trans({
'strong_tag': '<strong>',
'strong_end_tag': '</strong>'
})|raw }}
</p>
<p class="text-lg mt-2">
{{ 'page.presentation.feature.security.data_minimum'|trans }}
</p>
<p class="text-lg mt-2">
{{ 'page.presentation.feature.security.no_fly_inscription'|trans({
'strong_tag': '<strong>',
'strong_end_tag': '</strong>'
})|raw }}
</p>
</div> </div>
{# Bloc 6: Formulaire de Contact Sécurisé (Mail Check) #} {# Bloc 6: Contact #}
<div class="p-6 border border-gray-200 rounded-xl hover:shadow-xl transition duration-500 transform hover:-translate-y-1 bg-white"> <div class="group p-8 border-4 border-gray-900 bg-white shadow-[8px_8px_0px_rgba(0,0,0,1)] hover:translate-x-1 hover:translate-y-1 hover:shadow-none transition-all duration-200">
<div class="flex items-center space-x-4 mb-3"> <div class="flex items-center mb-4">
<span class="text-yellow-500 text-3xl flex-shrink-0 p-2 bg-yellow-100 rounded-lg"> <div class="p-3 bg-yellow-400 border-4 border-gray-900 text-black mr-4 shadow-[4px_4px_0px_rgba(0,0,0,1)]">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-mail-check"><path d="M22 10V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v12c0 1.1.9 2 2 2h10"/><path d="m22 10-7.23 6.11a3 3 0 0 1-3.48 0L2 10"/><path d="m16 22 2 2 4-4"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M22 10V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v12c0 1.1.9 2 2 2h10"/><path d="m22 10-7.23 6.11a3 3 0 0 1-3.48 0L2 10"/><path d="m16 22 2 2 4-4"/></svg>
</span> </div>
<h3 class="font-extrabold text-xl text-gray-900">{{ 'page.presentation.feature.contact.title'|trans }}</h3> <h3 class="font-black text-xl uppercase leading-none">{{ 'page.presentation.feature.contact.title'|trans }}</h3>
</div> </div>
<p class="text-lg"> <p class="font-bold text-gray-700 leading-snug">{{ 'page.presentation.feature.contact.description'|trans }}</p>
{{ 'page.presentation.feature.contact.description'|trans }} <a href="{{ path('app_rgpd') }}" class="mt-4 block text-[10px] uppercase font-black text-red-600 hover:underline italic">{{ 'page.presentation.feature.contact.policy_text'|trans }}</a>
<br><span class="text-sm mt-2 block text-gray-500 font-medium">{{ 'page.presentation.feature.contact.disclaimer'|trans}}<a target="_blank" class='text-red-500 hover:text-red-600 underline font-bold transition duration-300' href='{{ path('app_rgpd') }}'>{{ 'page.presentation.feature.contact.policy_text'|trans }}</a></span>
</p>
</div> </div>
{# Bloc 7: Personalisation (Palette) #}
<div class="p-6 border border-gray-200 rounded-xl hover:shadow-xl transition duration-500 transform hover:-translate-y-1 bg-white">
<div class="flex items-center space-x-4 mb-3">
<span class="text-red-500 text-3xl flex-shrink-0 p-2 bg-red-100 rounded-lg">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-palette"><circle cx="13.5" cy="6.5" r=".5" fill="currentColor"/><circle cx="17.5" cy="10.5" r=".5" fill="currentColor"/><circle cx="8.5" cy="7.5" r=".5" fill="currentColor"/><circle cx="10.5" cy="12.5" r=".5" fill="currentColor"/><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.92 0 1.63-.67 1.95-1.57.17-.46.33-.87.49-1.29.35-.91.78-1.78 1.3-2.58.6-1.14 1.34-2.13 2.22-2.91.88-.78 1.94-1.28 3.12-1.28C21.5 10.5 22 6.5 22 12c0-5.5-4.5-10-10-10z"/></svg>
</span>
<h3 class="font-extrabold text-xl text-gray-900">{{ 'page.presentation.feature.customization.title'|trans }}</h3>
</div>
<p class="text-lg">{{ 'page.presentation.feature.customization.description'|trans({
'page_span': '<span class="bg-clip-text text-transparent bg-gradient-to-r from-yellow-500 to-red-600">EPage</span>'
})|raw }}</p>
</div>
{# Bloc 8: Suivi / Analytics (Activity) #}
<div class="p-6 border border-gray-200 rounded-xl hover:shadow-xl transition duration-500 transform hover:-translate-y-1 bg-white">
<div class="flex items-center space-x-4 mb-3">
<span class="text-yellow-500 text-3xl flex-shrink-0 p-2 bg-yellow-100 rounded-lg">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-activity"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg>
</span>
<h3 class="font-extrabold text-xl text-gray-900">{{ 'page.presentation.feature.analytics.title'|trans }}</h3>
</div>
<p class="text-lg">{{ 'page.presentation.feature.analytics.description'|trans }}</p>
</div>
</div> </div>
</div> </div>
{# BLOC : OFFRE SANS ENGAGEMENT #} {# BLOC : OFFRE SANS ENGAGEMENT #}
<div class="mt-12 p-6 sm:p-8 bg-white border-2 border-red-500 rounded-2xl shadow-xl text-center"> <div class="mt-12 p-10 bg-white border-8 border-red-500 shadow-[12px_12px_0px_rgba(239,68,68,1)] text-center relative overflow-hidden">
<h4 class="text-xl sm:text-3xl font-extrabold text-gray-900 mb-3 flex items-center justify-center"> <div class="absolute top-0 left-0 bg-red-500 text-white px-6 py-2 uppercase font-black tracking-widest text-xs rotate-[-2deg] -translate-x-2 translate-y-2 border-4 border-gray-900">
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-rocket-launch mr-3 text-red-500"><path d="M10 21h4c1.1 0 2-.9 2-2v-7a2 2 0 0 0-2-2h-4c-1.1 0-2 .9-2 2v7c0 1.1.9 2 2 2z"/><path d="M12 10a2 2 0 0 0 2-2V4a2 2 0 1 0-4 0v4a2 2 0 0 0 2 2z"/><path d="M7 16l-3 3"/><path d="M17 16l3 3"/><path d="M12 21v-2"/></svg> PRO MISSION
</div>
<h4 class="text-4xl font-black text-gray-900 mb-6 uppercase tracking-tighter italic">
{{ 'page.presentation.flexibility.title'|trans }} {{ 'page.presentation.flexibility.title'|trans }}
</h4> </h4>
<p class="text-lg sm:text-xl text-gray-700 leading-relaxed"> <div class="text-2xl font-bold text-gray-800 leading-tight">
{{ 'page.presentation.flexibility.no_commitment'|trans({ {{ 'page.presentation.flexibility.no_commitment'|trans({
'page_span': '<span class="bg-clip-text text-transparent bg-gradient-to-r from-yellow-500 to-red-600">EPage</span>', 'page_span': '<span class="text-red-600 uppercase font-black">EPage</span>',
'strong_tag': '<strong>', 'strong_tag': '<span class="underline decoration-yellow-400 decoration-4 px-1">',
'strong_end_tag': '</strong>' 'strong_end_tag': '</span>'
})|raw }} })|raw }}
</p> </div>
<p class="text-base sm:text-lg text-gray-600 mt-2">
{{ 'page.presentation.flexibility.renewal_auto'|trans|raw }}
<strong>{{ 'page.presentation.flexibility.periods_cancel'|trans }}</strong>
</p>
</div> </div>
{# Appel à l'action pour les étapes #} {# Appel à l'action étapes #}
<div class="text-center mt-16"> <div class="text-center mt-24">
<h3 class="text-2xl sm:text-3xl font-extrabold text-gray-800 mb-5">{{ 'page.presentation.call_to_action'|trans }}</h3> <h3 class="text-5xl font-black text-gray-900 uppercase italic tracking-tighter bg-yellow-400 inline-block px-4 border-4 border-gray-900 shadow-[6px_6px_0px_rgba(0,0,0,1)]">
{{ 'page.presentation.call_to_action'|trans }}
</h3>
</div> </div>
{# CONTENEUR DE GRILLE POUR LES 3 BLOCS D'INFORMATION #} {# GRILLE INFOS TECHNIQUES #}
<div class="mt-12 grid grid-cols-1 md:grid-cols-3 gap-6 sm:gap-8"> <div class="mt-12 grid grid-cols-1 md:grid-cols-3 gap-8">
{# Bloc 1: Domaine #}
{# BLOC 1: INFO TECHNIQUE NOM DE DOMAINE #} <div class="p-8 bg-white border-4 border-gray-900 shadow-[8px_8px_0px_rgba(234,179,8,1)]">
<div class="p-6 sm:p-8 bg-yellow-50 border border-yellow-300 rounded-xl shadow-md text-gray-700"> <h4 class="text-2xl font-black text-yellow-600 mb-4 uppercase tracking-tighter italic border-b-4 border-gray-100 pb-2">
<h4 class="text-xl sm:text-2xl font-extrabold text-yellow-700 mb-3 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-code-square mr-2"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="m10 13-2-2 2-2"/><path d="m14 11 2 2-2 2"/></svg>
{{ 'page.presentation.domain_info.title'|trans }} {{ 'page.presentation.domain_info.title'|trans }}
</h4> </h4>
<p class="text-base sm:text-lg leading-relaxed"> <div class="space-y-4 font-bold text-gray-800 text-sm md:text-base uppercase tracking-tight">
<strong>{{ 'page.presentation.domain_info.no_domain_question'|trans }}</strong> <p>{{ 'page.presentation.domain_info.no_domain_question'|trans }}</p>
<br>{{ 'page.presentation.domain_info.default_url'|trans({ <code class="block bg-gray-900 text-yellow-400 p-3 border-2 border-gray-900 font-mono text-xs break-all">
'url_part': '<code class="bg-gray-200 text-yellow-800 p-1 rounded font-mono text-sm">votre_pseudo.<span class="bg-clip-text text-transparent bg-gradient-to-r from-yellow-500 to-red-600">e-cosplay</span>.com</code>' votre_pseudo.e-cosplay.com
})|raw }} </code>
</p> <p>{{ 'page.presentation.domain_info.has_domain_question'|trans }}</p>
<p class="text-base sm:text-lg leading-relaxed mt-3"> <p class="text-xs text-gray-500">{{ 'page.presentation.domain_info.cname_guide'|trans({'page_span': 'EPage'})|raw }}</p>
<strong>{{ 'page.presentation.domain_info.has_domain_question'|trans }}</strong> </div>
<br>{{ 'page.presentation.domain_info.cname_guide'|trans({
'page_span': '<span class="bg-clip-text text-transparent bg-gradient-to-r from-yellow-500 to-red-600">EPage</span>'
})|raw }}
</p>
<p class="text-base sm:text-lg leading-relaxed mt-3 border-t pt-3 border-yellow-300">
<strong class="text-yellow-700">{{ 'page.presentation.domain_info.purchase_title'|trans }}</strong>
<br>{{ 'page.presentation.domain_info.partner_purchase'|trans({
'partner_strong': '<strong>SARL SITECONSEIL</strong>'
})|raw }}
</p>
</div> </div>
{# BLOC 2: INFO LÉGALE COPYRIGHT #} {# Bloc 2: Copyright #}
<div class="p-6 sm:p-8 bg-blue-50 border border-blue-300 rounded-xl shadow-md text-gray-700"> <div class="p-8 bg-white border-4 border-gray-900 shadow-[8px_8px_0px_rgba(37,99,235,1)]">
<h4 class="text-xl sm:text-2xl font-extrabold text-blue-700 mb-3 flex items-center"> <h4 class="text-2xl font-black text-blue-600 mb-4 uppercase tracking-tighter italic border-b-4 border-gray-100 pb-2">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-gavel mr-2"><path d="m15 11-8 8"/><path d="m14 4 6 6"/><path d="m4 4 6 6"/><path d="M17 17l5 5"/><path d="m15 11-1 1-2 2-2 2"/></svg>
{{ 'page.presentation.copyright_info.title'|trans }} {{ 'page.presentation.copyright_info.title'|trans }}
</h4> </h4>
<p class="text-base sm:text-lg leading-relaxed"> <p class="font-bold text-gray-800 leading-snug uppercase text-sm">
{{ 'page.presentation.copyright_info.responsibility'|trans({ {{ 'page.presentation.copyright_info.responsibility'|trans({
'page_span': '<span class="bg-clip-text text-transparent bg-gradient-to-r from-yellow-500 to-red-600">EPage</span>', 'page_span': 'EPage',
'strong_tag': '<strong>', 'strong_tag': '<span class="text-blue-600">',
'strong_end_tag': '</strong>', 'strong_end_tag': '</span>',
'red_strong': '<strong class="text-red-600">' 'red_strong': '<span class="text-red-600">'
})|raw }} })|raw }}
</p> </p>
<p class="text-base sm:text-lg leading-relaxed mt-3">
<strong class="text-blue-700">{{ 'page.presentation.copyright_info.help_team'|trans }}</strong>
<br>{{ 'page.presentation.copyright_info.contact_us'|trans }}
</p>
</div> </div>
{# BLOC 3: INFO FONCTIONNALITÉS SUPPLÉMENTAIRES #} {# Bloc 3: Add-ons #}
<div class="p-6 sm:p-8 bg-red-50 border border-red-300 rounded-xl shadow-md text-gray-700"> <div class="p-8 bg-white border-4 border-gray-900 shadow-[8px_8px_0px_rgba(220,38,38,1)]">
<h4 class="text-xl sm:text-2xl font-extrabold text-red-700 mb-3 flex items-center"> <h4 class="text-2xl font-black text-red-600 mb-4 uppercase tracking-tighter italic border-b-4 border-gray-100 pb-2">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-zap mr-2"><path d="M10 17l6-6-6-6v3H4v6h6z"/></svg>
{{ 'page.presentation.additional_features.title'|trans }} {{ 'page.presentation.additional_features.title'|trans }}
</h4> </h4>
<p class="text-base sm:text-lg leading-relaxed"> <p class="font-bold text-gray-800 leading-snug uppercase text-sm mb-4">
{{ 'page.presentation.additional_features.request_support'|trans({ {{ 'page.presentation.additional_features.request_support'|trans({
'page_span': '<span class="bg-clip-text text-transparent bg-gradient-to-r from-yellow-500 to-red-600">EPage</span>', 'page_span': 'EPage',
'strong_tag': '<strong>', 'strong_tag': '<span class="text-red-600">',
'strong_end_tag': '</strong>' 'strong_end_tag': '</span>'
})|raw }} })|raw }}
</p> </p>
<p class="text-base sm:text-lg leading-relaxed mt-3"> <p class="text-[10px] text-gray-400 uppercase font-black tracking-widest border-t-2 border-gray-100 pt-4">
{{ 'page.presentation.additional_features.siteconseil_referral'|trans({ PARTNER_REFERRAL: SARL SITECONSEIL
'partner_strong_cyan': '<strong class="text-cyan-700">SARL SITECONSEIL</strong>'
})|raw }}
</p> </p>
</div> </div>
</div> </div>
{# BLOC DE TARIFICATION EPage (CARTE UNIQUE AVEC SÉLECTEUR) - CENTRÉ ET RESPONSIVE #} {# BLOC TARIFICATION #}
<div class="mt-16 text-center" style="display: none"> <div id="pricing-section" class="mt-24 text-center" style="display: none">
<h3 class="text-4xl font-extrabold text-gray-800 mb-8">{{ 'page.presentation.pricing.choose_period'|trans }}</h3> <h3 class="text-5xl font-black text-gray-900 mb-10 uppercase tracking-tighter">{{ 'page.presentation.pricing.choose_period'|trans }}</h3>
<div class="max-w-xl mx-auto p-6 sm:p-8 bg-white border-4 border-red-500 rounded-3xl shadow-2xl"> <div class="max-w-2xl mx-auto bg-white border-8 border-gray-900 p-8 md:p-12 shadow-[20px_20px_0px_rgba(0,0,0,1)] relative">
<h4 class="text-3xl font-bold text-gray-900 mb-6"> <div class="absolute -top-6 left-1/2 -translate-x-1/2 bg-gray-900 text-white px-10 py-2 uppercase font-black text-xl italic skew-x-[-10deg]">
<span class="bg-clip-text text-transparent bg-gradient-to-r from-yellow-500 to-red-600">EPage</span> Access Terminal
</div>
<h4 class="text-4xl font-black text-transparent bg-clip-text bg-gradient-to-r from-yellow-500 to-red-600 mb-10 uppercase italic">
EPage Connect
</h4> </h4>
{# SÉLECTEUR DE DURÉE (Utilise flex-wrap pour s'adapter sur mobile) #} {# SÉLECTEUR DE DURÉE #}
<div class="flex flex-wrap justify-center gap-2 sm:gap-4 mb-8 bg-gray-100 p-2 rounded-xl"> <div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 gap-3 mb-10">
{% for period in ['1M', '2M', '3M', '6M', '12M'] %}
<label class="relative flex-1 cursor-pointer min-w-[70px]"> <label class="relative cursor-pointer group">
<input type="radio" name="duration" value="1M" class="peer hidden" checked onchange="updatePrice(this.value)"> <input type="radio" name="duration" value="{{ period }}" class="peer hidden" {% if period == '1M' %}checked{% endif %} onchange="updatePrice(this.value)">
<span class="block px-2 sm:px-4 py-2 text-sm sm:text-lg font-semibold text-gray-700 bg-white rounded-lg transition duration-200 <span class="flex items-center justify-center py-3 border-4 border-gray-900 font-black uppercase text-xs transition-all peer-checked:bg-red-500 peer-checked:text-white peer-checked:translate-x-1 peer-checked:translate-y-1 peer-checked:shadow-none shadow-[4px_4px_0px_rgba(0,0,0,1)] group-hover:bg-gray-100">
peer-checked:bg-red-500 peer-checked:text-white peer-checked:shadow-lg hover:bg-red-100"> {{ ('page.presentation.pricing.period_' ~ period|lower)|trans }}
{{ 'page.presentation.pricing.period_1m'|trans }}
</span> </span>
</label> </label>
{% endfor %}
<label class="relative flex-1 cursor-pointer group min-w-[70px]">
<input type="radio" name="duration" value="2M" class="peer hidden" onchange="updatePrice(this.value)">
<span class="block px-2 sm:px-4 py-2 text-sm sm:text-lg font-semibold text-gray-700 bg-white rounded-lg transition duration-200
peer-checked:bg-red-500 peer-checked:text-white peer-checked:shadow-lg hover:bg-red-100">
{{ 'page.presentation.pricing.period_2m'|trans }}
<span class="absolute top-[-10px] right-[-5px] text-[10px] sm:text-xs font-bold text-white bg-yellow-500 px-1.5 py-0.5 rounded-full shadow-md transform -rotate-3 group-hover:rotate-0 transition">{{ 'page.presentation.pricing.save_2e'|trans }}</span>
</span>
</label>
<label class="relative flex-1 cursor-pointer group min-w-[70px]">
<input type="radio" name="duration" value="3M" class="peer hidden" onchange="updatePrice(this.value)">
<span class="block px-2 sm:px-4 py-2 text-sm sm:text-lg font-semibold text-gray-700 bg-white rounded-lg transition duration-200
peer-checked:bg-red-500 peer-checked:text-white peer-checked:shadow-lg hover:bg-red-100">
{{ 'page.presentation.pricing.period_3m'|trans }}
<span class="absolute top-[-10px] right-[-5px] text-[10px] sm:text-xs font-bold text-white bg-yellow-500 px-1.5 py-0.5 rounded-full shadow-md transform -rotate-3 group-hover:rotate-0 transition">{{ 'page.presentation.pricing.save_3e'|trans }}</span>
</span>
</label>
<label class="relative flex-1 cursor-pointer group min-w-[70px]">
<input type="radio" name="duration" value="6M" class="peer hidden" onchange="updatePrice(this.value)">
<span class="block px-2 sm:px-4 py-2 text-sm sm:text-lg font-semibold text-gray-700 bg-white rounded-lg transition duration-200
peer-checked:bg-red-500 peer-checked:text-white peer-checked:shadow-lg hover:bg-red-100">
{{ 'page.presentation.pricing.period_6m'|trans }}
<span class="absolute top-[-10px] right-[-5px] text-[10px] sm:text-xs font-bold text-white bg-yellow-500 px-1.5 py-0.5 rounded-full shadow-md transform -rotate-3 group-hover:rotate-0 transition">{{ 'page.presentation.pricing.save_0e'|trans }}</span>
</span>
</label>
<label class="relative flex-1 cursor-pointer group min-w-[70px]">
<input type="radio" name="duration" value="12M" class="peer hidden" onchange="updatePrice(this.value)">
<span class="block px-2 sm:px-4 py-2 text-sm sm:text-lg font-semibold text-gray-700 bg-white rounded-lg transition duration-200
peer-checked:bg-red-500 peer-checked:text-white peer-checked:shadow-lg hover:bg-red-100">
{{ 'page.presentation.pricing.period_12m'|trans }}
<span class="absolute top-[-10px] right-[-5px] text-[10px] sm:text-xs font-bold text-white bg-red-700 px-1.5 py-0.5 rounded-full shadow-md transform -rotate-3 group-hover:rotate-0 transition">{{ 'page.presentation.pricing.best_deal'|trans }}</span>
</span>
</label>
</div> </div>
{# AFFICHAGE DU PRIX DYNAMIQUE #} {# PRIX DYNAMIQUE #}
<div class="text-5xl sm:text-6xl font-extrabold text-gray-900 my-6"> <div class="bg-gray-900 text-white p-8 border-4 border-gray-900 shadow-[8px_8px_0px_rgba(234,179,8,1)] mb-8">
<span id="current-price">5€</span><span class="text-xl sm:text-2xl text-red-600"> {{ 'page.presentation.pricing.tax_info'|trans }}</span> <div class="text-7xl font-black tracking-tighter mb-2 italic">
<span id="current-price">5€</span>
</div>
<p class="text-yellow-400 font-black uppercase tracking-widest text-xs">
{{ 'page.presentation.pricing.tax_info'|trans }}
</p>
</div> </div>
<p id="price-per-month" class="text-lg sm:text-xl text-gray-500 mb-8"></p> <p id="price-per-month" class="text-sm font-black text-gray-500 uppercase tracking-widest mb-10 h-10"></p>
{# BOUTON D'ACTION #} <button onclick="redirectToCheckout()" class="w-full py-6 bg-red-600 text-white border-4 border-gray-900 font-black text-2xl uppercase tracking-widest shadow-[10px_10px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-x-2 hover:translate-y-2 transition-all active:scale-95">
<button onclick="redirectToCheckout()" class="w-full px-8 py-4 bg-gradient-to-r from-yellow-500 to-red-600 text-white font-extrabold text-xl rounded-xl transition duration-300 transform hover:scale-[1.03] shadow-lg shadow-red-300/50">
{{ 'page.presentation.pricing.cta_button'|trans }} {{ 'page.presentation.pricing.cta_button'|trans }}
</button> </button>
<p class="text-xs sm:text-sm text-gray-500 mt-4 italic"> <p class="text-[9px] text-gray-400 uppercase font-bold mt-6 tracking-widest">
{{ 'page.presentation.pricing.disclaimer'|trans }} {{ 'page.presentation.pricing.disclaimer'|trans }}
</p> </p>
</div> </div>
</div> </div>
{# BLOC PARTENARIAT SITECONSEIL #}
<div class="mt-20 pt-10 pb-10 bg-white text-gray-900 rounded-3xl shadow-2xl border border-gray-200"> {# BLOC PARTENARIAT #}
<div class="text-center px-4 sm:px-6"> <div class="mt-32 p-10 bg-white border-8 border-cyan-500 shadow-[12px_12px_0px_rgba(6,182,212,1)] flex flex-col md:flex-row items-center gap-10">
<h3 class="text-3xl sm:text-4xl font-extrabold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-cyan-600"> <div class="flex-1 text-left">
<h3 class="text-3xl font-black text-cyan-600 uppercase italic tracking-tighter mb-4">
{{ 'page.presentation.siteconseil_partner.title'|trans }} {{ 'page.presentation.siteconseil_partner.title'|trans }}
</h3> </h3>
<p class="text-lg sm:text-xl text-gray-600 mb-6"> <p class="text-gray-800 font-bold uppercase text-sm leading-tight">
{{ 'page.presentation.siteconseil_partner.intro'|trans({ {{ 'page.presentation.siteconseil_partner.intro'|trans({
'page_span': '<span class="bg-clip-text text-transparent bg-gradient-to-r from-yellow-500 to-red-600">EPage</span>', 'page_span': '<span class="text-cyan-600 font-black underline">EPage</span>',
'strong_tag': '<strong>', 'strong_tag': '<b>',
'strong_end_tag': '</strong>' 'strong_end_tag': '</b>'
})|raw }} })|raw }}
</p> </p>
</div>
<div class="bg-gray-100 p-6 rounded-xl border-l-8 border-cyan-500 inline-block max-w-xl text-gray-900"> <div class="bg-gray-900 text-white p-6 border-4 border-gray-900 shadow-[8px_8px_0px_rgba(6,182,212,0.5)] max-w-sm">
<p class="text-xl sm:text-2xl font-bold mb-2">{{ 'page.presentation.siteconseil_partner.recommended'|trans }}</p> <p class="text-xs font-black text-cyan-400 uppercase mb-4 tracking-widest">{{ 'page.presentation.siteconseil_partner.recommended'|trans }}</p>
<p class="text-base sm:text-lg text-gray-700"> <p class="text-sm font-bold mb-6">
{{ 'page.presentation.siteconseil_partner.cms_info'|trans({ {{ 'page.presentation.siteconseil_partner.cms_info'|trans({
'partner_strong': '<strong>SARL SITECONSEIL</strong>', 'partner_strong': '<span class="text-cyan-400">SARL SITECONSEIL</span>',
'cms_strong': '<strong class="text-yellow-600">Esy-Flex</strong>' 'cms_strong': '<span class="text-yellow-400 font-black">Esy-Flex</span>'
})|raw }} })|raw }}
</p> </p>
<p class="text-base sm:text-lg text-gray-700 mt-2"> <a href="https://www.siteconseil.fr" target="_blank" class="block text-center py-3 bg-cyan-500 text-gray-900 font-black uppercase text-xs border-2 border-white hover:bg-white transition-colors">
{{ 'page.presentation.siteconseil_partner.offer_info'|trans }} {{ 'page.presentation.siteconseil_partner.discover_button'|trans }} _
</p> </a>
<a href="https://www.siteconseil.fr" target="_blank" class="mt-4 inline-block px-6 sm:px-8 py-3 bg-cyan-500 hover:bg-cyan-600 text-gray-900 font-extrabold text-base sm:text-lg rounded-full transition duration-300 transform hover:scale-105 shadow-lg">
{{ 'page.presentation.siteconseil_partner.discover_button'|trans }}
<!-- Icone de Lien Externe -->
<svg xmlns="http://www.w3.org/2000/svg" class="inline-block ml-2 h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 7h10v10"/><path d="M10 14L16.6 7.4"/></svg>
</a>
</div>
</div> </div>
</div> </div>
</div> </div>
{# --- JAVASCRIPT --- #}
<script> <script>
// Données de prix (en Euros HT)
const pricing = { const pricing = {
'1M': { price: 5, label: '5€ / mois' }, '1M': {price: 5, label: '5€ / mois'},
'2M': { price: 8, label: '4€ / mois' }, '2M': {price: 8, label: '4€ / mois'},
'3M': { price: 12, label: '4€ / mois' }, '3M': {price: 12, label: '4€ / mois'},
'6M': { price: 25, label: '4.16€ / mois' }, '6M': {price: 25, label: '4.16€ / mois'},
'12M': { price: 40, label: '3.33€ / mois' } '12M': {price: 40, label: '3.33€ / mois'}
}; };
// Translation Keys (In a real Symfony app, these would be loaded from an assets file or context)
const translations = { const translations = {
'monthly_renewal': '{{ 'page.presentation.js.monthly_renewal'|trans }}', 'monthly_renewal': '{{ 'page.presentation.js.monthly_renewal'|trans }}',
'annual_billing': '{{ 'page.presentation.js.annual_billing'|trans }}', 'annual_billing': '{{ 'page.presentation.js.annual_billing'|trans }}',
@@ -414,59 +322,35 @@
function updatePrice(duration) { function updatePrice(duration) {
const priceElement = document.getElementById('current-price'); const priceElement = document.getElementById('current-price');
const perMonthElement = document.getElementById('price-per-month'); const perMonthElement = document.getElementById('price-per-month');
const data = pricing[duration]; const data = pricing[duration];
if (data) { if (data) {
priceElement.textContent = data.price + '€'; priceElement.textContent = data.price + '€';
if (duration === '1M') { if (duration === '1M') {
perMonthElement.textContent = translations.monthly_renewal; perMonthElement.textContent = translations.monthly_renewal;
} else if (duration === '12M') { } else if (duration === '12M') {
// Use string replacement for translated text with interpolation
const translatedText = translations.annual_billing.replace( const translatedText = translations.annual_billing.replace(
'%average_price%', `<strong class="text-red-500">${data.label}</strong>` '%average_price%', `<span class="text-red-600 font-black underline decoration-4 underline-offset-4">${data.label}</span>`
); );
perMonthElement.innerHTML = translatedText; perMonthElement.innerHTML = translatedText;
} else { } else {
// Use string replacement for translated text with interpolation
const months = duration.replace('M', ''); const months = duration.replace('M', '');
const translatedText = translations.periodic_billing const translatedText = translations.periodic_billing
.replace('%duration%', months) .replace('%duration%', months)
.replace('%average_price%', `<strong class="text-red-500">${data.label}</strong>`); .replace('%average_price%', `<span class="text-red-600 font-black underline decoration-4 underline-offset-4">${data.label}</span>`);
perMonthElement.innerHTML = translatedText; perMonthElement.innerHTML = translatedText;
} }
} }
} }
// Initialiser le prix au chargement (pour l'abonnement 1M).
// J'utilise turbo:load ou DOMContentLoaded comme fallback.
function initializePrice() { function initializePrice() {
updatePrice('1M'); updatePrice('1M');
} }
function redirectToCheckout() { function redirectToCheckout() {
const selectedDurationInput = document.querySelector('input[name="duration"]:checked'); const selectedDurationInput = document.querySelector('input[name="duration"]:checked');
const selectedDuration = selectedDurationInput ? selectedDurationInput.value : '1M';
if (selectedDurationInput) { window.location.href = `/pages/onboaring?abo=${selectedDuration}`;
const selectedDuration = selectedDurationInput.value;
// --- AJOUT DE LA VALIDATION DE DURÉE ---
if (VALID_DURATIONS.includes(selectedDuration)) {
// Redirection avec le paramètre 'abo' valide
window.location.href = `/pages/onboaring?abo=${selectedDuration}`;
} else {
// Fallback si la durée sélectionnée n'est pas dans la liste des valides
console.error("Durée d'abonnement sélectionnée non valide:", selectedDuration);
// On peut rediriger vers la page par défaut si l'on ne veut pas bloquer l'utilisateur
window.location.href = `/pages/onboaring?abo=1M`;
}
} else {
// Fallback si rien n'est sélectionné (redirection par défaut vers 1M ou page de découverte)
console.error("Aucune durée d'abonnement sélectionnée. Redirection par défaut.");
window.location.href = `/pages/onboaring?abo=1M`;
}
} }
if (typeof window.Turbo !== 'undefined') { if (typeof window.Turbo !== 'undefined') {
@@ -475,7 +359,5 @@
document.addEventListener('DOMContentLoaded', initializePrice); document.addEventListener('DOMContentLoaded', initializePrice);
} }
</script> </script>
</main> </div>
{% endblock %} {% endblock %}