Story 5.3: persistance localStorage

This commit is contained in:
2026-02-04 21:10:40 +01:00
parent fb95a39792
commit a4e0cb71e9
7 changed files with 222 additions and 42 deletions

View File

@@ -1,6 +1,6 @@
/**
/**
* Validation du formulaire de contact
* JavaScript vanilla - pas de dépendances
* JavaScript vanilla - pas de dépendances
*/
class FormValidator {
@@ -21,13 +21,13 @@ class FormValidator {
required: true,
minLength: 2,
maxLength: 100,
message: 'Veuillez entrer votre nom (2 caractères minimum)'
message: 'Veuillez entrer votre nom (2 caractères minimum)'
},
prenom: {
required: true,
minLength: 2,
maxLength: 100,
message: 'Veuillez entrer votre prénom (2 caractères minimum)'
message: 'Veuillez entrer votre prénom (2 caractères minimum)'
},
email: {
required: true,
@@ -36,19 +36,19 @@ class FormValidator {
},
categorie: {
required: true,
message: 'Veuillez sélectionner une catégorie'
message: 'Veuillez sélectionner une catégorie'
},
objet: {
required: true,
minLength: 5,
maxLength: 200,
message: 'Veuillez entrer un objet (5 caractères minimum)'
message: 'Veuillez entrer un objet (5 caractères minimum)'
},
message: {
required: true,
minLength: 20,
maxLength: 5000,
message: 'Veuillez entrer votre message (20 caractères minimum)'
message: 'Veuillez entrer votre message (20 caractères minimum)'
}
};
@@ -98,7 +98,7 @@ class FormValidator {
if (isValid && rule.maxLength && value.length > rule.maxLength) {
isValid = false;
errorMessage = `Maximum ${rule.maxLength} caractères`;
errorMessage = `Maximum ${rule.maxLength} caractères`;
}
if (isValid && rule.email && value) {
@@ -212,6 +212,89 @@ class FormValidator {
}
}
class ContactFormPersistence {
constructor(formId) {
this.form = document.getElementById(formId);
if (!this.form) return;
this.debounceTimer = null;
this.init();
}
init() {
this.loadSavedData();
this.bindEvents();
}
bindEvents() {
this.form.addEventListener('input', () => {
clearTimeout(this.debounceTimer);
this.debounceTimer = setTimeout(() => this.saveData(), 500);
});
const clearBtn = document.getElementById('clear-form-btn');
if (clearBtn) {
clearBtn.addEventListener('click', () => this.clearForm());
}
this.form.addEventListener('formSuccess', () => {
AppState.clearFormData();
});
}
saveData() {
const formData = new FormData(this.form);
const data = {};
formData.forEach((value, key) => {
data[key] = value;
});
AppState.saveFormData(data);
}
loadSavedData() {
const savedData = AppState.getFormData();
if (!savedData) return;
Object.keys(savedData).forEach((key) => {
const field = this.form.querySelector(`[name="${key}"]`);
if (field && savedData[key]) {
field.value = savedData[key];
}
});
const messageField = this.form.querySelector('[name="message"]');
const countEl = document.getElementById('message-count');
if (messageField && countEl) {
countEl.textContent = messageField.value.length;
}
}
clearForm() {
if (!confirm('Êtes-vous sûr de vouloir effacer le formulaire ?')) {
return;
}
AppState.clearFormData();
this.form.reset();
const countEl = document.getElementById('message-count');
if (countEl) {
countEl.textContent = '0';
}
this.form.querySelectorAll('.input-error').forEach((el) => {
el.classList.remove('input-error');
});
this.form.querySelectorAll('[data-error]').forEach((el) => {
el.classList.add('hidden');
el.textContent = '';
});
}
}
document.addEventListener('DOMContentLoaded', () => {
window.contactFormValidator = new FormValidator('contact-form');
window.contactFormPersistence = new ContactFormPersistence('contact-form');
});