// screens-profile.jsx — profile + reviews + my profile // Helpers : adapte un user qui peut venir du mock (objects bilingues) OU de l'API (strings) function userName(u, lang) { if (!u) return ''; if (typeof u.name === 'object' && u.name !== null) return u.name[lang] || u.name.fr || ''; return u.name || ''; } function userLocation(u, lang) { if (!u) return ''; if (u.city) return u.city; if (typeof u.location === 'object' && u.location !== null) return u.location[lang] || u.location.fr || ''; return u.location || ''; } function userBio(u, lang) { if (!u) return ''; if (typeof u.bio === 'object' && u.bio !== null) return u.bio[lang] || u.bio.fr || ''; return u.bio || ''; } function userPhoto(u) { return (u && (u.profile_photo || u.avatar)) || null; } function memberSinceLabel(u, lang) { if (!u || !u.created_at) return null; const d = new Date(u.created_at); if (isNaN(d.getTime())) return null; const year = d.getFullYear(); return lang === 'ka' ? `წევრი ${year}-დან` : `Membre depuis ${year}`; } function ProfileScreen({ user, lang, t, onBack, onOpenChat, onLeaveReview, isMe = false, onOpenReferral, onLogout, onOpenMyListings, onOpenFavorites, onOpenAbout, onOpenContact, onOpenPrivacy, onOpenTerms, onOpenDeleteAccount, onOpenBlocked }) { const [showReport, setShowReport] = React.useState(false); const [showBlock, setShowBlock] = React.useState(false); // En mode "isMe", on utilise toujours le user réel du localStorage (ignore le prop user mock) const realUser = isMe ? (window.TrustaAuth && window.TrustaAuth.getUser()) || null : user; if (!realUser) { return (
{lang === 'ka' ? 'იტვირთება…' : 'Chargement…'}
); } const name = userName(realUser, lang); const location = userLocation(realUser, lang); const photo = userPhoto(realUser); const bio = userBio(realUser, lang); const memberSince = memberSinceLabel(realUser, lang); const verified = !!realUser.verified; // Stats : seulement si le user a des données réelles (pour l'instant aucune) const hasStats = (realUser.missions != null && realUser.missions > 0) || (realUser.recommend != null); const hasReviews = realUser.reviewCount && realUser.reviewCount > 0; const hasRating = realUser.rating != null && realUser.rating > 0; const handleLogout = async () => { if (!window.TrustaAPI) return; try { await window.TrustaAPI.logout(); } catch (e) {} if (onLogout) onLogout(); else window.location.reload(); }; return (
{!isMe && realUser && realUser.id && ( )}
} />
{name || (lang === 'ka' ? 'უსახელო' : 'Sans nom')}
{verified && (
)}
{(location || memberSince) && (
{location && ( <> {location} )} {location && memberSince && ' · '} {memberSince}
)} {hasRating && (
{realUser.rating} ({realUser.reviewCount} {t('reviews')})
)}
{/* Stats — seulement si le user a des données réelles */} {hasStats && (
{[ { val: realUser.missions || 0, label: t('missions_done') }, { val: realUser.years || 0, label: t('years_active') }, { val: (realUser.recommend || 0) + '%', label: t('recommendation') }, ].map((s, i) => (
0 ? `1px solid ${COLORS.borderSoft}` : 'none' }}>
{s.val}
{s.label}
))}
)} {/* Bio */} {bio && (
{bio}
)} {/* Empty state pour profil neuf */} {isMe && !bio && !hasReviews && !hasStats && (
{lang === 'ka' ? 'შენი პროფილი ჯერ ცარიელია. შექმენი განცხადება, რომ თემამ გაგიცნოს.' : 'Ton profil est encore vide. Crée une annonce pour que la communauté te découvre.'}
)} {/* Reviews — seulement si vraies reviews */} {hasReviews && window.REVIEWS && window.REVIEWS[realUser.id] && (
{t('reviews_section')}
{t('view_all')}
{window.REVIEWS[realUser.id].slice(0, 2).map((r, i) => { const author = window.MEMBERS && window.MEMBERS[r.author]; if (!author) return null; return (
{userName(author, lang)}
{r.date}
{r.text[lang]}
); })}
)} {!isMe && (
)} {isMe && (
{/* Section légale & support (pages requises App Store / Google Play) */}
{lang === 'ka' ? 'ინფორმაცია' : 'Informations'}
{onOpenAbout && ( )} {onOpenContact && ( )} {onOpenPrivacy && ( )} {onOpenTerms && ( )} {onOpenBlocked && ( )} {/* Suppression de compte — obligatoire Apple/Google. Rouge pour signaler la criticité */} {onOpenDeleteAccount && ( )}
TRUSTA · v1.0 · trusta.click
)}
{!isMe && onOpenChat && (
{onLeaveReview && {t('leave_review')}} onOpenChat(realUser)}>{t('message_btn')}
)} {/* Modals signaler / bloquer */} {showReport && window.ReportModal && ( setShowReport(false)} /> )} {showBlock && window.BlockUserModal && ( setShowBlock(false)} onBlocked={() => { // Une fois bloqué, retour à l'accueil (on ne devrait plus voir ce profil) if (onBack) onBack(); }} /> )}
); } function menuRowStyle() { return { display: 'flex', alignItems: 'center', gap: 12, padding: '14px 14px', background: COLORS.card, borderRadius: 12, border: `1px solid ${COLORS.borderSoft}`, color: '#fff', fontFamily: 'Inter', fontSize: 14, fontWeight: 500, cursor: 'pointer', textAlign: 'left', }; } function menuIconStyle() { return { width: 28, height: 28, borderRadius: 8, background: COLORS.goldSoft, display: 'flex', alignItems: 'center', justifyContent: 'center', }; } function ReviewModal({ user, lang, t, onClose }) { const [stars, setStars] = React.useState(5); const [text, setText] = React.useState(''); const [sent, setSent] = React.useState(false); return (
{sent ? (
{lang === 'ka' ? 'გმადლობთ!' : 'Merci !'}
{lang === 'ka' ? 'შეფასება გაგზავნილია' : 'Votre avis a été envoyé'}
) : (
{userName(user, lang)}
{t('how_was')}
{[1, 2, 3, 4, 5].map(i => ( ))}
{t('comment')}