chore: build

This commit is contained in:
2026-06-12 15:33:52 +02:00
parent 4792536900
commit 0a8548033d
3 changed files with 90 additions and 51 deletions
@@ -14,7 +14,9 @@ const ChangePasswordPage = () => {
const [showNew, setShowNew] = useState(false);
const [showConfirm, setShowConfirm] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [modal, setModal] = useState<{ show: boolean; type: 'success' | 'error'; message: string }>({ show: false, type: 'success', message: '' });
const [showSuccessModal, setShowSuccessModal] = useState(false);
const [showErrorModal, setShowErrorModal] = useState(false);
const [errorMsg, setErrorMsg] = useState('');
const validate = (): string | null => {
if (!currentPassword) return "Le mot de passe actuel est requis";
@@ -30,7 +32,8 @@ const ChangePasswordPage = () => {
const validationError = validate();
if (validationError) {
setModal({ show: true, type: 'error', message: validationError });
setErrorMsg(validationError);
setShowErrorModal(true);
return;
}
@@ -38,23 +41,16 @@ const ChangePasswordPage = () => {
try {
const result = await changePassword(currentPassword, newPassword);
if (result.success) {
setModal({ show: true, type: 'success', message: 'Mot de passe mis à jour avec succès !' });
setShowSuccessModal(true);
} else {
setModal({ show: true, type: 'error', message: result.message || 'Erreur lors du changement de mot de passe.' });
setErrorMsg(result.message || 'Erreur lors du changement de mot de passe.');
setShowErrorModal(true);
}
} finally {
setIsLoading(false);
}
};
const handleCloseModal = () => {
if (modal.type === 'success') {
navigate("/user/accueil");
} else {
setModal(m => ({ ...m, show: false }));
}
};
return (
<>
<div className="cp-container">
@@ -177,24 +173,36 @@ const ChangePasswordPage = () => {
</div>
</div>
{modal.show && (
<div className="cp-modal-overlay" onClick={handleCloseModal}>
{/* Modal succès */}
{showSuccessModal && (
<div className="cp-modal-overlay" onClick={() => navigate('/user/accueil')}>
<div className="cp-modal" onClick={(e) => e.stopPropagation()}>
<button className="cp-modal-close" onClick={handleCloseModal}>
<div className="cp-modal-icon cp-modal-icon--success">
<CheckCircle size={28} />
</div>
<h3 className="cp-modal-title">Mot de passe mis à jour</h3>
<p className="cp-modal-body">Votre mot de passe a é changé avec succès.</p>
<button className="cp-modal-btn cp-modal-btn--success" onClick={() => navigate('/user/accueil')}>
<CheckCircle size={16} /> Continuer
</button>
</div>
</div>
)}
{/* Modal erreur */}
{showErrorModal && (
<div className="cp-modal-overlay" onClick={() => setShowErrorModal(false)}>
<div className="cp-modal" onClick={(e) => e.stopPropagation()}>
<button className="cp-modal-close" onClick={() => setShowErrorModal(false)}>
<X size={18} />
</button>
<div className={`cp-modal-icon ${modal.type === 'error' ? 'cp-modal-icon--error' : 'cp-modal-icon--success'}`}>
{modal.type === 'error'
? <AlertTriangle size={28} />
: <CheckCircle size={28} />
}
<div className="cp-modal-icon cp-modal-icon--error">
<AlertTriangle size={28} />
</div>
<h3 className="cp-modal-title">
{modal.type === 'error' ? 'Erreur' : 'Succès'}
</h3>
<p className="cp-modal-body">{modal.message}</p>
<button className={`cp-modal-btn ${modal.type === 'error' ? 'cp-modal-btn--error' : 'cp-modal-btn--success'}`} onClick={handleCloseModal}>
{modal.type === 'success' ? <><CheckCircle size={16} /> Continuer</> : <><X size={16} /> Fermer</>}
<h3 className="cp-modal-title">Une erreur est survenue</h3>
<p className="cp-modal-body">{errorMsg}</p>
<button className="cp-modal-btn cp-modal-btn--error" onClick={() => setShowErrorModal(false)}>
<X size={16} /> Fermer
</button>
</div>
</div>
@@ -375,3 +375,9 @@
border-color: rgba(16, 185, 129, 0.3);
color: #10b981;
}
.profile-modal-btn--success {
background: transparent;
border: 1px solid rgba(16, 185, 129, 0.4);
color: #10b981;
}
+50 -25
View File
@@ -27,11 +27,14 @@ export default function ProfilePage() {
const [defaultPhone, setDefaultPhone] = useState(() => localStorage.getItem(STORAGE_PHONE) ?? '');
const [signalPseudo, setSignalPseudo] = useState(() => localStorage.getItem(STORAGE_SIGNAL) ?? '');
// Feedback
const [savingContact, setSavingContact] = useState(false);
const [feedbackModal, setFeedbackModal] = useState<{
show: boolean; type: 'success' | 'error'; title: string; body: string;
}>({ show: false, type: 'success', title: '', body: '' });
// Modals succès / erreur (pattern identique à l'app mobile)
const [showSuccessModal, setShowSuccessModal] = useState(false);
const [successTitle, setSuccessTitle] = useState('');
const [successMsg, setSuccessMsg] = useState('');
const [showErrorModal, setShowErrorModal] = useState(false);
const [errorMsg, setErrorMsg] = useState('');
// Telegram
const [tgLinked, setTgLinked] = useState(false);
@@ -79,13 +82,16 @@ export default function ProfilePage() {
});
}, [navigate]);
const showFeedback = (type: 'success' | 'error', title: string, body: string) => {
setFeedbackModal({ show: true, type, title, body });
const showSuccess = (title: string, msg: string) => {
setSuccessTitle(title); setSuccessMsg(msg); setShowSuccessModal(true);
};
const showError = (msg: string) => {
setErrorMsg(msg); setShowErrorModal(true);
};
const saveAddress = () => {
localStorage.setItem(STORAGE_ADDRESS, defaultAddress.trim());
showFeedback('success', 'Adresse enregistrée', 'Votre adresse par défaut a été sauvegardée et sera pré-remplie à votre prochaine commande.');
showSuccess('Adresse enregistrée', 'Votre adresse par défaut a été sauvegardée et sera pré-remplie à votre prochaine commande.');
};
const saveLocal = () => {
@@ -93,7 +99,7 @@ export default function ProfilePage() {
localStorage.setItem(STORAGE_PHONE, defaultPhone.trim());
localStorage.setItem(STORAGE_SIGNAL, signalPseudo.trim());
setShowSaveModal(false);
showFeedback('success', 'Infos enregistrées', 'Adresse, téléphone et pseudo Signal sauvegardés. Ils seront pré-remplis à votre prochaine commande.');
showSuccess('Infos enregistrées', 'Adresse, téléphone et pseudo Signal sauvegardés. Ils seront pré-remplis à votre prochaine commande.');
};
const handleLinkTelegram = async () => {
@@ -101,7 +107,7 @@ export default function ProfilePage() {
const res = await generateTelegramLinkToken();
setTgLoading(false);
if (res.error || !res.link_url) {
showFeedback('error', 'Telegram indisponible', res.error || 'Service Telegram non disponible');
showError(res.error || 'Service Telegram non disponible');
return;
}
window.open(res.link_url, '_blank');
@@ -126,9 +132,9 @@ export default function ProfilePage() {
setTwoFALoading(false);
if (res.success) {
setTwoFAEnabled(newVal);
showFeedback('success', newVal ? '2FA activée' : '2FA désactivée', newVal ? 'La double authentification est maintenant active. Un code vous sera envoyé sur Telegram à chaque connexion.' : 'La double authentification a été désactivée.');
showSuccess(newVal ? '2FA activée' : '2FA désactivée', newVal ? 'Un code vous sera envoyé sur Telegram à chaque connexion.' : 'La double authentification a été désactivée.');
} else {
showFeedback('error', 'Erreur', res.error || 'Erreur lors de la modification');
showError(res.error || 'Erreur lors de la modification');
}
};
@@ -137,9 +143,9 @@ export default function ProfilePage() {
const res = await updateMyProfile({ nom: nom.trim(), prenom: prenom.trim(), telephone: telephone.trim() });
setSavingContact(false);
if (res.success) {
showFeedback('success', 'Profil mis à jour', 'Vos informations de compte ont été enregistrées avec succès.');
showSuccess('Profil mis à jour', 'Vos informations de compte ont été enregistrées avec succès.');
} else {
showFeedback('error', 'Erreur', res.message ?? 'Erreur lors de la mise à jour du profil.');
showError(res.message ?? 'Erreur lors de la mise à jour du profil.');
}
};
@@ -386,23 +392,42 @@ export default function ProfilePage() {
</div>
)}
{feedbackModal.show && (
<div className="profile-modal-overlay" onClick={() => setFeedbackModal(m => ({ ...m, show: false }))}>
{/* Modal succès */}
{showSuccessModal && (
<div className="profile-modal-overlay" onClick={() => setShowSuccessModal(false)}>
<div className="profile-modal" onClick={(e) => e.stopPropagation()}>
<button className="profile-modal-close" onClick={() => setFeedbackModal(m => ({ ...m, show: false }))}>
<button className="profile-modal-close" onClick={() => setShowSuccessModal(false)}>
<FontAwesomeIcon icon={faTimes} />
</button>
<div className={`profile-modal-icon ${feedbackModal.type === 'error' ? 'profile-modal-icon--danger' : 'profile-modal-icon--success'}`}>
<FontAwesomeIcon icon={feedbackModal.type === 'error' ? faExclamationTriangle : faCheckCircle} />
<div className="profile-modal-icon profile-modal-icon--success">
<FontAwesomeIcon icon={faCheckCircle} />
</div>
<h3 className="profile-modal-title">{feedbackModal.title}</h3>
<p className="profile-modal-body">{feedbackModal.body}</p>
<h3 className="profile-modal-title">{successTitle}</h3>
<p className="profile-modal-body">{successMsg}</p>
<div className="profile-modal-actions">
<button
className={`profile-modal-btn ${feedbackModal.type === 'error' ? 'profile-modal-btn--danger' : 'profile-modal-btn--confirm'}`}
onClick={() => setFeedbackModal(m => ({ ...m, show: false }))}
>
<FontAwesomeIcon icon={faCheckCircle} /> Fermer
<button className="profile-modal-btn profile-modal-btn--confirm profile-modal-btn--success" onClick={() => setShowSuccessModal(false)}>
Fermer
</button>
</div>
</div>
</div>
)}
{/* Modal erreur */}
{showErrorModal && (
<div className="profile-modal-overlay" onClick={() => setShowErrorModal(false)}>
<div className="profile-modal" onClick={(e) => e.stopPropagation()}>
<button className="profile-modal-close" onClick={() => setShowErrorModal(false)}>
<FontAwesomeIcon icon={faTimes} />
</button>
<div className="profile-modal-icon profile-modal-icon--danger">
<FontAwesomeIcon icon={faExclamationTriangle} />
</div>
<h3 className="profile-modal-title">Une erreur est survenue</h3>
<p className="profile-modal-body">{errorMsg}</p>
<div className="profile-modal-actions">
<button className="profile-modal-btn profile-modal-btn--danger" onClick={() => setShowErrorModal(false)}>
Fermer
</button>
</div>
</div>