{# templates/commande/wizard.html.twig #} {# Wizard Multi-Formulaires NUM-ECARD - Style Apple #} {% extends 'base.html.twig' %} {% block title %}Commander {{ packLabel }} × {{ quantity }}{% endblock %} {% block stylesheets %} {{ parent() }} {% endblock %} {% block body %}
{# ==================================================================== HEADER - INFO COMMANDE ==================================================================== #}
{% if isCartEdit|default(false) %}

✏️ Modifier ma carte

Modifiez les informations de votre carte {{ packLabel }}

{% else %}

🎯 {{ packLabel }}

{{ totalCards }} carte{{ totalCards > 1 ? 's' : '' }} de visite digitale{{ totalCards > 1 ? 's' : '' }} à configurer

{% endif %}
{% if not isCartEdit|default(false) %}
{{ totalHT|number_format(0, ',', ' ') }} € HT
{{ totalTTC|number_format(2, ',', ' ') }} € TTC
{% endif %}
{# ==================================================================== NAVIGATION BÉNÉFICIAIRES (si plusieurs) ==================================================================== #} {% if totalCards > 1 %} {# Calcul du nombre de cartes par pack selon le type #} {% set isMultiPack = packType starts with 'multi-' %} {% if isMultiPack %} {% set cardsPerPack = packType|replace({'multi-': ''})|number_format(0) %} {% else %} {% set cardsPerPack = totalCards %} {# Pour non-multi, toutes les cartes = 1 seul "pack" #} {% endif %} {% set totalPacks = (totalCards / cardsPerPack)|round(0, 'ceil') %}
{% for i in 1..totalCards %} {# Calcul du numéro de pack pour cette carte (seulement pour multi) #} {% if isMultiPack %} {% set packNum = ((i - 1) // cardsPerPack) + 1 %} {% set packClass = 'pack-' ~ packNum %} {% else %} {% set packClass = '' %} {# Pas de couleur par pack pour Essentiel/Premium/Force de Vente #} {% endif %} {% endfor %}
{# Légende des packs (seulement pour les packs multi avec plusieurs packs) #} {% if totalPacks > 1 and packType starts with 'multi-' %}
{% for p in 1..totalPacks %} {% set startCard = (p - 1) * cardsPerPack + 1 %} {% set endCard = p * cardsPerPack %} {% if endCard > totalCards %}{% set endCard = totalCards %}{% endif %}
Pack {{ p }} (cartes {{ startCard }}-{{ endCard }})
{% endfor %}
{% endif %} {% endif %} {# ==================================================================== FORMULAIRE PRINCIPAL ==================================================================== #} {{ form_start(form, {'attr': {'class': 'wizard-form', 'id': 'wizardForm', 'novalidate': 'novalidate'}}) }} {# Flash messages (erreurs de validation serveur) #} {% for type, messages in app.flashes %} {% for message in messages %}
{{ type == 'error' ? '⚠️' : '✅' }} {{ message }}
{% endfor %} {% endfor %} {# Boucle sur chaque bénéficiaire #} {% for index, beneficiaireForm in form.beneficiaires %}
{# Barre de progression des étapes #}
1
Identité
2
Entreprise
3
Coordonnées
4
Services
5
Réseaux
{% if isPremium %}
6
Premium
{% endif %}
{# Carte du formulaire #}
{{ loop.index }}

Bénéficiaire {{ loop.index }} sur {{ totalCards }}

Renseignez les informations pour cette carte de visite

{# Bouton copier infos entreprise (à partir du 2ème bénéficiaire) #} {% if not loop.first %} {% endif %} {# ================================================================ ÉTAPE 1 : IDENTITÉ ================================================================ #}
👤Informations personnelles
{{ form_label(beneficiaireForm.prenom, null, {'label_attr': {'class': 'required'}}) }} {{ form_widget(beneficiaireForm.prenom, {'attr': {'class': 'form-input'}}) }} {{ form_errors(beneficiaireForm.prenom) }}
{{ form_label(beneficiaireForm.nom, null, {'label_attr': {'class': 'required'}}) }} {{ form_widget(beneficiaireForm.nom, {'attr': {'class': 'form-input'}}) }} {{ form_errors(beneficiaireForm.nom) }}
{{ form_label(beneficiaireForm.fonction) }} {{ form_widget(beneficiaireForm.fonction, {'attr': {'class': 'form-input'}}) }} {{ form_errors(beneficiaireForm.fonction) }}
{# Avatar : gestion selon le pack #} {% if packType == 'forcevente' %} {# Force de Vente : choix initiales/photo #}
{{ form_widget(beneficiaireForm.avatarType) }}
{{ form_label(beneficiaireForm.initiales) }} {{ form_widget(beneficiaireForm.initiales, {'attr': {'class': 'form-input', 'style': 'max-width: 150px;'}}) }}
Entrez 2-3 lettres (ex: JD pour Jean Dupont)
{{ form_label(beneficiaireForm.photoFile) }} {{ form_widget(beneficiaireForm.photoFile, {'attr': {'class': 'form-input'}}) }}
JPG, PNG, GIF, WebP - Max 5 Mo
{% elseif packType == 'essentiel' %} {# Essentiel : PAS d'avatar, juste un champ caché #} {% else %} {# Premium, Multi : initiales uniquement #}
{{ form_label(beneficiaireForm.initiales) }} {{ form_widget(beneficiaireForm.initiales, {'attr': {'class': 'form-input', 'style': 'max-width: 150px;'}}) }}
Entrez 2-3 lettres pour votre avatar (ex: JD pour Jean Dupont)
{% endif %}
{# ================================================================ ÉTAPE 2 : ENTREPRISE & CHARTE GRAPHIQUE ================================================================ #}
🏢Entreprise & Charte
{{ form_label(beneficiaireForm.entreprise) }} {{ form_widget(beneficiaireForm.entreprise, {'attr': {'class': 'form-input'}}) }} {{ form_errors(beneficiaireForm.entreprise) }}
{% if packType != 'essentiel' %}
{{ form_label(beneficiaireForm.slogan) }} {{ form_widget(beneficiaireForm.slogan, {'attr': {'class': 'form-input'}}) }}
{% endif %}
{{ form_label(beneficiaireForm.siteWeb) }} {{ form_widget(beneficiaireForm.siteWeb, {'attr': {'class': 'form-input'}}) }}
{# ✅ FIX DEFINITIF : marquer les champs comme rendus sans les afficher #} {# Ceci empêche form_rest() de les re-soumettre avec des valeurs vides #} {% set _d1 = form_widget(beneficiaireForm.charteType) %} {% set _d2 = form_widget(beneficiaireForm.couleurPrincipale) %} {% set _d3 = form_widget(beneficiaireForm.couleurSecondaire) %}
{# ============================================================ SÉLECTEUR DE CHARTE GRAPHIQUE AVEC MOCKUP ============================================================ #}
{# Champ caché pour stocker la valeur — lu par _charte_js.html.twig via id charteTemplate-N #}
{{ form_widget(beneficiaireForm.charteTemplate, {'attr': {'id': 'charteTemplate-' ~ loop.index}}) }}
{% set _defaultCharte = (packType == 'forcevente') ? 55 : (packType == 'essentiel' ? 2 : 53) %} {% include 'components/_charte_mockup.html.twig' with { mockupId: loop.index, packType: packType, currentCharte: _defaultCharte, mockupNom: 'Prénom NOM', mockupInitiales: 'AB', mockupFonction: 'VOTRE FONCTION', mockupEntreprise: 'VOTRE ENTREPRISE', mockupSlogan: 'Votre slogan' } %}

📋 Charte personnalisée
Renseignez les informations ci-dessous pour que nous créions votre carte avec votre identité visuelle.

{{ form_label(beneficiaireForm.chartePdfFile, 'Document de charte graphique (optionnel)') }} {{ form_widget(beneficiaireForm.chartePdfFile, {'attr': {'class': 'form-input'}}) }}
Si vous avez un document PDF de charte graphique
{# Upload du logo (toutes les cartes) #}
{{ form_label(beneficiaireForm.logo, '🏢 Logo de l\'entreprise') }} {{ form_widget(beneficiaireForm.logo, {'attr': {'class': 'form-input'}}) }}
PNG, JPG ou WebP - Max 5 Mo - Apparaîtra en haut de votre carte
{# ================================================================ ÉTAPE 3 : COORDONNÉES ================================================================ #}
📞Coordonnées
{{ form_label(beneficiaireForm.fixe) }} {{ form_widget(beneficiaireForm.fixe, {'attr': {'class': 'form-input'}}) }}
{{ form_label(beneficiaireForm.mobile) }} {{ form_widget(beneficiaireForm.mobile, {'attr': {'class': 'form-input'}}) }} {{ form_errors(beneficiaireForm.mobile) }}
{{ form_label(beneficiaireForm.email) }} {{ form_widget(beneficiaireForm.email, {'attr': {'class': 'form-input'}}) }} {{ form_errors(beneficiaireForm.email) }}
{{ form_label(beneficiaireForm.adresse) }} {{ form_widget(beneficiaireForm.adresse, {'attr': {'class': 'form-textarea'}}) }} {{ form_errors(beneficiaireForm.adresse) }}
📍 Adresse qui apparaîtra sur la carte de visite
{# ================================================================ ÉTAPE 4 : SERVICES ================================================================ #}
Services / Expertises

Ajoutez jusqu'à 4 services ou domaines d'expertise qui apparaîtront sur votre carte.

{{ form_label(beneficiaireForm.service1, 'Service 1') }} {{ form_widget(beneficiaireForm.service1, {'attr': {'class': 'form-input'}}) }}
{{ form_label(beneficiaireForm.service2, 'Service 2') }} {{ form_widget(beneficiaireForm.service2, {'attr': {'class': 'form-input'}}) }}
{{ form_label(beneficiaireForm.service3, 'Service 3') }} {{ form_widget(beneficiaireForm.service3, {'attr': {'class': 'form-input'}}) }}
{{ form_label(beneficiaireForm.service4, 'Service 4') }} {{ form_widget(beneficiaireForm.service4, {'attr': {'class': 'form-input'}}) }}
{# ================================================================ ÉTAPE 5 : RÉSEAUX SOCIAUX & VISIO ================================================================ #}
📱Réseaux sociaux & Visioconférence

Renseignez uniquement les réseaux que vous souhaitez afficher sur votre carte.

Réseaux sociaux

{{ form_label(beneficiaireForm.linkedin) }} {{ form_widget(beneficiaireForm.linkedin, {'attr': {'class': 'form-input'}}) }}
{{ form_label(beneficiaireForm.facebook) }} {{ form_widget(beneficiaireForm.facebook, {'attr': {'class': 'form-input'}}) }}
{{ form_label(beneficiaireForm.insta) }} {{ form_widget(beneficiaireForm.insta, {'attr': {'class': 'form-input'}}) }}
{{ form_label(beneficiaireForm.x) }} {{ form_widget(beneficiaireForm.x, {'attr': {'class': 'form-input'}}) }}
{{ form_label(beneficiaireForm.tiktok) }} {{ form_widget(beneficiaireForm.tiktok, {'attr': {'class': 'form-input'}}) }}
{{ form_label(beneficiaireForm.youtube) }} {{ form_widget(beneficiaireForm.youtube, {'attr': {'class': 'form-input'}}) }}
{{ form_label(beneficiaireForm.threads) }} {{ form_widget(beneficiaireForm.threads, {'attr': {'class': 'form-input'}}) }}

🎥 Visioconférence

{{ form_label(beneficiaireForm.zoom) }} {{ form_widget(beneficiaireForm.zoom, {'attr': {'class': 'form-input'}}) }}
{{ form_label(beneficiaireForm.googleMeet) }} {{ form_widget(beneficiaireForm.googleMeet, {'attr': {'class': 'form-input'}}) }}
{{ form_label(beneficiaireForm.microsoftTeams) }} {{ form_widget(beneficiaireForm.microsoftTeams, {'attr': {'class': 'form-input'}}) }}
{# ================================================================ ÉTAPE 6 : FONCTIONNALITÉS PREMIUM (si pack Premium+) ================================================================ #} {% if isPremium %}
🌟Fonctionnalités Premium

💡 Bonus Premium
Renseignez l'URL pour activer la fonctionnalité. Laissez vide pour la désactiver.

{{ form_label(beneficiaireForm.agendaLink, '📅 Prise de rendez-vous') }} {{ form_widget(beneficiaireForm.agendaLink, {'attr': {'class': 'form-input'}}) }}
Calendly, Cal.com, Google Calendar, etc.
{{ form_label(beneficiaireForm.galerieLink, '🖼️ Galerie / Portfolio') }} {{ form_widget(beneficiaireForm.galerieLink, {'attr': {'class': 'form-input'}}) }}
Behance, Instagram portfolio, etc.
{{ form_label(beneficiaireForm.satisfactionLink, '⭐ Avis clients') }} {{ form_widget(beneficiaireForm.satisfactionLink, {'attr': {'class': 'form-input'}}) }}
Google Reviews, Trustpilot, etc.
{{ form_label(beneficiaireForm.catalogueLink, '📋 Catalogue / Menu') }} {{ form_widget(beneficiaireForm.catalogueLink, {'attr': {'class': 'form-input'}}) }}
PDF en ligne, boutique, lien externe.
{{ form_label(beneficiaireForm.videoLink, '🎬 Vidéo de présentation') }} {{ form_widget(beneficiaireForm.videoLink, {'attr': {'class': 'form-input'}}) }}
YouTube, Vimeo, etc.
{{ form_label(beneficiaireForm.lienPersonnalise, '🔗 Lien personnalisé') }} {{ form_widget(beneficiaireForm.lienPersonnalise, {'attr': {'class': 'form-input'}}) }}
N'importe quel lien supplémentaire.
{# ================================================================ STATS FOOTER - UNIQUEMENT PACK PREMIUM ================================================================ #} {% if packType == 'premium' %}

📊 Statistiques Footer (affiché en bas de votre carte)

Ces informations apparaîtront dans le footer de votre carte Premium pour valoriser votre expertise.

{{ form_label(beneficiaireForm.expertise, '📅 Années d\'expertise') }} {{ form_widget(beneficiaireForm.expertise, {'attr': {'class': 'form-input', 'placeholder': 'Ex: 12 ans'}}) }}
Votre expérience professionnelle
{{ form_label(beneficiaireForm.seances, '📈 Projets / Séances') }} {{ form_widget(beneficiaireForm.seances, {'attr': {'class': 'form-input', 'placeholder': 'Ex: 500+'}}) }}
Nombre de projets réalisés
{{ form_label(beneficiaireForm.satisfaction, '⭐ Taux de satisfaction') }} {{ form_widget(beneficiaireForm.satisfaction, {'attr': {'class': 'form-input', 'placeholder': 'Ex: 100%'}}) }}
Satisfaction de vos clients
{% endif %}
{% endif %} {# ================================================================ NAVIGATION ENTRE ÉTAPES ================================================================ #}
{# Bouton final (visible uniquement sur la dernière étape du dernier bénéficiaire) #} {% if loop.last %} {% endif %}
{% endfor %} {# Champs cachés de la commande - packType, quantity, paiementMode, et champs client (optionnels) #}
{{ form_widget(form.packType) }} {{ form_widget(form.quantity) }} {{ form_widget(form.paiementMode) }} {{ form_rest(form) }}
{{ form_end(form) }}
{# Loader #}
{# ═══════════════════════════════════════════════════════════════════════ CHARTE JS FACTORISÉ — Source unique des 55 chartes + selectCharte() Fournit : chartes, chartOrder, currentChartes, selectCharte(), prevCharte(), nextCharte(), getBrightness(), initCharteMockup() ═══════════════════════════════════════════════════════════════════════ #} {% set _mockupIds = [] %} {% for i in 1..totalCards %} {% set _mockupIds = _mockupIds|merge([i]) %} {% endfor %} {% set _defaultCharteNum = (packType == 'forcevente') ? 55 : (packType == 'essentiel' ? 2 : 53) %} {% set _defaultChartes = {} %} {% for i in 1..totalCards %} {% set _defaultChartes = _defaultChartes|merge({(i): _defaultCharteNum}) %} {% endfor %} {% include 'components/_charte_js.html.twig' with { mockupIds: _mockupIds, packType: packType, defaultChartes: _defaultChartes } %} {% endblock %}