chore: build
This commit is contained in:
@@ -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 été 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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user