diff --git a/src/features/rh/components/HRDashboard.jsx b/src/features/rh/components/HRDashboard.jsx index 372a2eb..bb5c949 100644 --- a/src/features/rh/components/HRDashboard.jsx +++ b/src/features/rh/components/HRDashboard.jsx @@ -9,6 +9,7 @@ import { DialogContent, DialogHeader, DialogTitle, + DialogDescription, DialogTrigger, } from "@/components/ui/dialog"; import { useEmployees } from '../hooks/useEmployees'; @@ -91,6 +92,9 @@ export const HRDashboard = () => { {editingRequest ? 'Editar Solicitação' : 'Nova Solicitação de RH'} + + {editingRequest ? 'Atualize os dados da solicitação abaixo.' : 'Preencha os dados para criar uma nova solicitação de RH.'} + { + const [employees, setEmployees] = useState([]); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [statistics, setStatistics] = useState([]); + const [alerts, setAlerts] = useState([]); -/** - * Hook customizado para gestão de colaboradores/solicitações (Padrão Integra Finance). - */ -export const useEmployees = (initialData = []) => { - const [employees, setEmployees] = useState(initialData); + /** + * Busca lista de colaboradores com filtros + */ + const fetchEmployees = useCallback(async (params = {}) => { + setLoading(true); + setError(null); + try { + const response = await rhService.getCollaborators(params); + const rawList = Array.isArray(response) ? response : (response?.data || []); + + // Mapeamento de campos da API para a UI + const mappedEmployees = rawList.map(emp => { + // Cálculo de status CNH baseado na validade + let cnhStatus = 'valida'; + if (emp.validade_cnh) { + const expiry = new Date(emp.validade_cnh); + const now = new Date(); + const diffDays = Math.ceil((expiry - now) / (1000 * 60 * 60 * 24)); + + if (diffDays < 0) cnhStatus = 'vencida'; + else if (diffDays <= 30) cnhStatus = 'proxima_vencer'; + } - const addEmployeeRequest = useCallback((newData) => { - setEmployees((prev) => [ - ...prev, - { ...newData, id: prev.length > 0 ? Math.max(...prev.map(e => e.id)) + 1 : 1 } - ]); + return { + id: emp.idcolaborador || emp.id, + name: emp.colaboradores || emp.nome || emp.name, + email: emp.email_corporativo || emp.email, + phone: emp.telefone, + cpf: emp.cpf_validado || emp.cpf, + role: emp.cargo || emp.role, + department: emp.empresas || emp.department, + status: emp.status_contrato || emp.status || 'Ativo', + cnh_status: cnhStatus, + admissionDate: emp.data_admissao ? new Date(emp.data_admissao).toLocaleDateString() : '-', + pasta: emp.pasta_rh || emp.pasta, + salary: emp.salario, + manager: emp.responsavel_direto_validado || '-' + }; + }); + + setEmployees(mappedEmployees); + return mappedEmployees; + } catch (err) { + setError(err.message); + toast.error('Erro ao carregar colaboradores'); + return []; + } finally { + setLoading(false); + } }, []); - const updateEmployeeRequest = useCallback((id, updatedData) => { - setEmployees((prev) => - prev.map((e) => (e.id === id ? { ...e, ...updatedData } : e)) - ); + /** + * Busca um colaborador por ID + */ + const fetchEmployeeById = useCallback(async (id) => { + try { + const response = await rhService.getCollaboratorById(id); + return response?.data || null; + } catch (err) { + toast.error('Erro ao buscar detalhes do colaborador'); + return null; + } }, []); - const deleteEmployeeRequest = useCallback((id) => { - setEmployees((prev) => prev.filter((e) => e.id !== id)); + /** + * Busca estatísticas de colaboradores + */ + const fetchStatistics = useCallback(async () => { + setLoading(true); + try { + const response = await rhService.getStatistics(); + console.log('RH Stats Response:', response); // Para debug se necessário + + if (!response?.success) { + setStatistics([]); + return null; + } + + const raw = response.data || {}; + + // Mapeamento dos cards superiores + const mappedStats = [ + { + label: 'Total Geral', + value: Number(raw.total || 0), + trend: 'Colaboradores', + color: 'bg-indigo-500/10 text-indigo-500' + }, + { + label: 'Colaboradores Ativos', + value: Number(raw.por_status_contrato?.find(i => i.status_contrato === 'Ativo')?.quantidade || 0), + trend: 'Em operação', + color: 'bg-emerald-500/10 text-emerald-500' + }, + { + label: 'CNH Vencidas', + value: Number(raw.cnh_status?.cnh_vencida || 0), + trend: 'Ação imediata', + color: 'bg-rose-500/10 text-rose-500', + negative: true + }, + { + label: 'CNH a Vencer', + value: Number(raw.cnh_status?.cnh_proxima_vencer || 0), + trend: 'Próximos 30 dias', + color: 'bg-amber-500/10 text-amber-500' + }, + { + label: 'Contas Email Corp.', + value: Number(raw.email_corporativo?.com_email || 0), + trend: 'Acesso liberado', + color: 'bg-blue-500/10 text-blue-500' + }, + { + label: 'Desktops da Empresa', + value: Number(raw.desktop_empresa?.com_desktop || 0), + trend: 'Patrimônio em uso', + color: 'bg-slate-500/10 text-slate-500' + } + ]; + + setStatistics(mappedStats); + + const result = { + stats: mappedStats, + charts: { + por_base: raw.por_base || [], + por_cargo: raw.por_cargo || [], + por_cliente: raw.por_cliente || [], + por_status: raw.por_status_contrato || [], + por_empresa: raw.por_empresa || [] + } + }; + + return result; + } catch (err) { + console.error('Erro ao carregar estatísticas:', err); + setStatistics([]); + return null; + } finally { + setLoading(false); + } + }, []); + + /** + * Busca alertas de colaboradores + */ + const fetchAlerts = useCallback(async () => { + try { + const response = await rhService.getAlerts(); + if (!response?.success) { + setAlerts([]); + return null; + } + + const raw = response.data || {}; + + const mappedAlerts = [ + { + label: 'CNH Vencida AGORA', + value: raw.cnh_vencida?.length || 0, + trend: 'Bloqueio imediato', + color: 'bg-rose-500/10 text-rose-500', + negative: true, + urgent: true + }, + { + label: 'Férias Próximas', + value: raw.ferias_proximas?.length || 0, + trend: 'Próximos 60 dias', + color: 'bg-blue-500/10 text-blue-500' + }, + { + label: 'Falta Telefone', + value: raw.sem_telefone?.length || 0, + trend: 'Contato urgente', + color: 'bg-slate-500/10 text-slate-500', + negative: true + }, + { + label: 'Sem Email Corp.', + value: raw.sem_email_corporativo?.length || 0, + trend: 'Pendência TI', + color: 'bg-amber-500/10 text-amber-500' + } + ]; + + setAlerts(mappedAlerts); + return raw; + } catch (err) { + console.error('Erro ao carregar alertas:', err); + setAlerts([]); + return null; + } + }, []); + + /** + * Atualiza dados de um colaborador + */ + const updateEmployee = useCallback(async (id, payload) => { + setLoading(true); + try { + const response = await rhService.updateCollaborator(id, payload); + if (response?.success) { + toast.success('Alterações salvas com sucesso!'); + await fetchEmployees(); + return response.data; + } + throw new Error(response?.error || 'Erro desconhecido'); + } catch (err) { + toast.error('Erro ao salvar alterações: ' + err.message); + throw err; + } finally { + setLoading(false); + } + }, [fetchEmployees]); + + /** + * Inativar colaborador + */ + const inactivateEmployee = useCallback(async (id) => { + setLoading(true); + try { + const response = await rhService.inactivateCollaborator(id); + if (response?.success) { + toast.success('Colaborador inativado com sucesso.'); + await fetchEmployees(); + return true; + } + throw new Error(response?.error || 'Falha ao inativar'); + } catch (err) { + toast.error(err.message); + return false; + } finally { + setLoading(false); + } + }, [fetchEmployees]); + + /** + * Reativar colaborador + */ + const reactivateEmployee = useCallback(async (id) => { + setLoading(true); + try { + const response = await rhService.reactivateCollaborator(id); + if (response?.success) { + toast.success('Colaborador reativado com sucesso.'); + await fetchEmployees(); + return true; + } + throw new Error(response?.error || 'Falha ao reativar'); + } catch (err) { + toast.error(err.message); + return false; + } finally { + setLoading(false); + } + }, [fetchEmployees]); + + /** + * Chat / Busca Inteligente + */ + const searchInChat = useCallback(async (pergunta) => { + try { + const response = await rhService.searchChat(pergunta); + return response; + } catch (err) { + toast.error('Erro na busca inteligente'); + return null; + } }, []); return { employees, - addEmployeeRequest, - updateEmployeeRequest, - deleteEmployeeRequest, + loading, + error, + statistics, + alerts, + fetchEmployees, + fetchEmployeeById, + fetchStatistics, + fetchAlerts, + updateEmployee, + inactivateEmployee, + reactivateEmployee, + searchInChat, setEmployees }; };