✉️ Feature: Epic 5 - Formulaire de Contact (Stories 5.1-5.7)
- Formulaire HTML5 avec validation (nom, prénom, email, entreprise, catégorie, objet, message) - Validation JavaScript côté client (FormValidator) - Persistance localStorage des données (AppState) - Intégration reCAPTCHA v3 avec dégradation gracieuse - Traitement PHP sécurisé (CSRF, validation, envoi email) - Feedback utilisateur AJAX (succès/erreur) - Liens contact secondaires (LinkedIn, GitHub, Email protégé) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
76
assets/js/state.js
Normal file
76
assets/js/state.js
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Gestionnaire d'état pour le localStorage
|
||||
* Persiste les données du formulaire de contact
|
||||
*/
|
||||
|
||||
const AppState = {
|
||||
STORAGE_KEY: 'portfolio_contact_form',
|
||||
|
||||
// Champs à ne jamais stocker (sécurité)
|
||||
EXCLUDED_FIELDS: ['csrf_token', 'password', 'recaptcha_token'],
|
||||
|
||||
/**
|
||||
* Vérifie si localStorage est disponible
|
||||
*/
|
||||
isStorageAvailable() {
|
||||
try {
|
||||
const test = '__storage_test__';
|
||||
localStorage.setItem(test, test);
|
||||
localStorage.removeItem(test);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sauvegarde les données du formulaire
|
||||
* @param {Object} data - Données du formulaire
|
||||
*/
|
||||
saveFormData(data) {
|
||||
if (!this.isStorageAvailable()) return;
|
||||
|
||||
try {
|
||||
// Filtrer les champs exclus
|
||||
const filteredData = {};
|
||||
Object.keys(data).forEach(key => {
|
||||
if (!this.EXCLUDED_FIELDS.includes(key)) {
|
||||
filteredData[key] = data[key];
|
||||
}
|
||||
});
|
||||
|
||||
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(filteredData));
|
||||
} catch (e) {
|
||||
console.warn('Impossible de sauvegarder dans localStorage:', e);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Charge les données sauvegardées
|
||||
* @returns {Object|null} Données ou null si absentes
|
||||
*/
|
||||
getFormData() {
|
||||
if (!this.isStorageAvailable()) return null;
|
||||
|
||||
try {
|
||||
const data = localStorage.getItem(this.STORAGE_KEY);
|
||||
return data ? JSON.parse(data) : null;
|
||||
} catch (e) {
|
||||
console.warn('Impossible de charger depuis localStorage:', e);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Efface les données sauvegardées
|
||||
*/
|
||||
clearFormData() {
|
||||
if (!this.isStorageAvailable()) return;
|
||||
|
||||
try {
|
||||
localStorage.removeItem(this.STORAGE_KEY);
|
||||
} catch (e) {
|
||||
// Silencieux
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user