feat: implement real user profile and authentication state
All checks were successful
Build and Deploy / build-and-push (push) Successful in 2m3s
All checks were successful
Build and Deploy / build-and-push (push) Successful in 2m3s
This commit is contained in:
@@ -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>
|
||||||
|
{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">
|
<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'}
|
{user.team_id === 'sales_1' ? 'Vendas Alpha' : user.team_id === 'sales_2' ? 'Vendas Beta' : user.team_id}
|
||||||
</span>
|
</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>
|
||||||
|
|||||||
Reference in New Issue
Block a user