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 { Camera, Save, Mail, User as UserIcon, Building, Shield, Loader2, CheckCircle2 } from 'lucide-react';
import { getUserById } from '../services/dataService';
import { User } from '../types';
import { getUserById, getTenants } from '../services/dataService';
import { User, Tenant } from '../types';
export const UserProfile: React.FC = () => {
const [user, setUser] = useState<User | null>(null);
const [tenant, setTenant] = useState<Tenant | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [isSuccess, setIsSuccess] = useState(false);
@@ -12,22 +13,29 @@ export const UserProfile: React.FC = () => {
const [bio, setBio] = useState('');
useEffect(() => {
const fetchUser = async () => {
const storedId = localStorage.getItem('ctms_user_id');
if (storedId) {
const fetchUserAndTenant = async () => {
const storedUserId = localStorage.getItem('ctms_user_id');
if (storedUserId) {
try {
const fetchedUser = await getUserById(storedId);
const fetchedUser = await getUserById(storedUserId);
if (fetchedUser) {
setUser(fetchedUser);
setName(fetchedUser.name);
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) {
console.error("Error fetching profile:", err);
console.error("Error fetching profile data:", err);
}
}
};
fetchUser();
fetchUserAndTenant();
}, []);
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="relative group cursor-pointer">
<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 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} />
@@ -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">
{user.role}
</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 === 'sales_1' ? 'Vendas Alpha' : 'Vendas Beta'}
</span>
{user.team_id && (
<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 === 'sales_1' ? 'Vendas Alpha' : user.team_id === 'sales_2' ? 'Vendas Beta' : user.team_id}
</span>
)}
</div>
</div>
<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>
<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>
Ativo
<div className={`w-2 h-2 rounded-full ${user.status === 'active' ? 'bg-green-500' : 'bg-slate-400'}`}></div>
{user.status === 'active' ? 'Ativo' : 'Inativo'}
</div>
<div className="flex items-center gap-3 text-sm text-slate-600">
<Building size={14} />
Fasto Corp (Organização)
{tenant?.name || 'Organização'}
</div>
</div>
</div>