feat: implement real user profile and authentication state
All checks were successful
Build and Deploy / build-and-push (push) Successful in 2m3s

This commit is contained in:
Cauê Faleiros
2026-02-26 10:36:59 -03:00
parent dda606ef9b
commit 6fb86b4806

View File

@@ -1,10 +1,11 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Camera, Save, Mail, User as UserIcon, Building, Shield, Loader2, CheckCircle2 } from 'lucide-react'; import { Camera, Save, Mail, User as UserIcon, Building, Shield, Loader2, CheckCircle2 } from 'lucide-react';
import { getUserById } from '../services/dataService'; import { getUserById, getTenants } from '../services/dataService';
import { User } from '../types'; import { User, Tenant } from '../types';
export const UserProfile: React.FC = () => { export const UserProfile: React.FC = () => {
const [user, setUser] = useState<User | null>(null); const [user, setUser] = useState<User | null>(null);
const [tenant, setTenant] = useState<Tenant | null>(null);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [isSuccess, setIsSuccess] = useState(false); const [isSuccess, setIsSuccess] = useState(false);
@@ -12,22 +13,29 @@ export const UserProfile: React.FC = () => {
const [bio, setBio] = useState(''); const [bio, setBio] = useState('');
useEffect(() => { useEffect(() => {
const fetchUser = async () => { const fetchUserAndTenant = async () => {
const storedId = localStorage.getItem('ctms_user_id'); const storedUserId = localStorage.getItem('ctms_user_id');
if (storedId) { if (storedUserId) {
try { try {
const fetchedUser = await getUserById(storedId); const fetchedUser = await getUserById(storedUserId);
if (fetchedUser) { if (fetchedUser) {
setUser(fetchedUser); setUser(fetchedUser);
setName(fetchedUser.name); setName(fetchedUser.name);
setBio(fetchedUser.bio || ''); setBio(fetchedUser.bio || '');
// Fetch tenant info
const tenants = await getTenants();
const userTenant = tenants.find(t => t.id === fetchedUser.tenant_id);
if (userTenant) {
setTenant(userTenant);
}
} }
} catch (err) { } catch (err) {
console.error("Error fetching profile:", err); console.error("Error fetching profile data:", err);
} }
} }
}; };
fetchUser(); fetchUserAndTenant();
}, []); }, []);
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = (e: React.FormEvent) => {
@@ -59,7 +67,7 @@ export const UserProfile: React.FC = () => {
<div className="bg-white p-6 rounded-2xl shadow-sm border border-slate-200 flex flex-col items-center text-center"> <div className="bg-white p-6 rounded-2xl shadow-sm border border-slate-200 flex flex-col items-center text-center">
<div className="relative group cursor-pointer"> <div className="relative group cursor-pointer">
<div className="w-32 h-32 rounded-full overflow-hidden border-4 border-slate-50 shadow-sm"> <div className="w-32 h-32 rounded-full overflow-hidden border-4 border-slate-50 shadow-sm">
<img src={user.avatar_url} alt={user.name} className="w-full h-full object-cover" /> <img src={user.avatar_url || `https://ui-avatars.com/api/?name=${encodeURIComponent(user.name)}&background=random`} alt={user.name} className="w-full h-full object-cover" />
</div> </div>
<div className="absolute inset-0 bg-black/40 rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-200"> <div className="absolute inset-0 bg-black/40 rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-200">
<Camera className="text-white" size={28} /> <Camera className="text-white" size={28} />
@@ -76,21 +84,23 @@ export const UserProfile: React.FC = () => {
<span className="px-3 py-1 bg-purple-100 text-purple-700 rounded-full text-xs font-semibold capitalize border border-purple-200"> <span className="px-3 py-1 bg-purple-100 text-purple-700 rounded-full text-xs font-semibold capitalize border border-purple-200">
{user.role} {user.role}
</span> </span>
<span className="px-3 py-1 bg-blue-100 text-blue-700 rounded-full text-xs font-semibold border border-blue-200"> {user.team_id && (
{user.team_id === 'sales_1' ? 'Vendas Alpha' : 'Vendas Beta'} <span className="px-3 py-1 bg-blue-100 text-blue-700 rounded-full text-xs font-semibold border border-blue-200">
</span> {user.team_id === 'sales_1' ? 'Vendas Alpha' : user.team_id === 'sales_2' ? 'Vendas Beta' : user.team_id}
</span>
)}
</div> </div>
</div> </div>
<div className="bg-slate-100 rounded-xl p-4 border border-slate-200"> <div className="bg-slate-100 rounded-xl p-4 border border-slate-200">
<h3 className="text-xs font-bold text-slate-500 uppercase tracking-wider mb-3">Status da Conta</h3> <h3 className="text-xs font-bold text-slate-500 uppercase tracking-wider mb-3">Status da Conta</h3>
<div className="flex items-center gap-3 text-sm text-slate-600 mb-2"> <div className="flex items-center gap-3 text-sm text-slate-600 mb-2">
<div className="w-2 h-2 rounded-full bg-green-500"></div> <div className={`w-2 h-2 rounded-full ${user.status === 'active' ? 'bg-green-500' : 'bg-slate-400'}`}></div>
Ativo {user.status === 'active' ? 'Ativo' : 'Inativo'}
</div> </div>
<div className="flex items-center gap-3 text-sm text-slate-600"> <div className="flex items-center gap-3 text-sm text-slate-600">
<Building size={14} /> <Building size={14} />
Fasto Corp (Organização) {tenant?.name || 'Organização'}
</div> </div>
</div> </div>
</div> </div>