feat: add 2FA and change title

This commit is contained in:
2026-05-09 15:17:19 +02:00
parent 771f514af3
commit 1672dc1e20
19 changed files with 622 additions and 62 deletions
+55 -2
View File
@@ -1,11 +1,11 @@
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import Navbar from '../../components/Navbar';
import { isUserAuthenticated, extractUsernameFromToken, getMyProfile, updateMyProfile, getTelegramStatus, generateTelegramLinkToken, unlinkTelegram } from '../../api/api';
import { isUserAuthenticated, extractUsernameFromToken, getMyProfile, updateMyProfile, getTelegramStatus, generateTelegramLinkToken, unlinkTelegram, get2FAStatus, toggle2FA, getPublicSettings } from '../../api/api';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faUser, faMapMarkerAlt, faPhone, faCommentDots,
faSave, faCheckCircle, faExclamationTriangle, faPaperPlane, faUnlink, faTimes, faLock,
faSave, faCheckCircle, faExclamationTriangle, faPaperPlane, faUnlink, faTimes, faLock, faShieldAlt,
} from '@fortawesome/free-solid-svg-icons';
import './ProfilePage.css';
@@ -37,6 +37,11 @@ export default function ProfilePage() {
const [tgEnabled, setTgEnabled] = useState(false);
const [tgLoading, setTgLoading] = useState(false);
// 2FA
const [twoFAEnabled, setTwoFAEnabled] = useState(false);
const [twoFAAdminEnabled, setTwoFAAdminEnabled] = useState(false);
const [twoFALoading, setTwoFALoading] = useState(false);
// Modal confirmation infos par défaut
const [showSaveModal, setShowSaveModal] = useState(false);
@@ -50,6 +55,12 @@ export default function ProfilePage() {
// Statut Telegram
getTelegramStatus().then((s) => { setTgLinked(s.linked); setTgEnabled(s.enabled); });
// Statut 2FA
Promise.all([get2FAStatus(), getPublicSettings()]).then(([status, pub]) => {
setTwoFAEnabled(status.two_fa_enabled);
setTwoFAAdminEnabled(pub.two_fa_enabled);
});
// Charger depuis backend
getMyProfile().then((res) => {
if (res.success && res.client) {
@@ -99,9 +110,23 @@ export default function ProfilePage() {
if (!window.confirm('Délier votre compte Telegram ? Vous ne recevrez plus de notifications.')) return;
await unlinkTelegram();
setTgLinked(false);
setTwoFAEnabled(false);
showSuccess('Compte Telegram délié');
};
const handleToggle2FA = async () => {
const newVal = !twoFAEnabled;
setTwoFALoading(true);
const res = await toggle2FA(newVal);
setTwoFALoading(false);
if (res.success) {
setTwoFAEnabled(newVal);
showSuccess(newVal ? 'Double authentification activée' : 'Double authentification désactivée');
} else {
showError(res.error || 'Erreur lors de la modification');
}
};
const saveContact = async () => {
setSavingContact(true);
const res = await updateMyProfile({ nom: nom.trim(), prenom: prenom.trim(), telephone: telephone.trim() });
@@ -276,6 +301,34 @@ export default function ProfilePage() {
)}
</div>
)}
{/* Section 2FA — visible uniquement si l'admin l'a activé ET Telegram est lié */}
{twoFAAdminEnabled && tgLinked && (
<div className="profile-card">
<h2 className="profile-card-title">
<FontAwesomeIcon icon={faShieldAlt} className="profile-card-icon" style={{ color: '#6366f1' }} />
Double authentification (2FA)
</h2>
<p className="profile-hint">
À chaque connexion, un code vous sera envoyé sur Telegram avant d'accéder à votre compte.
</p>
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem', marginTop: '0.8rem' }}>
<button
className={`profile-btn ${twoFAEnabled ? 'profile-btn--danger' : 'profile-btn--telegram'}`}
onClick={handleToggle2FA}
disabled={twoFALoading}
>
<FontAwesomeIcon icon={faShieldAlt} />
{twoFALoading ? ' ...' : twoFAEnabled ? ' Désactiver la 2FA' : ' Activer la 2FA'}
</button>
{twoFAEnabled && (
<span style={{ color: '#10b981', fontSize: '0.9rem' }}>
<FontAwesomeIcon icon={faCheckCircle} /> Activée
</span>
)}
</div>
</div>
)}
</div>
{showSaveModal && (