Commit_Formulaires

This commit is contained in:
2025-10-09 11:06:59 +02:00
commit eeadb71855
11 changed files with 9916 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,168 @@
(function() {
'use strict';
console.log('🔧 DataLayer universel chargé');
// Arrêter sur les pages de confirmation
if (window.location.href.includes('confirmation')) {
console.log('⏭️ Page de confirmation - script ignoré');
return;
}
// Attendre le formulaire avec plus de patience
function waitForForm(maxAttempts = 100) {
let attempts = 0;
const checkInterval = setInterval(function() {
attempts++;
const form = document.getElementById('oscar_school_form');
if (form) {
clearInterval(checkInterval);
console.log('✅ Formulaire trouvé après', attempts, 'tentatives');
initializeDataLayer(form);
} else if (attempts >= maxAttempts) {
clearInterval(checkInterval);
console.log('⏱️ Formulaire non trouvé après ' + (maxAttempts * 200 / 1000) + ' secondes');
}
}, 200);
}
function initializeDataLayer(form) {
console.log('📊 Initialisation tracking DataLayer');
// Fonction SHA-256
async function sha256(value) {
if (!value) return '';
try {
const encoder = new TextEncoder();
const data = encoder.encode(value.trim().toLowerCase());
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
} catch (error) {
console.error('❌ Erreur hashage:', error);
return '';
}
}
// Récupérer texte d'un select
function getSelectText(selectId) {
const select = document.getElementById(selectId);
if (select && select.selectedIndex >= 0 && select.options[select.selectedIndex]) {
return select.options[select.selectedIndex].text;
}
return '';
}
// Fonction principale de capture
async function captureAndPushDataLayer() {
console.log('📝 Capture des données formulaire');
// Vérifier consentement CNIL
const consentCheckbox = document.querySelector('input[name="cnil"]');
if (!consentCheckbox || !consentCheckbox.checked) {
console.warn('⚠️ Pas de consentement CNIL - dataLayer non envoyé');
return;
}
// Récupération des champs (compatible tous formulaires)
const typeRaw = (document.querySelector('input[name="type_formulaire"]') || {}).value || '';
const emailRaw = (document.getElementById('email') || {}).value || '';
const portableRaw = (document.getElementById('portable') || {}).value || '';
const villeRaw = (document.getElementById('ville') || {}).value || '';
const codePostalRaw = (document.getElementById('codepostal') || document.getElementById('code_postal') || {}).value || '';
const campusRaw = (document.getElementById('campus_selection') || {}).value || '';
// Selects (texte, pas value)
const statusRaw = getSelectText('OscarContactJeSuisRefIdField');
const formationRaw = getSelectText('formation');
// Pays
const paysSelect = document.getElementById('pays');
let paysNom = '';
if (paysSelect && paysSelect.selectedIndex > 0) {
paysNom = paysSelect.options[paysSelect.selectedIndex].text;
}
console.log('📦 Données:', {
type: typeRaw,
status: statusRaw,
campus: campusRaw,
formation: formationRaw,
hasEmail: !!emailRaw,
hasPhone: !!portableRaw
});
// Hashage
const emailHash = await sha256(emailRaw);
const portableHash = await sha256(portableRaw);
const codePostalHash = await sha256(codePostalRaw);
// Construction dataLayer
const dataLayerObject = {
event: 'form_submit',
type: typeRaw.trim().toLowerCase(),
je_suis: statusRaw.trim(),
sha256_email_address: emailHash,
sha256_phone_number: portableHash,
sha256_postal_code: codePostalHash,
ville: villeRaw.trim(),
pays: paysNom,
campus: campusRaw.trim(),
formation: formationRaw.trim()
};
// Push dataLayer
window.dataLayer = window.dataLayer || [];
window.dataLayer.push(dataLayerObject);
console.log('🚀 DataLayer push réussi:', dataLayerObject);
}
// Attacher aux événements submit du FORMULAIRE
form.addEventListener('submit', async function(event) {
console.log('📝 Event: form submit');
await captureAndPushDataLayer();
});
// Attacher AUSSI aux boutons (pour formulaire contact)
const desktopBtn = document.getElementById('desktop-submit-btn');
const mobileBtn = document.getElementById('mobile-submit-btn');
if (desktopBtn) {
desktopBtn.addEventListener('click', async function(e) {
console.log('📝 Event: desktop button click');
await captureAndPushDataLayer();
});
}
if (mobileBtn) {
mobileBtn.addEventListener('click', async function(e) {
console.log('📝 Event: mobile button click');
await captureAndPushDataLayer();
});
}
// Boutons submit classiques (JPO, candidature)
const submitButtons = form.querySelectorAll('button[type="submit"]');
submitButtons.forEach(btn => {
btn.addEventListener('click', async function(e) {
console.log('📝 Event: submit button click');
// Ne pas empêcher l'événement, juste capturer
await captureAndPushDataLayer();
});
});
console.log('✅ Tracking activé sur tous les événements');
}
// Démarrage
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
waitForForm();
});
} else {
waitForForm();
}
})();

View File

@@ -0,0 +1,896 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Formulaire de contact Oscar School</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="oscar_school_form_container">
<div id="oscar_school_form_body">
<form id="oscar_school_form" method="POST" action="https://v3.oscar-campus.com/groupe_ensup/forms" ref="schoolForm">
<input type="hidden" name="type_formulaire" value="contact">
<div class="form-sections-wrapper">
<div id="section1" class="form-section form-section-step active ">
<div class="form-intro-message">
<h2><i class="fas fa-info-circle"></i> Une question sur nos formations, l'admission, le campus ou l'alternance ?</h2>
<p style="text-align: center;">Veuillez compléter ce formulaire, notre équipe vous recontactera rapidement.</p>
</div>
<div style="margin-bottom: 5px;"></div>
<div class="form-group ">
<div class="form-group-item">
<label for="je_suis_ref_id">Je suis<span class="oscar_input_required">(*)</span>:</label>
<select
id="OscarContactJeSuisRefIdField"
class="form-control"
name="je_suis_ref_id"
v-on:change="determineRelatedFieldsOptions"
v-on:focus="displayAvailableOptions"
>
<option value="">Choisir</option>
<option value="434">Lycéen(ne)</option>
<option value="435">Étudiant(e)</option>
<option value="436">En poste / reconversion</option>
<option value="437">Étudiant avec un diplôme étranger</option>
<option value="439">Parent de l&#039;étudiant(e)</option>
</select>
</div>
</div>
<div class="form-group">
<div class="form-group-item">
<label for="nom">Nom<span class="oscar_input_required">(*)</span></label>
<input type="text" id="nom" name="nom" class="form-control" required pattern="^[A-Za-zÀ-ÿ' \-]{2,50}$" maxlength="50"
title="Le nom doit contenir uniquement des lettres (pas de chiffres ou symboles)">
</div>
<div class="form-group-item">
<label for="prenom">Prénom<span class="oscar_input_required">(*)</span></label>
<input type="text" id="prenom" name="prenom" class="form-control" required pattern="^[A-Za-zÀ-ÿ' \-]{2,50}$" maxlength="50"
title="Le prénom doit contenir uniquement des lettres (pas de chiffres ou symboles)">
</div>
</div>
<div class="form-group">
<div class="form-group-item">
<label for="email">Email<span class="oscar_input_required">(*)</span></label>
<input type="email" id="email" name="email" class="form-control" required title="Veuillez saisir une adresse email valide.">
</div>
<div class="form-group-item">
<label for="portable">Portable<span class="oscar_input_required">(*)</span></label>
<input type="tel" id="portable" name="portable" class="form-control" required>
</div>
</div>
<div class="form-group" id="campus_selection_app_Brochure">
<div class="form-group-item">
<label for="campus_selection_Brochure">Campus souhaité<span class="oscar_input_required">(*)</span></label>
<select id="campus_selection" name="campus" class="form-control" v-model="selectedCampus" required>
<option value="">Choisir un campus</option>
<option value="sqy">Saint-Quentin-en-Yvelines</option>
<option value="cgy">Cergy</option>
<option value="nantes">Nantes</option>
<option value="marseille">Marseille</option>
</select>
</div>
</div>
<div class="form-group">
<div class="form-group-item full-width">
<label for="remarque">Objet de la demande:</label>
<textarea id="remarque" name="remarque" class="form-control" rows="4"></textarea>
</div>
</div>
<div class="form-group cnil-consent-group">
<div class="cnil-checkbox-wrapper">
<input type="checkbox" id="cnil_oui" name="cnil" class="custom-control-input" value="1" required>
<label for="cnil_oui" class="cnil-info-label custom-control-label">
<strong>Oui, je donne mon approbation pour le traitement de mes données personnelles à ENSITECH.</strong><br>
<span style="color: grey; font-size: small;">En soumettant ce formulaire, j'accepte que mes informations soient utilisées dans le cadre de ma demande et de la relation commerciale éthique et personnalisée qui pourrait en découler si je le souhaite. <span class="oscar_input_required">(*)</span></span>
</label>
</div>
</div>
<button type="submit" id="desktop-submit-btn" class="btn-primary desktop-submit-button">
<span class="btn-text">ENVOYER</span>
<span class="btn-loading" style="display: none;">⏳ Envoi en cours...</span>
</button>
</div>
</div>
<div id="final-mobile-navigation">
<button type="submit" id="mobile-submit-btn" class="btn-primary mobile-submit-button">
<span class="btn-text">ENVOYER</span>
<span class="btn-loading" style="display: none;">⏳ Envoi en cours...</span>
</button>
</div>
<div class="mandatory-fields-note-global">(*) Champs obligatoires</div>
<input type="hidden" id="hidden_token_field" name="token">
<input type="hidden" id="hidden_formID_field" name="formID">
<input type="hidden" name="utm_campaign" value="">
<input type="hidden" name="utm_source" value="">
<input type="hidden" name="utm_medium" value="">
<input type="hidden" name="utm_term" value="">
<input type="hidden" name="utm_content" value="">
<div class="username_field" style="display: none;">
<label for="username">Type your username</label>
<input type="text" id="username" name="username" value="">
</div>
</form>
</div>
</div>
<style>
.form-description {
text-align: center;
margin-bottom: 25px;
padding: 0 15px;
}
input:valid {
border: 1px solid green;
}
body {
margin: 0;
padding: 0;
background-color: #f0f2f5;
font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: #333;
}
#oscar_school_form_container {
max-width: 1200px;
margin: 20px auto;
padding: 0 15px;
}
#oscar_school_form_body {
position: relative;
background: linear-gradient(to bottom right, #f8f9fa, #e9ecef);
padding: 25px;
border-radius: 12px;
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
#oscar_school_form_header h1 {
color: #198AB4;
text-align: center;
margin-bottom: 20px;
font-size: 2.5em;
text-shadow: 1px 1px 2px rgba(0,0,0,0.05);
}
#oscar_school_form_header p {
text-align: center;
color: #555;
font-size: 1.15em;
margin-bottom: 35px;
}
.form-sections-wrapper {
margin-bottom: 25px;
}
.form-section {
padding: 20px;
border: 1px solid #e0e0e0;
border-radius: 10px;
background-color: #ffffff;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
height: auto;
margin-bottom: 20px;
display: flex;
flex-direction: column;
}
.form-section:hover {
transform: translateY(-5px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
}
.form-section h2 {
margin-top: 0;
color: #0087CF;
font-size: 1.5em;
border-bottom: 2px solid #0087CF;
padding-bottom: 12px;
margin-bottom: 22px;
text-align: center;
}
.form-section h2 i {
margin-right: 8px;
color: #0087CF;
}
.form-group {
margin-bottom: 8px;
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.form-group-item {
flex: 1 1 calc(50% - 10px);
max-width: calc(50% - 10px);
}
.form-group > .form-group-item:only-child,
.form-group:not(.cnil-consent-group) > label + .form-control {
flex: 1 1 100%;
max-width: 100%;
}
.form-group label {
display: block;
margin-bottom: 6px;
color: #444;
font-size: 0.98em;
font-weight: 500;
}
.cnil-info-label {
color: #6c757d;
font-size: 0.85em;
margin-top: 8px;
font-weight: normal;
}
.cnil-checkbox-wrapper {
display: flex;
align-items: flex-start;
gap: 8px;
width: 100%;
}
.form-control {
width: 100%;
padding: 8px 12px;
border: 1px solid #ced4da;
border-radius: 6px;
font-size: 1em;
color: #495057;
transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
box-sizing: border-box;
min-height: 38px;
}
.form-control:focus {
border-color: #80bdff;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.form-control.is-invalid {
border-color: #dc3545;
padding-right: calc(1.5em + 0.75rem);
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right calc(0.375em + 0.1875rem) center;
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}
.form-control.is-invalid:focus {
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}
textarea.form-control {
resize: vertical;
min-height: 90px;
}
.oscar_input_required {
color: #DD1B51;
font-weight: bold;
}
.custom-control-input {
width: 20px;
height: 20px;
border: 1px solid #ced4da;
border-radius: 4px;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
cursor: pointer;
flex-shrink: 0;
margin-top: 2px;
}
.custom-control-input:checked {
background-color: #198AB4;
border-color: #198AB4;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M4 8.5L6.5 11 12 5'/%3e%3csvg%3e");
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
}
.custom-control-input:focus {
outline: none;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.custom-control-label {
cursor: pointer;
color: #333;
flex-grow: 1;
}
.cnil-consent-group {
padding: 10px 0;
margin-bottom: 20px;
}
.btn-primary {
display: block;
width: 100%;
padding: 15px 25px;
margin-top: 30px;
font-size: 1.25em;
font-weight: bold;
color: #fff;
background-color: #198AB4;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease, box-shadow 0.2s ease;
box-shadow: 0 5px 15px rgba(0, 123, 255, 0.25);
}
.btn-primary:hover {
background-color: #0056b3;
transform: translateY(-3px);
box-shadow: 0 7px 20px rgba(0, 123, 255, 0.35);
}
.btn-primary:disabled {
background-color: #b0d8ff;
cursor: not-allowed;
opacity: 0.7;
transform: none;
box-shadow: none;
}
.btn-loading {
display: none;
}
.btn-primary.sending .btn-text {
display: none;
}
.btn-primary.sending .btn-loading {
display: inline-block;
}
.form-section-step {
width: 100%;
display: none;
}
.form-navigation {
display: none;
justify-content: center;
gap: 15px;
margin-top: 25px;
}
.form-navigation .btn-next,
.form-navigation .btn-prev {
flex: 1;
max-width: 160px;
padding: 14px 0;
font-size: 1.15em;
font-weight: bold;
cursor: pointer;
border-radius: 8px;
border: none;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transition: background-color 0.3s ease, transform 0.2s ease;
}
.form-navigation .btn-prev {
background-color: #DD1B3D;
color: #fff;
}
.form-navigation .btn-prev:hover {
background-color: #c71534;
transform: translateY(-2px);
}
.form-navigation .btn-next {
background-color: #198AB4;
color: #fff;
}
.form-navigation .btn-next:hover {
background-color: #147395;
transform: translateY(-2px);
}
.mandatory-fields-note-global {
font-size: 0.85em;
color: #555;
text-align: right;
margin-top: 15px;
padding-right: 15px;
}
@media (min-width: 769px) {
#oscar_school_form_container {
padding: 0 20px;
}
.form-sections-wrapper {
display: flex;
flex-wrap: nowrap;
justify-content: center;
gap: 30px;
align-items: stretch;
margin-bottom: 0;
}
.form-section-step {
flex: 1;
min-width: 0;
max-width: 50%;
display: flex !important;
margin-bottom: 0;
}
.form-section {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
padding-bottom: 20px;
}
.form-navigation,
.section-navigation-mobile,
#final-mobile-navigation,
.mobile-submit-button {
display: none !important;
}
.desktop-submit-button {
display: block !important;
width: 100%;
margin-top: auto;
align-self: center;
padding: 15px 25px;
font-size: 1.25em;
box-shadow: 0 5px 15px rgba(0, 123, 255, 0.25);
}
.form-group {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.form-group-item {
flex: 1 1 calc(50% - 10px);
max-width: calc(50% - 10px);
}
#section1 .form-group:first-of-type .form-group-item {
flex: 1 1 100%;
max-width: 100%;
}
.mandatory-fields-note-global {
position: absolute;
bottom: 20px;
left: 25px;
right: auto;
font-size: 0.9em;
color: #777;
text-align: left;
padding-right: 0;
}
}
@media (max-width: 768px) {
#oscar_school_form_container {
width: 100%;
padding: 0 15px;
margin-top: 15px;
}
#oscar_school_form_body {
padding: 20px;
}
.form-sections-wrapper {
flex-direction: column;
gap: 15px;
margin-bottom: 0;
}
.form-section {
min-width: unset;
padding: 18px;
margin-bottom: 20px;
height: auto;
align-items: flex-start;
}
.form-section-step.active {
display: flex;
flex-direction: column;
}
.form-group {
margin-bottom: 12px;
flex-direction: column;
gap: 0;
width: 100%;
max-width: 400px;
margin-left: 0;
margin-right: auto;
}
.form-group-item {
flex: 1 1 100%;
max-width: 100%;
margin-bottom: 10px;
display: flex;
flex-direction: row;
align-items: center;
gap: 10px;
}
.form-group-item:last-child {
margin-bottom: 0;
}
.form-group-item label {
display: inline-block;
flex-shrink: 0;
width: 90px;
text-align: left;
margin-bottom: 0;
}
.form-group-item .form-control {
flex-grow: 1;
width: auto;
max-width: calc(100% - 100px);
}
#section1 .form-group {
flex-direction: column;
flex-wrap: nowrap;
gap: 0;
}
#section1 .form-group-item {
flex: 1 1 100%;
max-width: 100%;
margin-bottom: 10px;
}
#section1 .form-group:first-of-type .form-group-item {
flex: 1 1 100%;
max-width: 100%;
justify-content: flex-start;
}
#section1 .form-group:first-of-type .form-group-item label {
width: 90px;
text-align: left;
}
#section1 .form-group:first-of-type .form-group-item .form-control {
max-width: calc(100% - 100px);
}
.cnil-consent-group {
max-width: 400px;
margin-left: auto;
margin-right: auto;
flex-direction: column;
align-items: flex-start;
}
.desktop-submit-button {
display: none !important;
}
#final-mobile-navigation {
display: block !important;
margin-top: 20px;
padding: 0 15px;
text-align: center;
}
.mobile-submit-button {
display: block !important;
margin: 0 auto;
max-width: 400px;
width: 100%;
}
.mandatory-fields-note-global {
position: static;
text-align: center;
margin-top: 20px;
padding-right: 0;
}
}
@media (max-width: 414px) {
.form-group-item label {
width: 70px;
}
.form-group-item .form-control {
max-width: calc(100% - 80px);
}
#section1 .form-group:first-of-type .form-group-item label {
width: 70px;
}
#section1 .form-group:first-of-type .form-group-item .form-control {
max-width: calc(100% - 80px);
}
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function () {
const campusSelect = document.getElementById('campus_selection');
const currentUrl = window.location.href;
let isSubmitting = false;
const campusConfirmationPaths = {
sqy: "confirmation-demande-de-contact/",
cgy: "confirmation-demande-de-contact/",
nantes: "confirmation-demande-de-contact/",
marseille: "confirmation-demande-de-contact/"
};
const vueInstance = new Vue({
el: "#campus_selection",
data: {
selectedCampus: campusSelect ? campusSelect.value : "",
campusTokens: {
sqy: "4dI7t38zd5Z1RXOT0VdcB",
cgy: "jqF8XULo9yumNQgCag2eW",
nantes: "fF5p5HvCpBkKvvPvpS0zH",
marseille: "nPS8hijHWAx4Uos3zBqNu"
},
campusFormIDs: {
sqy: "271",
cgy: "269",
nantes: "261",
marseille: "268"
},
campusConfirmationPaths
},
watch: {
selectedCampus() {
this.updateHiddenFields();
}
},
mounted() {
if (campusSelect) {
const urlToCampusValueMap = {
'saint-quentin-en-yvelines': 'sqy',
'campus-cgy': 'cgy',
'campus-nantes': 'nantes',
'campus-marseille': 'marseille'
};
for (const urlPart in urlToCampusValueMap) {
if (currentUrl.includes(urlPart)) {
campusSelect.value = urlToCampusValueMap[urlPart];
this.selectedCampus = urlToCampusValueMap[urlPart];
break;
}
}
this.selectedCampus = campusSelect.value;
this.updateHiddenFields();
campusSelect.addEventListener("change", (e) => {
this.selectedCampus = e.target.value;
});
}
},
methods: {
updateHiddenFields() {
const tokenField = document.getElementById("hidden_token_field");
const formIDField = document.getElementById("hidden_formID_field");
if (tokenField) tokenField.value = this.campusTokens[this.selectedCampus] || "";
if (formIDField) formIDField.value = this.campusFormIDs[this.selectedCampus] || "";
},
async submitForm() {
if (isSubmitting) {
console.log("Soumission déjà en cours, ignorée");
return;
}
isSubmitting = true;
const form = document.getElementById("oscar_school_form");
const campusSelect = document.getElementById('campus_selection');
if (!campusSelect || !campusSelect.value) {
alert("Veuillez sélectionner un campus");
isSubmitting = false;
return;
}
this.setLoadingState(true);
try {
const formData = new FormData(form);
const selectedCampusValue = campusSelect.value;
console.log("Campus sélectionné:", selectedCampusValue);
let path = this.campusConfirmationPaths[selectedCampusValue];
if (!path) {
console.error("Pas de chemin de confirmation pour le campus:", selectedCampusValue);
path = "confirmation-demande-de-contact/";
}
const baseUrl = "https://ensitech.eu/";
const redirectUrl = baseUrl + path;
console.log("Redirection prévue vers:", redirectUrl);
const response = await axios.post(form.action, formData);
console.log("Formulaire envoyé avec succès");
window.location.href = redirectUrl;
} catch (error) {
console.error("Erreur lors de l'envoi:", error);
alert("Erreur lors de l'envoi du formulaire. Veuillez réessayer.");
isSubmitting = false;
this.setLoadingState(false);
}
},
setLoadingState(loading) {
const desktopBtn = document.getElementById("desktop-submit-btn");
const mobileBtn = document.getElementById("mobile-submit-btn");
[desktopBtn, mobileBtn].forEach(btn => {
if (btn) {
if (loading) {
btn.classList.add('sending');
btn.disabled = true;
} else {
btn.classList.remove('sending');
btn.disabled = false;
}
}
});
}
}
});
function validateForm() {
const formSection = document.getElementById('section1');
const requiredInputs = formSection.querySelectorAll('input[required], select[required], textarea[required]');
let allValid = true;
requiredInputs.forEach(input => {
input.classList.remove('is-invalid');
let isValid = true;
const value = input.value.trim();
if (input.type === 'email') {
isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
} else if (['nom', 'prenom'].includes(input.name)) {
isValid = /^[A-Za-zÀ-ÿ' \-]{2,50}$/.test(value);
} else if (input.name === 'portable') {
isValid = /^(?:(?:\+|00)33|0)\s*[1-9](?:[\s.-]*\d{2}){4}$/.test(value);
} else if (input.type === 'checkbox' || input.type === 'radio') {
if (input.type === 'radio') {
const groupChecked = formSection.querySelectorAll(`input[name="${input.name}"]:checked`);
isValid = groupChecked.length > 0;
} else {
isValid = input.checked;
}
} else {
isValid = value.length > 0;
}
if (!isValid) {
input.classList.add('is-invalid');
allValid = false;
}
});
return allValid;
}
const cnilCheckbox = document.getElementById('cnil_oui');
const desktopBtn = document.getElementById('desktop-submit-btn');
const mobileBtn = document.getElementById('mobile-submit-btn');
function toggleSubmitButtonState() {
const accepted = cnilCheckbox && cnilCheckbox.checked;
if (desktopBtn) desktopBtn.disabled = !accepted;
if (mobileBtn) mobileBtn.disabled = !accepted;
}
toggleSubmitButtonState();
if (cnilCheckbox) {
cnilCheckbox.addEventListener("change", toggleSubmitButtonState);
}
function handleFormSubmit(e) {
e.preventDefault();
e.stopPropagation();
console.log("Tentative de soumission...");
if (isSubmitting) {
console.log("Soumission déjà en cours");
return false;
}
if (!validateForm()) {
const accepted = cnilCheckbox && cnilCheckbox.checked;
alert(accepted
? "Veuillez remplir tous les champs obligatoires."
: "Veuillez accepter les conditions CNIL pour envoyer le formulaire.");
return false;
}
if (vueInstance && typeof vueInstance.submitForm === 'function') {
vueInstance.submitForm();
}
return false;
}
if (desktopBtn) {
desktopBtn.addEventListener('click', handleFormSubmit);
}
if (mobileBtn) {
mobileBtn.addEventListener('click', handleFormSubmit);
}
const form = document.getElementById('oscar_school_form');
if (form) {
form.addEventListener('submit', function(e) {
e.preventDefault();
e.stopPropagation();
console.log("Soumission native bloquée");
return false;
});
}
});
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,883 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
<link rel="stylesheet" href="style.css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="oscar_school_form_container">
<div id="oscar_school_form_body">
<form id="oscar_school_form" method="POST" action="https://v3.oscar-campus.com/groupe_ensup/forms" ref="schoolForm">
<input type="hidden" name="type_formulaire" value="Brochure">
<div class="form-sections-wrapper">
<div id="section1" class="form-section form-section-step active ">
<h2><i class="fas fa-book"></i> Demande de brochure</h2>
<p class="form-description">Remplissez ce formulaire pour accéder à notre brochure.</p>
<div class="form-group ">
<div class="form-group-item">
<label for="je_suis_ref_id">Je suis<span class="oscar_input_required">(*)</span>:</label>
</label>
<select
id="OscarContactJeSuisRefIdField"
class="form-control"
name="je_suis_ref_id"
v-on:change="determineRelatedFieldsOptions"
v-on:focus="displayAvailableOptions"
>
<option value="">Choisir</option>
<option value="434">Lycéen(ne)</option>
<option value="435">Étudiant(e)</option>
<option value="436">En poste / reconversion</option>
<option value="437">Étudiant avec un diplôme étranger</option>
<option value="439">Parent de l&#039;étudiant(e)</option>
</select>
</div>
</div>
<div class="form-group">
<div class="form-group-item">
<label for="nom">Nom<span class="oscar_input_required">(*)</span></label>
<input type="text" id="nom" name="nom" class="form-control" required pattern="^[A-Za-zÀ-ÿ' \-]{2,50}$" maxlength="50"
title="Le nom doit contenir uniquement des lettres (pas de chiffres ou symboles)">
</div>
<div class="form-group-item">
<label for="prenom">Prénom<span class="oscar_input_required">(*)</span></label>
<input type="text" id="prenom" name="prenom" class="form-control" required pattern="^[A-Za-zÀ-ÿ' \-]{2,50}$" maxlength="50"
title="Le prénom doit contenir uniquement des lettres (pas de chiffres ou symboles)">
</div>
</div>
<div class="form-group">
<div class="form-group-item">
<label for="email">Email<span class="oscar_input_required">(*)</span></label>
<input type="email" id="email" name="email" class="form-control" required title="Veuillez saisir une adresse email valide.">
</div>
<div class="form-group-item">
<label for="portable">Portable<span class="oscar_input_required">(*)</span></label>
<input type="tel" id="portable" name="portable" class="form-control" required>
</div>
</div>
<div class="form-group" id= "campus_selection_app_Brochure">
<div class="form-group-item">
<label for="campus_selection_Brochure">Campus souhaité<span class="oscar_input_required">(*)</span></label>
<select id="campus_selection" name="campus" class="form-control" v-model="selectedCampus" required>
<option value="">Choisir un campus</option>
<option value="sqy">Saint-Quentin-en-Yvelines</option>
<option value="cgy">Cergy</option>
<option value="nantes">Nantes</option>
<option value="marseille">Marseille</option>
</select>
</div>
<div class="form-group-item">
<label for="formation">Formation souhaitée<span class="oscar_input_required">(*)</span></label>
<select id="formation" name="formation_souhaitee_formation_id" class="form-control" required>
<option value="">Choisir une formation</option>
<option value="367">BTS SIO SLAM</option>
<option value="369">BTS SIO SISR</option>
<option value="371">BTS CIEL</option>
<option value="373">Bachelor TECH &amp; DEV spé Gestion de projet IA &amp; Data</option>
<option value="374">Bachelor TECH &amp; DEV spé Développeur Full Stack</option>
<option value="376">Bachelor Systèmes &amp; Réseaux spé Infra &amp; Sécurité</option>
<option value="377">Bachelor Systèmes &amp; Réseaux spé cybersécurité</option>
<option value="378">M1/M2 Expert Solutions Data</option>
<option value="379">M1/M2 Expert Solutions IA &amp; IOT</option>
<option value="380">M1/M2 Lead Developer Full Stack</option>
<option value="382">M1/M2 Expert Architectures IA &amp; IOT</option>
<option value="383">M1/M2 Expert Réseaux &amp; Sécurité</option>
<option value="384">M1/M2 Expert Cybersécurité &amp; Cloud Computing</option>
</select>
</div>
</div>
<div class="form-group cnil-consent-group">
<div class="cnil-checkbox-wrapper">
<input type="checkbox" id="cnil_oui" name="cnil" class="custom-control-input" value="1" required>
<label for="cnil_oui" class="cnil-info-label custom-control-label">
<strong>Oui, je donne mon approbation pour le traitement de mes données personnelles à ENSITECH.</strong><br>
<span style="color: grey; font-size: small;">En soumettant ce formulaire, jaccepte que mes informations soient utilisées dans le cadre de ma demande et de la relation commerciale éthique et personnalisée qui pourrait en découler si je le souhaite. <span class="oscar_input_required">(*)</span></span>
</label>
</div>
</div>
<button type="submit" class="btn-primary desktop-submit-button">DEMANDER LA BROCHURE </button>
</div>
</div>
<div id="final-mobile-navigation">
<button type="submit" class="btn-primary mobile-submit-button">DEMANDER LA BROCHURE</button>
</div>
<div class="mandatory-fields-note-global">(*) Champs obligatoires</div>
<input type="hidden" id="hidden_token_field" name="token">
<input type="hidden" id="hidden_formID_field" name="formID">
<input type="hidden" name="utm_campaign" value="">
<input type="hidden" name="utm_source" value="">
<input type="hidden" name="utm_medium" value="">
<input type="hidden" name="utm_term" value="">
<input type="hidden" name="utm_content" value="">
<div class="username_field" style="display: none;">
<label for="username">Type your username</label>
<input type="text" id="username" name="username" value="">
</div>
</form>
</div>
</div>
</body>
</html>
<style>
.form-description {
text-align: center;
margin-bottom: 25px; /* Space between description and form */
padding: 0 15px; /* Add some horizontal padding to prevent text from touching edges on small screens */
}
input:valid {
border: 1px solid green;
}
body {
margin: 0;
padding: 0;
background-color: #f0f2f5;
font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: #333;
}
/* --- Main Form Container --- */
#oscar_school_form_container {
max-width: 1200px;
margin: 20px auto;
padding: 0 15px;
}
/* --- Form Body Styles (The white/light gray box) --- */
#oscar_school_form_body {
position: relative;
background: linear-gradient(to bottom right, #f8f9fa, #e9ecef);
padding: 25px;
border-radius: 12px;
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
/* Optional: Form Header Styles if you uncomment them in HTML */
#oscar_school_form_header h1 {
color: #198AB4;
text-align: center;
margin-bottom: 20px;
font-size: 2.5em;
text-shadow: 1px 1px 2px rgba(0,0,0,0.05);
}
#oscar_school_form_header p {
text-align: center;
color: #555;
font-size: 1.15em;
margin-bottom: 35px;
}
/* --- Form Sections Wrapper (Desktop Flex / Mobile Stack) --- */
.form-sections-wrapper {
margin-bottom: 25px; /* Provides space if no final nav/note below */
}
/* --- Individual Form Section Styles (e.g., Identité, Projet de formation) --- */
.form-section {
padding: 20px;
border: 1px solid #e0e0e0;
border-radius: 10px;
background-color: #ffffff;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
height: auto;
margin-bottom: 20px; /* Space between stacked sections on mobile */
display: flex; /* Makes the section a flex container for its internal content */
flex-direction: column; /* Stacks its direct children vertically */
}
.form-section:hover {
transform: translateY(-5px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
}
.form-section h2 {
margin-top: 0;
color: #198AB4;
font-size: 1.7em;
border-bottom: 2px solid #198AB4;
padding-bottom: 12px;
margin-bottom: 22px;
text-align: center;
}
.form-section h2 i {
margin-right: 8px;
color: #198AB4;
}
/* --- Form Group & Control Styles --- */
.form-group {
margin-bottom: 8px;
display: flex; /* Makes immediate children flex items */
flex-wrap: wrap; /* Allows items to wrap to the next line */
gap: 20px; /* Space between flex items */
}
/* Default for individual items in a flex form-group */
.form-group-item {
flex: 1 1 calc(50% - 10px); /* Tries to take 50% width minus half the gap */
max-width: calc(50% - 10px);
}
/* For form-groups that should always be full width (e.g., "Je suis" select, or single input lines) */
/* This rule is more for desktop, on mobile we manage this differently */
.form-group > .form-group-item:only-child,
.form-group:not(.cnil-consent-group) > label + .form-control {
flex: 1 1 100%;
max-width: 100%;
}
.form-group label {
display: block;
margin-bottom: 6px;
color: #444;
font-size: 0.98em;
font-weight: 500;
}
/* Specific style for CNIL info label */
.cnil-info-label {
color: #6c757d;
font-size: 0.85em;
margin-top: 8px;
font-weight: normal;
}
/* New wrapper for CNIL checkbox and label */
.cnil-checkbox-wrapper {
display: flex;
align-items: flex-start; /* Align checkbox and text at the top */
gap: 8px; /* Space between checkbox and text */
width: 100%; /* Ensure it takes full width within its parent */
}
.form-control {
width: 100%;
padding: 8px 12px;
border: 1px solid #ced4da;
border-radius: 6px;
font-size: 1em;
color: #495057;
transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
box-sizing: border-box;
min-height: 38px;
}
.form-control:focus {
border-color: #80bdff;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
/* Styles for invalid inputs - ONLY apply when the 'is-invalid' class is present */
.form-control.is-invalid {
border-color: #dc3545;
padding-right: calc(1.5em + 0.75rem);
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right calc(0.375em + 0.1875rem) center;
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}
.form-control.is-invalid:focus {
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}
textarea.form-control {
resize: vertical;
min-height: 90px;
}
/* Required fields indicator */
.oscar_input_required {
color: #DD1B51;
font-weight: bold;
}
/* CNIL checkbox */
.custom-control-input {
width: 20px; /* Larger hit area */
height: 20px; /* Larger hit area */
border: 1px solid #ced4da;
border-radius: 4px; /* Slightly rounded corners for checkbox */
appearance: none; /* Hide default checkbox */
-webkit-appearance: none;
-moz-appearance: none;
cursor: pointer;
flex-shrink: 0; /* Prevent checkbox from shrinking */
margin-top: 2px; /* Adjust vertical alignment with text */
}
.custom-control-input:checked {
background-color: #198AB4;
border-color: #198AB4;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M4 8.5L6.5 11 12 5'/%3e%3csvg%3e");
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
}
.custom-control-input:focus {
outline: none;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.custom-control-label {
cursor: pointer;
color: #333;
flex-grow: 1; /* Allow label to take remaining space */
}
/* Style for the CNIL group itself */
.cnil-consent-group {
padding: 10px 0;
margin-bottom: 20px; /* Space below the group */
}
/* --- Primary Button (General Style for submit/next) --- */
.btn-primary {
display: block;
width: 100%;
padding: 15px 25px;
margin-top: 30px; /* Default margin, overridden by specific rules */
font-size: 1.25em;
font-weight: bold;
color: #fff;
background-color: #198AB4;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease, box-shadow 0.2s ease;
box-shadow: 0 5px 15px rgba(0, 123, 255, 0.25);
}
.btn-primary:hover {
background-color: #0056b3;
transform: translateY(-3px);
box-shadow: 0 7px 20px rgba(0, 123, 255, 0.35);
}
.btn-primary:disabled {
background-color: #b0d8ff;
cursor: not-allowed;
opacity: 0.7;
transform: none;
box-shadow: none;
}
/* --- Step-by-Step Form Sections (Mobile default display controlled by JS/active class) --- */
.form-section-step {
width: 100%;
/* !!! IMPORTANT: This 'display: none;' is why your form sections are hidden on mobile
by default. JavaScript MUST add the 'active' class to make them visible. */
display: none;
}
/* --- Navigation Buttons (Prev/Next for Mobile Steps) --- */
/* IMPORTANT: All .form-navigation elements are hidden by default on mobile.
JavaScript will explicitly set 'display: flex' for the active navigation. */
.form-navigation {
display: none; /* Crucial: This ensures all mobile navs are initially hidden */
justify-content: center;
gap: 15px;
margin-top: 25px; /* Space from content above */
}
.form-navigation .btn-next,
.form-navigation .btn-prev {
flex: 1;
max-width: 160px; /* Limit button width */
padding: 14px 0;
font-size: 1.15em;
font-weight: bold;
cursor: pointer;
border-radius: 8px;
border: none;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transition: background-color 0.3s ease, transform 0.2s ease;
}
/* Specific colors for navigation buttons */
.form-navigation .btn-prev {
background-color: #DD1B3D; /* Red color for previous */
color: #fff;
}
.form-navigation .btn-prev:hover {
background-color: #c71534;
transform: translateY(-2px);
}
.form-navigation .btn-next {
background-color: #198AB4; /* Blue color for next */
color: #fff;
}
.form-navigation .btn-next:hover {
background-color: #147395;
transform: translateY(-2px);
}
/* Mandatory fields note (global placement) */
.mandatory-fields-note-global {
font-size: 0.85em;
color: #555;
text-align: right; /* Default for desktop */
margin-top: 15px;
padding-right: 15px;
}
/* --- Media Query for DESKTOP SCREENS (min-width: 769px) --- */
@media (min-width: 769px) {
#oscar_school_form_container {
padding: 0 20px;
}
/* Form sections layout in two columns */
.form-sections-wrapper {
display: flex;
flex-wrap: nowrap; /* Prevent wrapping to new lines */
justify-content: center;
gap: 30px; /* Space between columns */
align-items: stretch; /* Make sections equal height */
margin-bottom: 0; /* No extra margin, note is positioned absolutely */
}
.form-section-step {
flex: 1; /* Each section takes equal space */
min-width: 0; /* Allow shrinking */
max-width: 50%; /* Max 50% width */
display: flex !important; /* Force display of all steps on desktop (as flex column) */
margin-bottom: 0; /* Remove mobile margin between sections */
}
.form-section {
height: 100%; /* Make sections equal height */
display: flex; /* Maintain flex column behavior for internal content */
flex-direction: column;
justify-content: space-between; /* Pushes content and the desktop submit button to ends */
padding-bottom: 20px; /* Add extra padding at the bottom of sections */
}
/* Hide all mobile-specific navigation elements on desktop */
.form-navigation, /* Targets all elements with this class */
.section-navigation-mobile,
#final-mobile-navigation,
.mobile-submit-button {
display: none !important; /* Force hide on desktop */
}
/* Show and style the desktop submit button inside the second column */
.desktop-submit-button {
display: block !important; /* Show the desktop button */
width: 100%; /* Make it full width of its column */
margin-top: auto; /* Pushes the button to the bottom of the flex column */
align-self: center; /* Centers the button */
padding: 15px 25px;
font-size: 1.25em;
box-shadow: 0 5px 15px rgba(0, 123, 255, 0.25);
}
/* Input fields layout in two columns within form-group */
.form-group {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.form-group-item {
flex: 1 1 calc(50% - 10px);
max-width: calc(50% - 10px);
}
/* "Je suis" select should take full width in its column on desktop */
#section1 .form-group:first-of-type .form-group-item {
flex: 1 1 100%;
max-width: 100%;
}
/* Mandatory fields note positioning on desktop */
.mandatory-fields-note-global {
position: absolute; /* Position relative to #oscar_school_form_body */
bottom: 20px;
left: 25px;
right: auto;
font-size: 0.9em;
color: #777;
text-align: left;
padding-right: 0;
}
}
/* --- Media Query for ALL MOBILE and TABLET DEVICES (max-width: 768px) --- */
/* This covers most phones and tablets. */
@media (max-width: 768px) {
#oscar_school_form_container {
width: 100%;
padding: 0 15px; /* Keeps a small padding on the sides of the page */
margin-top: 15px;
}
#oscar_school_form_body {
padding: 20px;
}
.form-sections-wrapper {
flex-direction: column; /* Stack sections vertically */
gap: 15px;
margin-bottom: 0; /* Controlled by JS and final-mobile-navigation */
}
.form-section {
min-width: unset;
padding: 18px;
margin-bottom: 20px; /* Space between sections if stacked by JS */
height: auto;
/* Align flex items to the start (left) of the section */
align-items: flex-start;
}
/* --- Mobile-specific section and navigation display rules --- */
/* This rule is critical: it makes a section visible ONLY IF it has the 'active' class. */
.form-section-step.active {
display: flex; /* Only show the active section on mobile */
flex-direction: column; /* Keep its internal content stacked */
}
/* All form-navigation elements are hidden by default, and ONLY shown by JS */
/* No CSS rule here to force display for specific mobile navs. JS handles it. */
/* General rule for form groups on mobile */
.form-group {
margin-bottom: 12px;
flex-direction: column; /* Each form-group-item (label+input pair) will stack vertically */
gap: 0;
width: 100%; /* Ensures form-group itself takes full width for its content */
max-width: 400px; /* Set a max-width for the form group to prevent it from being too wide */
/* IMPORTANT: Align the group to the left if the section is align-items: flex-start */
margin-left: 0; /* Ensures no auto margin on the left */
margin-right: auto; /* Allows right margin to push the group to the left if its width < max-width */
}
.form-group-item {
flex: 1 1 100%;
max-width: 100%; /* Make items fill the width of the form-group */
margin-bottom: 10px; /* Space between each label-input pair */
/* Each form-group-item contains label and input side by side */
display: flex;
flex-direction: row; /* Align label and input side by side */
align-items: center; /* Align vertically in the middle */
gap: 10px; /* Space between label and input */
}
.form-group-item:last-child {
margin-bottom: 0;
}
/* Adjustments for labels and controls within form-group-item */
.form-group-item label {
display: inline-block;
flex-shrink: 0;
width: 90px; /* Fixed width for labels to align them */
text-align: left; /* Align label text to the right */
margin-bottom: 0;
}
.form-group-item .form-control {
flex-grow: 1; /* Allow input to take remaining space */
width: auto;
max-width: calc(100% - 100px); /* Adjust max-width: Total 100% - label width - gap */
/* (100px = 90px (label width) + 10px (gap)) */
}
/* --- Specific to SECTION 1 (Example: "Identité") --- */
#section1 .form-group {
flex-direction: column; /* Ensures each field group (Nom, Prénom, etc.) is on its own line */
flex-wrap: nowrap;
gap: 0;
/* .form-group rules apply (max-width, left alignment) */
}
#section1 .form-group-item {
flex: 1 1 100%;
max-width: 100%;
margin-bottom: 10px; /* Space between each field (Nom, Prénom, etc.) */
}
/* Adjustment for the "Je suis" selector in section 1 */
#section1 .form-group:first-of-type .form-group-item {
flex: 1 1 100%;
max-width: 100%;
justify-content: flex-start;
}
#section1 .form-group:first-of-type .form-group-item label {
width: 90px; /* Keep fixed width for consistency with other labels */
text-align: left; /* Align to the right for consistency */
}
#section1 .form-group:first-of-type .form-group-item .form-control {
max-width: calc(100% - 100px); /* Apply max-width here too */
}
/* Specific for the CNIL group */
.cnil-consent-group {
max-width: 400px; /* Match other form-groups for alignment */
margin-left: auto;
margin-right: auto;
flex-direction: column; /* Ensure it stacks if needed */
align-items: flex-start;
}
/* Hide desktop submit button and show mobile submit button */
.desktop-submit-button {
display: none !important;
}
#final-mobile-navigation {
display: block !important; /* Show the container for the mobile submit button */
margin-top: 20px;
padding: 0 15px; /* Adjust padding as needed */
text-align: center; /* Center the button within its container */
}
.mobile-submit-button {
display: block !important; /* Show the mobile submit button */
margin: 0 auto; /* Center the button horizontally */
max-width: 400px; /* Align with max-width of form-groups */
width: 100%;
}
/* Mandatory fields note positioning on mobile */
.mandatory-fields-note-global {
position: static; /* Remove absolute positioning */
text-align: center; /* Center the note */
margin-top: 20px;
padding-right: 0;
}
}
/* --- Media Query for SMALL PHONES (max-width: 414px) --- */
/* This targets smaller phones (e.g., iPhone 6/7/8/SE new) and even smaller devices.
Adjust '414px' to '375px' or '320px' if you need more granular control for specific very small screens. */
@media (max-width: 414px) {
.form-group-item label {
width: 70px; /* Reduce label width to give more space to input */
}
.form-group-item .form-control {
max-width: calc(100% - 80px); /* Adjust max-width based on new label width (70px) + gap (10px) */
}
/* Re-adjust specific labels if needed for very small screens */
#section1 .form-group:first-of-type .form-group-item label {
width: 70px;
}
#section1 .form-group:first-of-type .form-group-item .form-control {
max-width: calc(100% - 80px);
}
}
</style>
<script>
(function() {
'use strict';
// Protection contre le double chargement
if (window.brochureFormLoaded) return;
window.brochureFormLoaded = true;
document.addEventListener("DOMContentLoaded", function () {
const form = document.getElementById('oscar_school_form');
if (!form) return;
const campusSelect = document.getElementById('campus_selection');
const formationSelect = document.getElementById('formation');
const cnilCheckbox = document.getElementById('cnil_oui');
let isSubmitting = false;
// Données
const campusTokens = {
sqy: "vsIu1hb1GNGrlz8WvmYId",
cgy: "7EeDfCG4JMnpVJEn0IQKX",
nantes: "PCqYmgZpmmy38TpKYh2rr",
marseille: "Q5vvHqjxtgAhcjnxwFary"
};
const campusFormIDs = {
sqy: "52", cgy: "192", nantes: "115", marseille: "26"
};
const campusConfirmationPaths = {
sqy: "confirmation-demande-de-brochure/",
cgy: "confirmation-demande-de-brochure/",
nantes: "confirmation-demande-de-brochure/",
marseille: "confirmation-demande-de-brochure/"
};
const formationsByCampus = {
sqy: [
{ value: "367", text: "BTS SIO SLAM" }, { value: "369", text: "BTS SIO SISR" },
{ value: "371", text: "BTS CIEL" }, { value: "373", text: "Bachelor TECH & DEV spé Gestion de projet IA & Data" },
{ value: "374", text: "Bachelor TECH & DEV spé Développeur Full Stack" },
{ value: "376", text: "Bachelor Systèmes & Réseaux spé Infra & Sécurité" },
{ value: "377", text: "Bachelor Systèmes & Réseaux spé cybersécurité" },
{ value: "378", text: "M1/M2 Expert Solutions Data" },
{ value: "379", text: "M1/M2 Expert Solutions IA & IOT" },
{ value: "380", text: "M1/M2 Lead Developer Full Stack" },
{ value: "382", text: "M1/M2 Expert Architectures IA & IOT" },
{ value: "383", text: "M1/M2 Expert Réseaux & Sécurité" },
{ value: "384", text: "M1/M2 Expert Cybersécurité & Cloud Computing" }
],
cgy: [
{ value: "367", text: "BTS SIO SLAM" }, { value: "369", text: "BTS SIO SISR" },
{ value: "371", text: "BTS CIEL" }, { value: "373", text: "Bachelor TECH & DEV spé Gestion de projet IA & Data" },
{ value: "374", text: "Bachelor TECH & DEV spé Développeur Full Stack" },
{ value: "376", text: "Bachelor Systèmes & Réseaux spé Infra & Sécurité" },
{ value: "377", text: "Bachelor Systèmes & Réseaux spé cybersécurité" },
{ value: "378", text: "M1/M2 Expert Solutions Data" },
{ value: "379", text: "M1/M2 Expert Solutions IA & IOT" },
{ value: "380", text: "M1/M2 Lead Developer Full Stack" },
{ value: "382", text: "M1/M2 Expert Architectures IA & IOT" },
{ value: "383", text: "M1/M2 Expert Réseaux & Sécurité" },
{ value: "384", text: "M1/M2 Expert Cybersécurité & Cloud Computing" }
],
nantes: [
{ value: "343", text: "BTS SIO SLAM" }, { value: "344", text: "BTS SIO SISR" },
{ value: "345", text: "BTS CIEL" }, { value: "363", text: "Bachelor TECH & DEV spé Gestion de projet IA & Data" },
{ value: "364", text: "Bachelor TECH & DEV spé Développeur Full Stack" },
{ value: "365", text: "Bachelor Systèmes & Réseaux spé Infra & Sécurité" },
{ value: "366", text: "Bachelor Systèmes & Réseaux spé cybersécurité" }
],
marseille: [
{ value: "402", text: "BTS SIO SLAM" }, { value: "404", text: "BTS SIO SISR" },
{ value: "406", text: "BTS CIEL" }, { value: "407", text: "Bachelor TECH & DEV spé Gestion de projet IA & Data" },
{ value: "408", text: "Bachelor TECH & DEV spé Développeur Full Stack" },
{ value: "409", text: "Bachelor Systèmes & Réseaux spé Infra & Sécurité" },
{ value: "410", text: "Bachelor Systèmes & Réseaux spé cybersécurité" }
]
};
// Fonctions
function updateHiddenFields() {
const campus = campusSelect.value;
document.getElementById("hidden_token_field").value = campusTokens[campus] || "";
document.getElementById("hidden_formID_field").value = campusFormIDs[campus] || "";
}
function updateFormationOptions() {
const campus = campusSelect.value;
formationSelect.innerHTML = '<option value="">Choisir une formation</option>';
if (campus && formationsByCampus[campus]) {
formationsByCampus[campus].forEach(f => {
const opt = document.createElement('option');
opt.value = f.value;
opt.textContent = f.text;
formationSelect.appendChild(opt);
});
}
}
function validateForm() {
const requiredInputs = form.querySelectorAll('[required]');
let allValid = true;
requiredInputs.forEach(input => {
input.classList.remove('is-invalid');
if ((input.type === "checkbox" && !input.checked) || (input.type !== "checkbox" && input.value.trim() === "")) {
input.classList.add('is-invalid');
allValid = false;
}
});
return allValid;
}
function updateSubmitButtons() {
const buttons = form.querySelectorAll('button[type="submit"]');
const canSubmit = cnilCheckbox.checked && !isSubmitting;
buttons.forEach(btn => btn.disabled = !canSubmit);
}
// Events
campusSelect.addEventListener('change', function() {
updateHiddenFields();
updateFormationOptions();
});
cnilCheckbox.addEventListener('change', updateSubmitButtons);
// CRUCIAL : Bloquer TOUTE soumission du formulaire
form.addEventListener('submit', function(e) {
e.preventDefault();
e.stopImmediatePropagation();
if (isSubmitting) {
console.warn("Déjà en cours");
return false;
}
if (!validateForm()) {
alert("Veuillez remplir tous les champs obligatoires et accepter le CNIL.");
return false;
}
isSubmitting = true;
const buttons = form.querySelectorAll('button[type="submit"]');
buttons.forEach(btn => {
btn.disabled = true;
btn.textContent = "Envoi en cours...";
});
const campus = campusSelect.value;
const redirectUrl = "https://ensitech.eu/" + (campusConfirmationPaths[campus] || "");
axios.post(form.action, new FormData(form))
.then(() => {
window.location.href = redirectUrl;
})
.catch(err => {
console.error(err);
alert("Erreur lors de l'envoi. Veuillez réessayer.");
isSubmitting = false;
buttons.forEach(btn => {
btn.disabled = false;
btn.textContent = "DEMANDER LA BROCHURE";
});
});
return false;
}, true); // true = capture phase
// Init
updateHiddenFields();
updateFormationOptions();
updateSubmitButtons();
});
})();
</script>

View File

@@ -0,0 +1,952 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Formulaire de Brochure Oscar School</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
<link rel="stylesheet" href="style.css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="oscar_school_form_container">
<div id="oscar_school_form_body">
<form id="oscar_school_form" method="POST" action="https://v3.oscar-campus.com/groupe_ensup/forms" ref="schoolForm">
<input type="hidden" name="type_formulaire" value="brochure">
<div class="form-sections-wrapper">
<div id="section1" class="form-section form-section-step active ">
<h2><i class="fas fa-book"></i> Demande de brochure</h2>
<p class="form-description">Remplissez ce formulaire pour accéder à notre brochure.</p>
<div class="form-group ">
<div class="form-group-item">
<label for="je_suis_ref_id">Je suis<span class="oscar_input_required">(*)</span>:</label>
</label>
<select
id="OscarContactJeSuisRefIdField"
class="form-control"
name="je_suis_ref_id"
v-on:change="determineRelatedFieldsOptions"
v-on:focus="displayAvailableOptions"
>
<option value="">Choisir</option>
<option value="434">Lycéen(ne)</option>
<option value="435">Étudiant(e)</option>
<option value="436">En poste / reconversion</option>
<option value="437">Étudiant avec un diplôme étranger</option>
<option value="439">Parent de l&#039;étudiant(e)</option>
</select>
</div>
</div>
<div class="form-group">
<div class="form-group-item">
<label for="nom">Nom<span class="oscar_input_required">(*)</span></label>
<input type="text" id="nom" name="nom" class="form-control" required pattern="^[A-Za-zÀ-ÿ' \-]{2,50}$" maxlength="50"
title="Le nom doit contenir uniquement des lettres (pas de chiffres ou symboles)">
</div>
<div class="form-group-item">
<label for="prenom">Prénom<span class="oscar_input_required">(*)</span></label>
<input type="text" id="prenom" name="prenom" class="form-control" required pattern="^[A-Za-zÀ-ÿ' \-]{2,50}$" maxlength="50"
title="Le prénom doit contenir uniquement des lettres (pas de chiffres ou symboles)">
</div>
</div>
<div class="form-group">
<div class="form-group-item">
<label for="email">Email<span class="oscar_input_required">(*)</span></label>
<input type="email" id="email" name="email" class="form-control" required title="Veuillez saisir une adresse email valide.">
</div>
<div class="form-group-item">
<label for="portable">Portable<span class="oscar_input_required">(*)</span></label>
<input type="tel" id="portable" name="portable" class="form-control" required>
</div>
</div>
<div class="form-group" >
<div class="form-group-item">
<label for="campus_selection_Brochure">Campus souhaité<span class="oscar_input_required">(*)</span></label>
<select id="campus_selection" name="campus" class="form-control" v-model="selectedCampus" required>
<option value="">Choisir un campus</option>
<option value="sqy">Saint-Quentin-en-Yvelines</option>
<option value="cgy">Cergy</option>
<option value="nantes">Nantes</option>
<option value="marseille">Marseille</option>
</select>
</div>
<div class="form-group-item">
<label for="formation">Formation souhaitée<span class="oscar_input_required">(*)</span></label>
<select id="formation" name="formation_souhaitee_formation_id" class="form-control" required>
<option value="">Choisir une formation</option>
<option value="346">BTS MCO</option>
<option value="348">BTS NDRC</option>
<option value="350">BTS GPME</option>
<option value="352">BTS CG</option>
<option value="354">BTS SAM</option>
<option value="355">Bachelor RCM</option>
<option value="356">Bachelor MDO</option>
<option value="357">DCG 2ème année</option>
<option value="358">M1/M2 Marketing et Stratégie Digitale</option>
<option value="359">M1/M2 Négociation Management des Affaires</option>
<option value="360">M1/M2 MCM spé Management et Stratégie d&#039;Entreprise</option>
<option value="361">M1/M2 Manager des Ressources Humaines</option>
<option value="362">M1/M2 Expert Finance et Pilotage de la Performance</option>
</select>
</div>
</div>
<div class="form-group cnil-consent-group">
<div class="cnil-checkbox-wrapper">
<input type="checkbox" id="cnil_oui" name="cnil" class="custom-control-input" value="1" required>
<label for="cnil_oui" class="cnil-info-label custom-control-label">
<strong>Oui, je donne mon approbation pour le traitement de mes données personnelles à ENSUP Business School.</strong><br>
<span style="color: grey; font-size: small;">En soumettant ce formulaire, jaccepte que mes informations soient utilisées dans le cadre de ma demande et de la relation commerciale éthique et personnalisée qui pourrait en découler si je le souhaite. <span class="oscar_input_required">(*)</span></span>
</label>
</div>
</div>
<button type="submit" class="btn-primary desktop-submit-button">DEMANDER LA BROCHURE </button>
</div>
</div>
<div id="final-mobile-navigation">
<button type="submit" class="btn-primary mobile-submit-button">DEMANDER LA BROCHURE</button>
</div>
<div class="mandatory-fields-note-global">(*) Champs obligatoires</div>
<input type="hidden" id="hidden_token_field" name="token">
<input type="hidden" id="hidden_formID_field" name="formID">
<input type="hidden" name="utm_campaign" value="">
<input type="hidden" name="utm_source" value="">
<input type="hidden" name="utm_medium" value="">
<input type="hidden" name="utm_term" value="">
<input type="hidden" name="utm_content" value="">
<div class="username_field" style="display: none;">
<label for="username">Type your username</label>
<input type="text" id="username" name="username" value="">
</div>
</form>
</div>
</div>
</body>
</html>
<style>
.form-description {
text-align: center;
margin-bottom: 25px; /* Space between description and form */
padding: 0 15px; /* Add some horizontal padding to prevent text from touching edges on small screens */
}
input:valid {
border: 1px solid green;
}
body {
margin: 0;
padding: 0;
background-color: #f0f2f5;
font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: #333;
}
/* --- Main Form Container --- */
#oscar_school_form_container {
max-width: 1200px;
margin: 20px auto;
padding: 0 15px;
}
/* --- Form Body Styles (The white/light gray box) --- */
#oscar_school_form_body {
position: relative;
background: linear-gradient(to bottom right, #f8f9fa, #e9ecef);
padding: 25px;
border-radius: 12px;
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
/* Optional: Form Header Styles if you uncomment them in HTML */
#oscar_school_form_header h1 {
color: #198AB4;
text-align: center;
margin-bottom: 20px;
font-size: 2.5em;
text-shadow: 1px 1px 2px rgba(0,0,0,0.05);
}
#oscar_school_form_header p {
text-align: center;
color: #555;
font-size: 1.15em;
margin-bottom: 35px;
}
/* --- Form Sections Wrapper (Desktop Flex / Mobile Stack) --- */
.form-sections-wrapper {
margin-bottom: 25px; /* Provides space if no final nav/note below */
}
/* --- Individual Form Section Styles (e.g., Identité, Projet de formation) --- */
.form-section {
padding: 20px;
border: 1px solid #e0e0e0;
border-radius: 10px;
background-color: #ffffff;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
height: auto;
margin-bottom: 20px; /* Space between stacked sections on mobile */
display: flex; /* Makes the section a flex container for its internal content */
flex-direction: column; /* Stacks its direct children vertically */
}
.form-section:hover {
transform: translateY(-5px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
}
.form-section h2 {
margin-top: 0;
color: #198AB4;
font-size: 1.7em;
border-bottom: 2px solid #198AB4;
padding-bottom: 12px;
margin-bottom: 22px;
text-align: center;
}
.form-section h2 i {
margin-right: 8px;
color: #198AB4;
}
/* --- Form Group & Control Styles --- */
.form-group {
margin-bottom: 8px;
display: flex; /* Makes immediate children flex items */
flex-wrap: wrap; /* Allows items to wrap to the next line */
gap: 20px; /* Space between flex items */
}
/* Default for individual items in a flex form-group */
.form-group-item {
flex: 1 1 calc(50% - 10px); /* Tries to take 50% width minus half the gap */
max-width: calc(50% - 10px);
}
/* For form-groups that should always be full width (e.g., "Je suis" select, or single input lines) */
/* This rule is more for desktop, on mobile we manage this differently */
.form-group > .form-group-item:only-child,
.form-group:not(.cnil-consent-group) > label + .form-control {
flex: 1 1 100%;
max-width: 100%;
}
.form-group label {
display: block;
margin-bottom: 6px;
color: #444;
font-size: 0.98em;
font-weight: 500;
}
/* Specific style for CNIL info label */
.cnil-info-label {
color: #6c757d;
font-size: 0.85em;
margin-top: 8px;
font-weight: normal;
}
/* New wrapper for CNIL checkbox and label */
.cnil-checkbox-wrapper {
display: flex;
align-items: flex-start; /* Align checkbox and text at the top */
gap: 8px; /* Space between checkbox and text */
width: 100%; /* Ensure it takes full width within its parent */
}
.form-control {
width: 100%;
padding: 8px 12px;
border: 1px solid #ced4da;
border-radius: 6px;
font-size: 1em;
color: #495057;
transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
box-sizing: border-box;
min-height: 38px;
}
.form-control:focus {
border-color: #80bdff;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
/* Styles for invalid inputs - ONLY apply when the 'is-invalid' class is present */
.form-control.is-invalid {
border-color: #dc3545;
padding-right: calc(1.5em + 0.75rem);
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right calc(0.375em + 0.1875rem) center;
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}
.form-control.is-invalid:focus {
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}
textarea.form-control {
resize: vertical;
min-height: 90px;
}
/* Required fields indicator */
.oscar_input_required {
color: #DD1B51;
font-weight: bold;
}
/* CNIL checkbox */
.custom-control-input {
width: 20px; /* Larger hit area */
height: 20px; /* Larger hit area */
border: 1px solid #ced4da;
border-radius: 4px; /* Slightly rounded corners for checkbox */
appearance: none; /* Hide default checkbox */
-webkit-appearance: none;
-moz-appearance: none;
cursor: pointer;
flex-shrink: 0; /* Prevent checkbox from shrinking */
margin-top: 2px; /* Adjust vertical alignment with text */
}
.custom-control-input:checked {
background-color: #198AB4;
border-color: #198AB4;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M4 8.5L6.5 11 12 5'/%3e%3csvg%3e");
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
}
.custom-control-input:focus {
outline: none;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.custom-control-label {
cursor: pointer;
color: #333;
flex-grow: 1; /* Allow label to take remaining space */
}
/* Style for the CNIL group itself */
.cnil-consent-group {
padding: 10px 0;
margin-bottom: 20px; /* Space below the group */
}
/* --- Primary Button (General Style for submit/next) --- */
.btn-primary {
display: block;
width: 100%;
padding: 15px 25px;
margin-top: 30px; /* Default margin, overridden by specific rules */
font-size: 1.25em;
font-weight: bold;
color: #fff;
background-color: #198AB4;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease, box-shadow 0.2s ease;
box-shadow: 0 5px 15px rgba(0, 123, 255, 0.25);
}
.btn-primary:hover {
background-color: #0056b3;
transform: translateY(-3px);
box-shadow: 0 7px 20px rgba(0, 123, 255, 0.35);
}
.btn-primary:disabled {
background-color: #b0d8ff;
cursor: not-allowed;
opacity: 0.7;
transform: none;
box-shadow: none;
}
/* --- Step-by-Step Form Sections (Mobile default display controlled by JS/active class) --- */
.form-section-step {
width: 100%;
/* !!! IMPORTANT: This 'display: none;' is why your form sections are hidden on mobile
by default. JavaScript MUST add the 'active' class to make them visible. */
display: none;
}
/* --- Navigation Buttons (Prev/Next for Mobile Steps) --- */
/* IMPORTANT: All .form-navigation elements are hidden by default on mobile.
JavaScript will explicitly set 'display: flex' for the active navigation. */
.form-navigation {
display: none; /* Crucial: This ensures all mobile navs are initially hidden */
justify-content: center;
gap: 15px;
margin-top: 25px; /* Space from content above */
}
.form-navigation .btn-next,
.form-navigation .btn-prev {
flex: 1;
max-width: 160px; /* Limit button width */
padding: 14px 0;
font-size: 1.15em;
font-weight: bold;
cursor: pointer;
border-radius: 8px;
border: none;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transition: background-color 0.3s ease, transform 0.2s ease;
}
/* Specific colors for navigation buttons */
.form-navigation .btn-prev {
background-color: #DD1B3D; /* Red color for previous */
color: #fff;
}
.form-navigation .btn-prev:hover {
background-color: #c71534;
transform: translateY(-2px);
}
.form-navigation .btn-next {
background-color: #198AB4; /* Blue color for next */
color: #fff;
}
.form-navigation .btn-next:hover {
background-color: #147395;
transform: translateY(-2px);
}
/* Mandatory fields note (global placement) */
.mandatory-fields-note-global {
font-size: 0.85em;
color: #555;
text-align: right; /* Default for desktop */
margin-top: 15px;
padding-right: 15px;
}
/* --- Media Query for DESKTOP SCREENS (min-width: 769px) --- */
@media (min-width: 769px) {
#oscar_school_form_container {
padding: 0 20px;
}
/* Form sections layout in two columns */
.form-sections-wrapper {
display: flex;
flex-wrap: nowrap; /* Prevent wrapping to new lines */
justify-content: center;
gap: 30px; /* Space between columns */
align-items: stretch; /* Make sections equal height */
margin-bottom: 0; /* No extra margin, note is positioned absolutely */
}
.form-section-step {
flex: 1; /* Each section takes equal space */
min-width: 0; /* Allow shrinking */
max-width: 50%; /* Max 50% width */
display: flex !important; /* Force display of all steps on desktop (as flex column) */
margin-bottom: 0; /* Remove mobile margin between sections */
}
.form-section {
height: 100%; /* Make sections equal height */
display: flex; /* Maintain flex column behavior for internal content */
flex-direction: column;
justify-content: space-between; /* Pushes content and the desktop submit button to ends */
padding-bottom: 20px; /* Add extra padding at the bottom of sections */
}
/* Hide all mobile-specific navigation elements on desktop */
.form-navigation, /* Targets all elements with this class */
.section-navigation-mobile,
#final-mobile-navigation,
.mobile-submit-button {
display: none !important; /* Force hide on desktop */
}
/* Show and style the desktop submit button inside the second column */
.desktop-submit-button {
display: block !important; /* Show the desktop button */
width: 100%; /* Make it full width of its column */
margin-top: auto; /* Pushes the button to the bottom of the flex column */
align-self: center; /* Centers the button */
padding: 15px 25px;
font-size: 1.25em;
box-shadow: 0 5px 15px rgba(0, 123, 255, 0.25);
}
/* Input fields layout in two columns within form-group */
.form-group {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.form-group-item {
flex: 1 1 calc(50% - 10px);
max-width: calc(50% - 10px);
}
/* "Je suis" select should take full width in its column on desktop */
#section1 .form-group:first-of-type .form-group-item {
flex: 1 1 100%;
max-width: 100%;
}
/* Mandatory fields note positioning on desktop */
.mandatory-fields-note-global {
position: absolute; /* Position relative to #oscar_school_form_body */
bottom: 20px;
left: 25px;
right: auto;
font-size: 0.9em;
color: #777;
text-align: left;
padding-right: 0;
}
}
/* --- Media Query for ALL MOBILE and TABLET DEVICES (max-width: 768px) --- */
/* This covers most phones and tablets. */
@media (max-width: 768px) {
#oscar_school_form_container {
width: 100%;
padding: 0 15px; /* Keeps a small padding on the sides of the page */
margin-top: 15px;
}
#oscar_school_form_body {
padding: 20px;
}
.form-sections-wrapper {
flex-direction: column; /* Stack sections vertically */
gap: 15px;
margin-bottom: 0; /* Controlled by JS and final-mobile-navigation */
}
.form-section {
min-width: unset;
padding: 18px;
margin-bottom: 20px; /* Space between sections if stacked by JS */
height: auto;
/* Align flex items to the start (left) of the section */
align-items: flex-start;
}
/* --- Mobile-specific section and navigation display rules --- */
/* This rule is critical: it makes a section visible ONLY IF it has the 'active' class. */
.form-section-step.active {
display: flex; /* Only show the active section on mobile */
flex-direction: column; /* Keep its internal content stacked */
}
/* All form-navigation elements are hidden by default, and ONLY shown by JS */
/* No CSS rule here to force display for specific mobile navs. JS handles it. */
/* General rule for form groups on mobile */
.form-group {
margin-bottom: 12px;
flex-direction: column; /* Each form-group-item (label+input pair) will stack vertically */
gap: 0;
width: 100%; /* Ensures form-group itself takes full width for its content */
max-width: 400px; /* Set a max-width for the form group to prevent it from being too wide */
/* IMPORTANT: Align the group to the left if the section is align-items: flex-start */
margin-left: 0; /* Ensures no auto margin on the left */
margin-right: auto; /* Allows right margin to push the group to the left if its width < max-width */
}
.form-group-item {
flex: 1 1 100%;
max-width: 100%; /* Make items fill the width of the form-group */
margin-bottom: 10px; /* Space between each label-input pair */
/* Each form-group-item contains label and input side by side */
display: flex;
flex-direction: row; /* Align label and input side by side */
align-items: center; /* Align vertically in the middle */
gap: 10px; /* Space between label and input */
}
.form-group-item:last-child {
margin-bottom: 0;
}
/* Adjustments for labels and controls within form-group-item */
.form-group-item label {
display: inline-block;
flex-shrink: 0;
width: 90px; /* Fixed width for labels to align them */
text-align: left; /* Align label text to the right */
margin-bottom: 0;
}
.form-group-item .form-control {
flex-grow: 1; /* Allow input to take remaining space */
width: auto;
max-width: calc(100% - 100px); /* Adjust max-width: Total 100% - label width - gap */
/* (100px = 90px (label width) + 10px (gap)) */
}
/* --- Specific to SECTION 1 (Example: "Identité") --- */
#section1 .form-group {
flex-direction: column; /* Ensures each field group (Nom, Prénom, etc.) is on its own line */
flex-wrap: nowrap;
gap: 0;
/* .form-group rules apply (max-width, left alignment) */
}
#section1 .form-group-item {
flex: 1 1 100%;
max-width: 100%;
margin-bottom: 10px; /* Space between each field (Nom, Prénom, etc.) */
}
/* Adjustment for the "Je suis" selector in section 1 */
#section1 .form-group:first-of-type .form-group-item {
flex: 1 1 100%;
max-width: 100%;
justify-content: flex-start;
}
#section1 .form-group:first-of-type .form-group-item label {
width: 90px; /* Keep fixed width for consistency with other labels */
text-align: left; /* Align to the right for consistency */
}
#section1 .form-group:first-of-type .form-group-item .form-control {
max-width: calc(100% - 100px); /* Apply max-width here too */
}
/* Specific for the CNIL group */
.cnil-consent-group {
max-width: 400px; /* Match other form-groups for alignment */
margin-left: auto;
margin-right: auto;
flex-direction: column; /* Ensure it stacks if needed */
align-items: flex-start;
}
/* Hide desktop submit button and show mobile submit button */
.desktop-submit-button {
display: none !important;
}
#final-mobile-navigation {
display: block !important; /* Show the container for the mobile submit button */
margin-top: 20px;
padding: 0 15px; /* Adjust padding as needed */
text-align: center; /* Center the button within its container */
}
.mobile-submit-button {
display: block !important; /* Show the mobile submit button */
margin: 0 auto; /* Center the button horizontally */
max-width: 400px; /* Align with max-width of form-groups */
width: 100%;
}
/* Mandatory fields note positioning on mobile */
.mandatory-fields-note-global {
position: static; /* Remove absolute positioning */
text-align: center; /* Center the note */
margin-top: 20px;
padding-right: 0;
}
}
/* --- Media Query for SMALL PHONES (max-width: 414px) --- */
/* This targets smaller phones (e.g., iPhone 6/7/8/SE new) and even smaller devices.
Adjust '414px' to '375px' or '320px' if you need more granular control for specific very small screens. */
@media (max-width: 414px) {
.form-group-item label {
width: 70px; /* Reduce label width to give more space to input */
}
.form-group-item .form-control {
max-width: calc(100% - 80px); /* Adjust max-width based on new label width (70px) + gap (10px) */
}
/* Re-adjust specific labels if needed for very small screens */
#section1 .form-group:first-of-type .form-group-item label {
width: 70px;
}
#section1 .form-group:first-of-type .form-group-item .form-control {
max-width: calc(100% - 80px);
}
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function () {
const campusSelect = document.getElementById('campus_selection');
const formationSelect = document.getElementById('formation');
const currentUrl = window.location.href;
const campusConfirmationPaths = {
sqy: "confirmation-demande-de-brochure/",
cgy: "confirmation-demande-de-brochure/",
nantes: "confirmation-demande-de-brochure/",
marseille: "confirmation-demande-de-brochure/"
};
const formationsByCampus = {
sqy: [
{ value: "346", text: "BTS MCO" },
{ value: "348", text: "BTS NDRC" },
{ value: "350", text: "BTS GPME" },
{ value: "352", text: "BTS CG" },
{ value: "354", text: "BTS SAM" },
{ value: "355", text: "Bachelor RCM" },
{ value: "356", text: "Bachelor MDO" },
{ value: "357", text: "DCG 2ème année" },
{ value: "358", text: "M1/M2 Marketing et Stratégie Digitale" },
{ value: "359", text: "M1/M2 Négociation Management des Affaires" },
{ value: "360", text: "M1/M2 MCM spé Management et Stratégie d'Entreprise" },
{ value: "361", text: "M1/M2 Manager des Ressources Humaines" },
{ value: "362", text: "M1/M2 Expert Finance et Pilotage de la Performance" }
],
cgy: [
{ value: "346", text: "BTS MCO" },
{ value: "348", text: "BTS NDRC" },
{ value: "350", text: "BTS GPME" },
{ value: "352", text: "BTS CG" },
{ value: "354", text: "BTS SAM" },
{ value: "355", text: "Bachelor RCM" },
{ value: "356", text: "Bachelor MDO" },
{ value: "357", text: "DCG 2ème année" },
{ value: "358", text: "M1/M2 Marketing et Stratégie Digitale" },
{ value: "359", text: "M1/M2 Négociation Management des Affaires" },
{ value: "360", text: "M1/M2 MCM spé Management et Stratégie d'Entreprise" },
{ value: "361", text: "M1/M2 Manager des Ressources Humaines" },
{ value: "362", text: "M1/M2 Expert Finance et Pilotage de la Performance" }
],
nantes: [
{ value: "331", text: "BTS MCO" },
{ value: "332", text: "BTS NDRC" },
{ value: "333", text: "BTS GPME" },
{ value: "335", text: "BTS CG" },
{ value: "334", text: "BTS SAM" },
{ value: "337", text: "Bachelor RCM" },
{ value: "336", text: "Bachelor MDO" },
{ value: "340", text: "M1/M2 Négociation Management des Affaires" },
{ value: "341", text: "M1/M2 MCM spé Management et Stratégie d'Entreprise" },
{ value: "342", text: "M1/M2 Manager des Ressources Humaines" }
],
marseille: [
{ value: "385", text: "BTS MCO" },
{ value: "387", text: "BTS NDRC" },
{ value: "389", text: "BTS GPME" },
{ value: "391", text: "BTS CG" },
{ value: "393", text: "BTS SAM" },
{ value: "394", text: "Bachelor RCM" },
{ value: "395", text: "Bachelor MDO" },
{ value: "398", text: "M1/M2 Négociation Management des Affaires" },
{ value: "399", text: "M1/M2 MCM spé Management et Stratégie d'Entreprise" },
{ value: "400", text: "M1/M2 Manager des Ressources Humaines" }
]
};
const vueInstance = new Vue({
el: "#oscar_school_form_container",
data: {
selectedCampus: campusSelect ? campusSelect.value : "",
campusTokens: {
sqy: "4izoKGMelggOkWr9WDmWb",
cgy: "MxtFVpAowjG6DLQj8kTP0",
nantes: "dejshqvaJLLFx9zdc74eV",
marseille: "mDkIP0CiAxScjYqkxObcr"
},
campusFormIDs: {
sqy: "159",
cgy: "49",
nantes: "122",
marseille: "27"
},
campusConfirmationPaths,
isSubmitting: false // ✅ placé ici
},
watch: {
selectedCampus() {
this.updateHiddenFields();
updateFormationOptions(this.selectedCampus);
}
},
mounted() {
if (campusSelect) {
const urlToCampusValueMap = {
'saint-quentin-en-yvelines': 'sqy',
'campus-cgy': 'cgy',
'campus-nantes': 'nantes',
'campus-marseille': 'marseille'
};
for (const urlPart in urlToCampusValueMap) {
if (currentUrl.includes(urlPart)) {
campusSelect.value = urlToCampusValueMap[urlPart];
this.selectedCampus = urlToCampusValueMap[urlPart];
break;
}
}
this.selectedCampus = campusSelect.value;
this.updateHiddenFields();
updateFormationOptions(this.selectedCampus);
campusSelect.addEventListener("change", (e) => {
this.selectedCampus = e.target.value;
});
}
},
methods: {
updateHiddenFields() {
const tokenField = document.getElementById("hidden_token_field");
const formIDField = document.getElementById("hidden_formID_field");
if (tokenField) tokenField.value = this.campusTokens[this.selectedCampus] || "";
if (formIDField) formIDField.value = this.campusFormIDs[this.selectedCampus] || "";
},
determineRelatedFieldsOptions() {
// ton code ici, même vide si tu veux juste supprimer le warning
},
displayAvailableOptions() {
return true; // ou ton vrai calcul
},
async submitForm() {
if (this.isSubmitting) return; // ✅ utilise this
this.isSubmitting = true;
this.disableSubmitButtons();
const form = document.getElementById("oscar_school_form");
const formData = new FormData(form);
const path = this.campusConfirmationPaths[this.selectedCampus] || "confirmation-generale/";
const baseUrl = "https://ensup.eu/";
try {
await axios.post(form.action, formData);
window.location.href = baseUrl + path;
} catch (error) {
console.error("Erreur :", error.response ? error.response.data : error.message);
alert("Erreur lors de l'envoi du formulaire. Veuillez réessayer.");
} finally {
setTimeout(() => {
this.isSubmitting = false;
this.enableSubmitButtons();
}, 2000);
}
},
disableSubmitButtons() {
const buttons = document.querySelectorAll('#oscar_school_form button[type="submit"], #final-mobile-navigation button[type="submit"]');
buttons.forEach(btn => {
btn.disabled = true;
btn.textContent = "Envoi en cours...";
});
},
enableSubmitButtons() {
const buttons = document.querySelectorAll('#oscar_school_form button[type="submit"], #final-mobile-navigation button[type="submit"]');
buttons.forEach(btn => {
btn.disabled = false;
btn.textContent = "Envoyer";
});
}
}
});
function updateFormationOptions(selectedCampusValue) {
formationSelect.innerHTML = '<option value="">Choisir une formation</option>';
if (selectedCampusValue && formationsByCampus[selectedCampusValue]) {
formationsByCampus[selectedCampusValue].forEach(formation => {
const option = document.createElement('option');
option.value = formation.value;
option.textContent = formation.text;
formationSelect.appendChild(option);
});
}
}
function validateForm() {
const form = document.getElementById('oscar_school_form');
const requiredInputs = form.querySelectorAll('input[required], select[required], textarea[required]');
let allValid = true;
requiredInputs.forEach(input => {
input.classList.remove('is-invalid');
let isValid = true;
const value = input.value.trim();
if (input.type === 'email') {
isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
} else if (['nom', 'prenom'].includes(input.name)) {
isValid = /^[A-Za-zÀ-ÿ' \-]{2,50}$/.test(value);
} else if (input.name === 'portable') {
isValid = /^(?:(?:\+|00)33|0)\s*[1-9](?:[\s.-]*\d{2}){4}$/.test(value);
} else if (input.type === 'checkbox' || input.type === 'radio') {
if (input.type === 'radio') {
const groupChecked = form.querySelectorAll(`input[name="${input.name}"]:checked`);
isValid = groupChecked.length > 0;
} else {
isValid = input.checked;
}
} else {
isValid = value.length > 0;
}
if (!isValid) {
input.classList.add('is-invalid');
allValid = false;
}
});
return allValid;
}
const cnilInputs = document.querySelectorAll('input[name="cnil"]');
function toggleSubmitState() {
const accepted = Array.from(cnilInputs).some(i => i.checked && i.value === "1");
document.querySelectorAll('#oscar_school_form button[type="submit"], #final-mobile-navigation button[type="submit"]')
.forEach(btn => btn.disabled = !accepted);
}
toggleSubmitState();
cnilInputs.forEach(i => i.addEventListener("change", toggleSubmitState));
const form = document.getElementById('oscar_school_form');
if (form) {
form.addEventListener('submit', function(e) {
e.preventDefault();
if (!validateForm()) {
alert("Veuillez remplir tous les champs obligatoires et accepter les conditions CNIL.");
return;
}
vueInstance.submitForm();
});
}
});
</script>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,169 @@
(function() {
'use strict';
console.log('🔧 DataLayer universel chargé');
if (window.location.href.includes('confirmation')) {
console.log('⏭️ Page de confirmation - script ignoré');
return;
}
let isProcessing = false;
let lastSubmitTime = 0;
const DEBOUNCE_DELAY = 1000;
async function sha256(value) {
if (!value) return '';
try {
const encoder = new TextEncoder();
const data = encoder.encode(value.trim().toLowerCase());
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
} catch (error) {
console.error('❌ Erreur hashage:', error);
return '';
}
}
function getSelectText(selectId) {
const select = document.getElementById(selectId);
if (select && select.selectedIndex >= 0 && select.options[select.selectedIndex]) {
return select.options[select.selectedIndex].text;
}
return '';
}
async function captureAndPushDataLayer() {
const now = Date.now();
if (isProcessing || (now - lastSubmitTime) < DEBOUNCE_DELAY) {
console.warn('⚠️ Envoi ignoré (protection anti-doublon)');
return;
}
isProcessing = true;
lastSubmitTime = now;
console.log('📝 Capture des données formulaire');
const consentCheckbox = document.querySelector('input[name="cnil"]:checked');
if (!consentCheckbox || consentCheckbox.value !== "1") {
console.warn('⚠️ Pas de consentement CNIL - dataLayer non envoyé');
isProcessing = false;
return;
}
const typeRaw = (document.querySelector('input[name="type_formulaire"]') || {}).value || '';
const emailRaw = (document.getElementById('email') || {}).value || '';
const portableRaw = (document.getElementById('portable') || {}).value || '';
const villeRaw = (document.getElementById('ville') || {}).value || '';
const codePostalRaw = (document.getElementById('codepostal') || document.getElementById('code_postal') || {}).value || '';
const campusRaw = (document.getElementById('campus_selection') || {}).value || '';
const statusRaw = getSelectText('OscarContactJeSuisRefIdField');
const formationRaw = getSelectText('formation');
const paysSelect = document.getElementById('pays');
let paysNom = '';
if (paysSelect && paysSelect.selectedIndex > 0) {
paysNom = paysSelect.options[paysSelect.selectedIndex].text;
}
console.log('📦 Données:', {
type: typeRaw,
status: statusRaw,
campus: campusRaw,
formation: formationRaw,
hasEmail: !!emailRaw,
hasPhone: !!portableRaw
});
const emailHash = await sha256(emailRaw);
const portableHash = await sha256(portableRaw);
const codePostalHash = await sha256(codePostalRaw);
const dataLayerObject = {
event: 'form_submit',
type: typeRaw.trim().toLowerCase(),
je_suis: statusRaw.trim(),
sha256_email_address: emailHash,
sha256_phone_number: portableHash,
sha256_postal_code: codePostalHash,
ville: villeRaw.trim(),
pays: paysNom,
campus: campusRaw.trim(),
formation: formationRaw.trim()
};
window.dataLayer = window.dataLayer || [];
window.dataLayer.push(dataLayerObject);
console.log('🚀 DataLayer push réussi:', dataLayerObject);
setTimeout(() => {
isProcessing = false;
}, 500);
}
// ✅ INTERCEPTER AXIOS.POST
function interceptAxios() {
if (!window.axios) {
console.warn('⚠️ Axios pas encore chargé, nouvelle tentative...');
setTimeout(interceptAxios, 100);
return;
}
console.log('✅ Interception axios configurée');
const originalPost = axios.post;
axios.post = async function(...args) {
const url = args[0];
// Vérifier si c'est un envoi de formulaire Oscar
if (url && url.includes('oscar-campus.com')) {
console.log('📝 Event: axios.post intercepté');
await captureAndPushDataLayer();
}
// Appeler la fonction originale
return originalPost.apply(this, args);
};
}
// ✅ Pour CANDIDATURE : mousedown (car Vue bloque tout)
function attachCandidatureListeners() {
const form = document.getElementById('oscar_school_form');
if (!form) return;
const typeInput = document.querySelector('input[name="type_formulaire"]');
const formType = typeInput ? typeInput.value : '';
if (formType === 'candidature') {
console.log('🎯 Mode candidature: ajout mousedown');
const allSubmitButtons = form.querySelectorAll('button[type="submit"]');
allSubmitButtons.forEach(btn => {
btn.addEventListener('mousedown', async function(e) {
console.log('📝 Event: mousedown (candidature)');
await captureAndPushDataLayer();
}, { capture: true });
});
}
}
// Démarrage
function init() {
console.log('🚀 Initialisation tracking DataLayer');
// Intercepter axios (pour JPO, Brochure, Contact)
interceptAxios();
// Attacher listeners spécifiques candidature
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', attachCandidatureListeners);
} else {
attachCandidatureListeners();
}
}
init();
})();

View File

@@ -0,0 +1,861 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Formulaire de contact Oscar School</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="oscar_school_form_container">
<div id="oscar_school_form_body">
<form id="oscar_school_form" method="POST" action="https://v3.oscar-campus.com/groupe_ensup/forms" ref="schoolForm">
<input type="hidden" name="type_formulaire" value="contact">
<div class="form-sections-wrapper">
<div id="section1" class="form-section form-section-step active ">
<div class="form-intro-message">
<h2><i class="fas fa-info-circle"></i> Une question sur nos formations, l'admission, le campus ou l'alternance ?</h2>
<p style="text-align: center;">Veuillez compléter ce formulaire, notre équipe vous recontactera rapidement.</p>
</div>
<div style="margin-bottom: 5px;"></div>
<div class="form-group">
<div class="form-group-item">
<label for="je_suis_ref_id">Je suis<span class="oscar_input_required">(*)</span>:</label>
<select id="OscarContactJeSuisRefIdField" class="form-control" name="je_suis_ref_id" v-on:change="determineRelatedFieldsOptions" v-on:focus="displayAvailableOptions">
<option value="">Choisir</option>
<option value="434">Lycéen(ne)</option>
<option value="435">Étudiant(e)</option>
<option value="436">En poste / reconversion</option>
<option value="437">Étudiant avec un diplôme étranger</option>
<option value="439">Parent de l&#039;étudiant(e)</option>
</select>
</div>
</div>
<div class="form-group">
<div class="form-group-item">
<label for="nom">Nom<span class="oscar_input_required">(*)</span></label>
<input type="text" id="nom" name="nom" class="form-control" required pattern="^[A-Za-zÀ-ÿ' \-]{2,50}$" maxlength="50" title="Le nom doit contenir uniquement des lettres (pas de chiffres ou symboles)">
</div>
<div class="form-group-item">
<label for="prenom">Prénom<span class="oscar_input_required">(*)</span></label>
<input type="text" id="prenom" name="prenom" class="form-control" required pattern="^[A-Za-zÀ-ÿ' \-]{2,50}$" maxlength="50" title="Le prénom doit contenir uniquement des lettres (pas de chiffres ou symboles)">
</div>
</div>
<div class="form-group">
<div class="form-group-item">
<label for="email">Email<span class="oscar_input_required">(*)</span></label>
<input type="email" id="email" name="email" class="form-control" required title="Veuillez saisir une adresse email valide.">
</div>
<div class="form-group-item">
<label for="portable">Portable<span class="oscar_input_required">(*)</span></label>
<input type="tel" id="portable" name="portable" class="form-control" required>
</div>
</div>
<div class="form-group">
<div class="form-group-item">
<label for="campus_selection">Campus souhaité<span class="oscar_input_required">(*)</span></label>
<select id="campus_selection" name="campus" class="form-control" v-model="selectedCampus" required>
<option value="">Choisir un campus</option>
<option value="sqy">Saint-Quentin-en-Yvelines</option>
<option value="cgy">Cergy</option>
<option value="nantes">Nantes</option>
<option value="marseille">Marseille</option>
</select>
</div>
</div>
<div class="form-group">
<div class="form-group-item full-width">
<label for="remarque">Objet de la demande:</label>
<textarea id="remarque" name="remarque" class="form-control" rows="4"></textarea>
</div>
</div>
<div class="form-group cnil-consent-group">
<div class="cnil-checkbox-wrapper">
<input type="checkbox" id="cnil_oui" name="cnil" class="custom-control-input" value="1" required>
<label for="cnil_oui" class="cnil-info-label custom-control-label">
<strong>Oui, je donne mon approbation pour le traitement de mes données personnelles à ENSUP Business School.</strong><br>
<span style="color: grey; font-size: small;">En soumettant ce formulaire, j'accepte que mes informations soient utilisées dans le cadre de ma demande et de la relation commerciale éthique et personnalisée qui pourrait en découler si je le souhaite. <span class="oscar_input_required">(*)</span></span>
</label>
</div>
</div>
<!-- Changé en type="button" au lieu de "submit" -->
<button type="button" class="btn-primary desktop-submit-button" id="desktop-submit-btn">
<span class="btn-text">ENVOYER</span>
<span class="btn-loading" style="display: none;">
<i class="fas fa-spinner fa-spin"></i> Envoi en cours...
</span>
</button>
</div>
</div>
<div id="final-mobile-navigation">
<!-- Changé en type="button" au lieu de "submit" -->
<button type="button" class="btn-primary mobile-submit-button" id="mobile-submit-btn">
<span class="btn-text">ENVOYER</span>
<span class="btn-loading" style="display: none;">
<i class="fas fa-spinner fa-spin"></i> Envoi en cours...
</span>
</button>
</div>
<div class="mandatory-fields-note-global">(*) Champs obligatoires</div>
<input type="hidden" id="hidden_token_field" name="token">
<input type="hidden" id="hidden_formID_field" name="formID">
<input type="hidden" name="utm_campaign" value="">
<input type="hidden" name="utm_source" value="">
<input type="hidden" name="utm_medium" value="">
<input type="hidden" name="utm_term" value="">
<input type="hidden" name="utm_content" value="">
<div class="username_field" style="display: none;">
<label for="username">Type your username</label>
<input type="text" id="username" name="username" value="">
</div>
</form>
</div>
</div>
<style>
.form-description {
text-align: center;
margin-bottom: 25px;
padding: 0 15px;
}
input:valid {
border: 1px solid green;
}
body {
margin: 0;
padding: 0;
background-color: #f0f2f5;
font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: #333;
}
#oscar_school_form_container {
max-width: 1200px;
margin: 20px auto;
padding: 0 15px;
}
#oscar_school_form_body {
position: relative;
background: linear-gradient(to bottom right, #f8f9fa, #e9ecef);
padding: 25px;
border-radius: 12px;
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
.form-sections-wrapper {
margin-bottom: 25px;
}
.form-section {
padding: 20px;
border: 1px solid #e0e0e0;
border-radius: 10px;
background-color: #ffffff;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
height: auto;
margin-bottom: 20px;
display: flex;
flex-direction: column;
}
.form-section:hover {
transform: translateY(-5px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
}
.form-section h2 {
margin-top: 0;
color: #198AB4;
font-size: 1.5em;
border-bottom: 2px solid #198AB4;
padding-bottom: 12px;
margin-bottom: 22px;
text-align: center;
}
.form-section h2 i {
margin-right: 8px;
color: #198AB4;
}
.form-group {
margin-bottom: 8px;
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.form-group-item {
flex: 1 1 calc(50% - 10px);
max-width: calc(50% - 10px);
}
.form-group > .form-group-item:only-child,
.form-group:not(.cnil-consent-group) > label + .form-control {
flex: 1 1 100%;
max-width: 100%;
}
.form-group label {
display: block;
margin-bottom: 6px;
color: #444;
font-size: 0.98em;
font-weight: 500;
}
.cnil-info-label {
color: #6c757d;
font-size: 0.85em;
margin-top: 8px;
font-weight: normal;
}
.cnil-checkbox-wrapper {
display: flex;
align-items: flex-start;
gap: 8px;
width: 100%;
}
.form-control {
width: 100%;
padding: 8px 12px;
border: 1px solid #ced4da;
border-radius: 6px;
font-size: 1em;
color: #495057;
transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
box-sizing: border-box;
min-height: 38px;
}
.form-control:focus {
border-color: #80bdff;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.form-control.is-invalid {
border-color: #dc3545;
padding-right: calc(1.5em + 0.75rem);
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right calc(0.375em + 0.1875rem) center;
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}
.form-control.is-invalid:focus {
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}
textarea.form-control {
resize: vertical;
min-height: 90px;
}
.oscar_input_required {
color: #DD1B51;
font-weight: bold;
}
.custom-control-input {
width: 20px;
height: 20px;
border: 1px solid #ced4da;
border-radius: 4px;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
cursor: pointer;
flex-shrink: 0;
margin-top: 2px;
}
.custom-control-input:checked {
background-color: #198AB4;
border-color: #198AB4;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M4 8.5L6.5 11 12 5'/%3e%3csvg%3e");
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
}
.custom-control-input:focus {
outline: none;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.custom-control-label {
cursor: pointer;
color: #333;
flex-grow: 1;
}
.cnil-consent-group {
padding: 10px 0;
margin-bottom: 20px;
}
.btn-primary {
display: block;
width: 100%;
padding: 15px 25px;
margin-top: 30px;
font-size: 1.25em;
font-weight: bold;
color: #fff;
background-color: #198AB4;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease, box-shadow 0.2s ease;
box-shadow: 0 5px 15px rgba(0, 123, 255, 0.25);
}
.btn-primary:hover:not(:disabled) {
background-color: #0056b3;
transform: translateY(-3px);
box-shadow: 0 7px 20px rgba(0, 123, 255, 0.35);
}
.btn-primary:disabled {
background-color: #b0d8ff;
cursor: not-allowed;
opacity: 0.7;
transform: none;
box-shadow: none;
}
/* États pour les boutons pendant l'envoi */
.btn-primary.sending {
background-color: #6c757d;
cursor: not-allowed;
pointer-events: none;
}
.btn-loading {
display: none;
}
.form-section-step {
width: 100%;
display: none;
}
.form-navigation {
display: none;
justify-content: center;
gap: 15px;
margin-top: 25px;
}
.mandatory-fields-note-global {
font-size: 0.85em;
color: #555;
text-align: right;
margin-top: 15px;
padding-right: 15px;
}
@media (min-width: 769px) {
#oscar_school_form_container {
padding: 0 20px;
}
.form-sections-wrapper {
display: flex;
flex-wrap: nowrap;
justify-content: center;
gap: 30px;
align-items: stretch;
margin-bottom: 0;
}
.form-section-step {
flex: 1;
min-width: 0;
max-width: 50%;
display: flex !important;
margin-bottom: 0;
}
.form-section {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
padding-bottom: 20px;
}
.form-navigation,
.section-navigation-mobile,
#final-mobile-navigation,
.mobile-submit-button {
display: none !important;
}
.desktop-submit-button {
display: block !important;
width: 100%;
margin-top: auto;
align-self: center;
padding: 15px 25px;
font-size: 1.25em;
box-shadow: 0 5px 15px rgba(0, 123, 255, 0.25);
}
.form-group {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.form-group-item {
flex: 1 1 calc(50% - 10px);
max-width: calc(50% - 10px);
}
#section1 .form-group:first-of-type .form-group-item {
flex: 1 1 100%;
max-width: 100%;
}
.mandatory-fields-note-global {
position: absolute;
bottom: 20px;
left: 25px;
right: auto;
font-size: 0.9em;
color: #777;
text-align: left;
padding-right: 0;
}
}
@media (max-width: 768px) {
#oscar_school_form_container {
width: 100%;
padding: 0 15px;
margin-top: 15px;
}
#oscar_school_form_body {
padding: 20px;
}
.form-sections-wrapper {
flex-direction: column;
gap: 15px;
margin-bottom: 0;
}
.form-section {
min-width: unset;
padding: 18px;
margin-bottom: 20px;
height: auto;
align-items: flex-start;
}
.form-section-step.active {
display: flex;
flex-direction: column;
}
.form-group {
margin-bottom: 12px;
flex-direction: column;
gap: 0;
width: 100%;
max-width: 400px;
margin-left: 0;
margin-right: auto;
}
.form-group-item {
flex: 1 1 100%;
max-width: 100%;
margin-bottom: 10px;
display: flex;
flex-direction: row;
align-items: center;
gap: 10px;
}
.form-group-item:last-child {
margin-bottom: 0;
}
.form-group-item label {
display: inline-block;
flex-shrink: 0;
width: 90px;
text-align: left;
margin-bottom: 0;
}
.form-group-item .form-control {
flex-grow: 1;
width: auto;
max-width: calc(100% - 100px);
}
#section1 .form-group {
flex-direction: column;
flex-wrap: nowrap;
gap: 0;
}
#section1 .form-group-item {
flex: 1 1 100%;
max-width: 100%;
margin-bottom: 10px;
}
#section1 .form-group:first-of-type .form-group-item {
flex: 1 1 100%;
max-width: 100%;
justify-content: flex-start;
}
#section1 .form-group:first-of-type .form-group-item label {
width: 90px;
text-align: left;
}
#section1 .form-group:first-of-type .form-group-item .form-control {
max-width: calc(100% - 100px);
}
.cnil-consent-group {
max-width: 400px;
margin-left: auto;
margin-right: auto;
flex-direction: column;
align-items: flex-start;
}
.desktop-submit-button {
display: none !important;
}
#final-mobile-navigation {
display: block !important;
margin-top: 20px;
padding: 0 15px;
text-align: center;
}
.mobile-submit-button {
display: block !important;
margin: 0 auto;
max-width: 400px;
width: 100%;
}
.mandatory-fields-note-global {
position: static;
text-align: center;
margin-top: 20px;
padding-right: 0;
}
}
@media (max-width: 414px) {
.form-group-item label {
width: 70px;
}
.form-group-item .form-control {
max-width: calc(100% - 80px);
}
#section1 .form-group:first-of-type .form-group-item label {
width: 70px;
}
#section1 .form-group:first-of-type .form-group-item .form-control {
max-width: calc(100% - 80px);
}
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function () {
const campusSelect = document.getElementById('campus_selection');
const currentUrl = window.location.href;
// Variable pour empêcher la double soumission
let isSubmitting = false;
const campusConfirmationPaths = {
sqy: "confirmation-demande-de-contact/",
cgy: "confirmation-demande-de-contact/",
nantes: "confirmation-demande-de-contact/",
marseille: "confirmation-demande-de-contact/"
};
const vueInstance = new Vue({
el: "#campus_selection",
data: {
selectedCampus: campusSelect ? campusSelect.value : "",
campusTokens: {
sqy: "PIx5eSXzI57PWJSfTFQBv",
cgy: "CjqbNJddymhrjbYH4w7XT",
nantes: "ggkp1CJ1YUnHBnDbo7VIG",
marseille: "Z9vB02p0kL15pnJSMSIsU"
},
campusFormIDs: {
sqy: "263",
cgy: "270",
nantes: "267",
marseille: "262"
},
campusConfirmationPaths
},
watch: {
selectedCampus() {
this.updateHiddenFields();
}
},
mounted() {
if (campusSelect) {
const urlToCampusValueMap = {
'saint-quentin-en-yvelines': 'sqy',
'campus-cgy': 'cgy',
'campus-nantes': 'nantes',
'campus-marseille': 'marseille'
};
for (const urlPart in urlToCampusValueMap) {
if (currentUrl.includes(urlPart)) {
campusSelect.value = urlToCampusValueMap[urlPart];
this.selectedCampus = urlToCampusValueMap[urlPart];
break;
}
}
this.selectedCampus = campusSelect.value;
this.updateHiddenFields();
campusSelect.addEventListener("change", (e) => {
this.selectedCampus = e.target.value;
});
}
},
methods: {
updateHiddenFields() {
const tokenField = document.getElementById("hidden_token_field");
const formIDField = document.getElementById("hidden_formID_field");
if (tokenField) tokenField.value = this.campusTokens[this.selectedCampus] || "";
if (formIDField) formIDField.value = this.campusFormIDs[this.selectedCampus] || "";
},
async submitForm() {
if (isSubmitting) {
console.log("Soumission déjà en cours, ignorée");
return;
}
isSubmitting = true;
const form = document.getElementById("oscar_school_form");
const campusSelect = document.getElementById('campus_selection');
// Vérifier que le campus est bien sélectionné
if (!campusSelect || !campusSelect.value) {
alert("Veuillez sélectionner un campus");
isSubmitting = false;
return;
}
this.setLoadingState(true);
try {
const formData = new FormData(form);
// S'assurer que la valeur du campus est bien récupérée
const selectedCampusValue = campusSelect.value;
console.log("Campus sélectionné:", selectedCampusValue);
// Vérifier que le path existe pour ce campus
const path = this.campusConfirmationPaths[selectedCampusValue];
if (!path) {
console.error("Pas de chemin de confirmation pour le campus:", selectedCampusValue);
// Utiliser le chemin par défaut ou gérer l'erreur
path = "confirmation-demande-de-contact/";
}
const baseUrl = "https://ensup.eu/";
const redirectUrl = baseUrl + path;
console.log("Redirection prévue vers:", redirectUrl);
const response = await axios.post(form.action, formData);
console.log("Formulaire envoyé avec succès");
window.location.href = redirectUrl;
} catch (error) {
console.error("Erreur lors de l'envoi:", error);
alert("Erreur lors de l'envoi du formulaire. Veuillez réessayer.");
isSubmitting = false;
this.setLoadingState(false);
}
},
setLoadingState(loading) {
const desktopBtn = document.getElementById("desktop-submit-btn");
const mobileBtn = document.getElementById("mobile-submit-btn");
[desktopBtn, mobileBtn].forEach(btn => {
if (btn) {
if (loading) {
btn.classList.add('sending');
btn.disabled = true;
const btnText = btn.querySelector('.btn-text');
const btnLoading = btn.querySelector('.btn-loading');
if (btnText) btnText.style.display = 'none';
if (btnLoading) btnLoading.style.display = 'inline-block';
} else {
btn.classList.remove('sending');
btn.disabled = false;
const btnText = btn.querySelector('.btn-text');
const btnLoading = btn.querySelector('.btn-loading');
if (btnText) btnText.style.display = 'inline';
if (btnLoading) btnLoading.style.display = 'none';
}
}
});
}
}
});
function validateForm() {
const formSection = document.getElementById('section1');
const requiredInputs = formSection.querySelectorAll('input[required], select[required], textarea[required]');
let allValid = true;
requiredInputs.forEach(input => {
input.classList.remove('is-invalid');
let isValid = true;
const value = input.value.trim();
if (input.type === 'email') {
isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
} else if (['nom', 'prenom'].includes(input.name)) {
isValid = /^[A-Za-zÀ-ÿ' \-]{2,50}$/.test(value);
} else if (input.name === 'portable') {
isValid = /^(?:(?:\+|00)33|0)\s*[1-9](?:[\s.-]*\d{2}){4}$/.test(value);
} else if (input.type === 'checkbox' || input.type === 'radio') {
if (input.type === 'radio') {
const groupChecked = formSection.querySelectorAll(`input[name="${input.name}"]:checked`);
isValid = groupChecked.length > 0;
} else {
isValid = input.checked;
}
} else {
isValid = value.length > 0;
}
if (!isValid) {
input.classList.add('is-invalid');
allValid = false;
}
});
return allValid;
}
const cnilCheckbox = document.getElementById('cnil_oui');
const desktopBtn = document.getElementById('desktop-submit-btn');
const mobileBtn = document.getElementById('mobile-submit-btn');
function toggleSubmitButtonState() {
const accepted = cnilCheckbox && cnilCheckbox.checked;
if (desktopBtn) desktopBtn.disabled = !accepted;
if (mobileBtn) mobileBtn.disabled = !accepted;
}
// État initial
toggleSubmitButtonState();
// Écouter les changements CNIL
if (cnilCheckbox) {
cnilCheckbox.addEventListener("change", toggleSubmitButtonState);
}
// Gestion des clics sur les boutons
function handleFormSubmit(e) {
e.preventDefault();
e.stopPropagation();
console.log("Tentative de soumission...");
if (isSubmitting) {
console.log("Soumission déjà en cours");
return false;
}
if (!validateForm()) {
const accepted = cnilCheckbox && cnilCheckbox.checked;
alert(accepted
? "Veuillez remplir tous les champs obligatoires."
: "Veuillez accepter les conditions CNIL pour envoyer le formulaire.");
return false;
}
if (vueInstance && typeof vueInstance.submitForm === 'function') {
vueInstance.submitForm();
}
return false;
}
// Attacher les événements aux boutons
if (desktopBtn) {
desktopBtn.addEventListener('click', handleFormSubmit);
}
if (mobileBtn) {
mobileBtn.addEventListener('click', handleFormSubmit);
}
// Empêcher la soumission native du formulaire
const form = document.getElementById('oscar_school_form');
if (form) {
form.addEventListener('submit', function(e) {
e.preventDefault();
e.stopPropagation();
console.log("Soumission native bloquée");
return false;
});
}
});
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff