chore: update
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import Navbar from '../../components/Navbar';
|
||||
import { isUserAuthenticated, extractUsernameFromToken, getMyProfile, updateMyProfile } from '../../api/api';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import {
|
||||
faUser, faMapMarkerAlt, faPhone, faCommentDots,
|
||||
faSave, faCheckCircle, faExclamationTriangle,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import './ProfilePage.css';
|
||||
|
||||
const STORAGE_ADDRESS = 'profile_default_address';
|
||||
const STORAGE_PHONE = 'profile_default_phone';
|
||||
const STORAGE_SIGNAL = 'profile_signal_pseudo';
|
||||
|
||||
export default function ProfilePage() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Données compte (backend)
|
||||
const [nom, setNom] = useState('');
|
||||
const [prenom, setPrenom] = useState('');
|
||||
const [telephone, setTelephone] = useState('');
|
||||
const [loadingProfile, setLoadingProfile] = useState(true);
|
||||
|
||||
// Données locales (localStorage)
|
||||
const [defaultAddress, setDefaultAddress] = useState('');
|
||||
const [defaultPhone, setDefaultPhone] = useState('');
|
||||
const [signalPseudo, setSignalPseudo] = useState('');
|
||||
|
||||
// Feedback
|
||||
const [savingContact, setSavingContact] = useState(false);
|
||||
const [successMsg, setSuccessMsg] = useState('');
|
||||
const [errorMsg, setErrorMsg] = useState('');
|
||||
|
||||
const username = extractUsernameFromToken() ?? '';
|
||||
|
||||
useEffect(() => {
|
||||
if (!isUserAuthenticated()) {
|
||||
navigate('/login/client', { replace: true });
|
||||
return;
|
||||
}
|
||||
// Charger depuis localStorage
|
||||
setDefaultAddress(localStorage.getItem(STORAGE_ADDRESS) ?? '');
|
||||
setDefaultPhone(localStorage.getItem(STORAGE_PHONE) ?? '');
|
||||
setSignalPseudo(localStorage.getItem(STORAGE_SIGNAL) || username);
|
||||
|
||||
// Charger depuis backend
|
||||
getMyProfile().then((res) => {
|
||||
if (res.success && res.client) {
|
||||
setNom(res.client.nom ?? '');
|
||||
setPrenom(res.client.prenom ?? '');
|
||||
setTelephone(res.client.telephone ?? '');
|
||||
// Initialiser le téléphone par défaut si pas encore défini
|
||||
if (!localStorage.getItem(STORAGE_PHONE) && res.client.telephone) {
|
||||
setDefaultPhone(res.client.telephone);
|
||||
}
|
||||
}
|
||||
setLoadingProfile(false);
|
||||
});
|
||||
}, [navigate]);
|
||||
|
||||
const showSuccess = (msg: string) => {
|
||||
setSuccessMsg(msg);
|
||||
setErrorMsg('');
|
||||
setTimeout(() => setSuccessMsg(''), 3000);
|
||||
};
|
||||
const showError = (msg: string) => {
|
||||
setErrorMsg(msg);
|
||||
setSuccessMsg('');
|
||||
setTimeout(() => setErrorMsg(''), 4000);
|
||||
};
|
||||
|
||||
const saveLocal = () => {
|
||||
localStorage.setItem(STORAGE_ADDRESS, defaultAddress.trim());
|
||||
localStorage.setItem(STORAGE_PHONE, defaultPhone.trim());
|
||||
localStorage.setItem(STORAGE_SIGNAL, signalPseudo.trim());
|
||||
showSuccess('Informations par défaut enregistrées');
|
||||
};
|
||||
|
||||
const saveContact = async () => {
|
||||
setSavingContact(true);
|
||||
const res = await updateMyProfile({ nom: nom.trim(), prenom: prenom.trim(), telephone: telephone.trim() });
|
||||
setSavingContact(false);
|
||||
if (res.success) {
|
||||
showSuccess('Profil mis à jour');
|
||||
} else {
|
||||
showError(res.message ?? 'Erreur lors de la mise à jour');
|
||||
}
|
||||
};
|
||||
|
||||
if (loadingProfile) {
|
||||
return (
|
||||
<>
|
||||
<Navbar />
|
||||
<div className="profile-container">
|
||||
<div className="profile-loading"><div className="spinner" /></div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Navbar />
|
||||
<div className="profile-container">
|
||||
<div className="profile-header">
|
||||
<div className="profile-avatar">
|
||||
<FontAwesomeIcon icon={faUser} />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="profile-title">Mon Profil</h1>
|
||||
<p className="profile-username">@{username}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{successMsg && (
|
||||
<div className="profile-alert profile-alert--success">
|
||||
<FontAwesomeIcon icon={faCheckCircle} /> {successMsg}
|
||||
</div>
|
||||
)}
|
||||
{errorMsg && (
|
||||
<div className="profile-alert profile-alert--error">
|
||||
<FontAwesomeIcon icon={faExclamationTriangle} /> {errorMsg}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Section compte */}
|
||||
<div className="profile-card">
|
||||
<h2 className="profile-card-title">
|
||||
<FontAwesomeIcon icon={faUser} className="profile-card-icon" />
|
||||
Mon compte
|
||||
</h2>
|
||||
<div className="profile-fields">
|
||||
<div className="profile-row">
|
||||
<div className="profile-group">
|
||||
<label>Prénom</label>
|
||||
<input
|
||||
type="text"
|
||||
value={prenom}
|
||||
onChange={(e) => setPrenom(e.target.value)}
|
||||
placeholder="Votre prénom"
|
||||
/>
|
||||
</div>
|
||||
<div className="profile-group">
|
||||
<label>Nom</label>
|
||||
<input
|
||||
type="text"
|
||||
value={nom}
|
||||
onChange={(e) => setNom(e.target.value)}
|
||||
placeholder="Votre nom"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="profile-group">
|
||||
<label>Téléphone (compte)</label>
|
||||
<input
|
||||
type="tel"
|
||||
value={telephone}
|
||||
onChange={(e) => setTelephone(e.target.value)}
|
||||
placeholder="+33 6 12 34 56 78"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button className="profile-btn" onClick={saveContact} disabled={savingContact}>
|
||||
<FontAwesomeIcon icon={faSave} />
|
||||
{savingContact ? ' Enregistrement...' : ' Enregistrer le compte'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Section adresse par défaut */}
|
||||
<div className="profile-card">
|
||||
<h2 className="profile-card-title">
|
||||
<FontAwesomeIcon icon={faMapMarkerAlt} className="profile-card-icon profile-card-icon--address" />
|
||||
Adresse par défaut
|
||||
</h2>
|
||||
<p className="profile-hint">
|
||||
Sera pré-remplie dans le formulaire de commande. Vous pourrez la modifier si vous n'êtes pas à cette adresse.
|
||||
</p>
|
||||
<div className="profile-group">
|
||||
<label>Adresse</label>
|
||||
<input
|
||||
type="text"
|
||||
value={defaultAddress}
|
||||
onChange={(e) => setDefaultAddress(e.target.value)}
|
||||
placeholder="Numéro, rue, ville, code postal"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Section contact commande */}
|
||||
<div className="profile-card">
|
||||
<h2 className="profile-card-title">
|
||||
<FontAwesomeIcon icon={faPhone} className="profile-card-icon profile-card-icon--phone" />
|
||||
Contact livraison
|
||||
</h2>
|
||||
<p className="profile-hint">
|
||||
Numéro utilisé par le livreur lors de la livraison. Peut être différent du numéro de votre compte.
|
||||
</p>
|
||||
<div className="profile-group">
|
||||
<label>Téléphone par défaut</label>
|
||||
<input
|
||||
type="tel"
|
||||
value={defaultPhone}
|
||||
onChange={(e) => setDefaultPhone(e.target.value)}
|
||||
placeholder="+33 6 12 34 56 78"
|
||||
/>
|
||||
</div>
|
||||
<div className="profile-group" style={{ marginTop: '1rem' }}>
|
||||
<label>
|
||||
<FontAwesomeIcon icon={faCommentDots} style={{ marginRight: '0.4rem' }} />
|
||||
Pseudo Signal (optionnel)
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={signalPseudo}
|
||||
onChange={(e) => setSignalPseudo(e.target.value)}
|
||||
placeholder="@votre.pseudo.signal"
|
||||
/>
|
||||
</div>
|
||||
<button className="profile-btn profile-btn--secondary" onClick={saveLocal}>
|
||||
<FontAwesomeIcon icon={faSave} /> Enregistrer les infos par défaut
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user