import { create } from 'zustand'; import { rhService } from '../services/rhService'; import { useRhFeedbackStore } from '../components/RhFeedbackNotification'; const notify = (type, title, message) => useRhFeedbackStore.getState().notify(type, title, message); /** * Hook customizado para gestão de colaboradores (Padrão Integra Finance - ZUSTAND). * Centraliza toda a lógica de negócio e comunicação com a API de colaboradores. * Agora utiliza Zustand para compartilhamento de estado entre componentes. */ export const useEmployees = create((set, get) => ({ employees: [], loading: false, error: null, statistics: [], alerts: [], /** * Busca lista de colaboradores com filtros */ fetchEmployees: async (params = {}) => { set({ loading: true, error: 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 (expiry.getFullYear() < 1900) cnhStatus = 'valida'; // Fallback para datas zeradas ou inválidas else if (diffDays < 0) cnhStatus = 'vencida'; else if (diffDays <= 30) cnhStatus = 'proxima_vencer'; } return { id: emp.idcolaborador || emp.id, idcolaborador: emp.idcolaborador, name: emp.colaboradores || emp.nome || emp.name, email: emp.email_corporativo || emp.email, phone: emp.telefone, cpf: 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 || '-', // Manter os dados brutos para preenchimento de formulários ...emp }; }); set({ employees: mappedEmployees }); return mappedEmployees; } catch (err) { set({ error: err.message }); notify('error', 'Falha na Busca', 'Erro ao carregar colaboradores: ' + err.message); return []; } finally { set({ loading: false }); } }, /** * Busca um colaborador por ID */ fetchEmployeeById: async (id) => { try { const response = await rhService.getCollaboratorById(id); if (response?.success && response?.data) { return response.data; } else if (response?.data) { return response.data; } else if (response && typeof response === 'object') { return response; } return null; } catch (err) { notify('error', 'Erro de Detalhes', 'Não foi possível buscar os dados completos do colaborador.'); return null; } }, /** * Busca estatísticas de colaboradores */ fetchStatistics: async () => { set({ loading: true }); try { const response = await rhService.getStatistics(); let raw = {}; if (response?.success && response?.data) { raw = response.data; } else if (response?.data) { raw = response.data; } else if (response && typeof response === 'object') { raw = response; } else { set({ statistics: [] }); return null; } 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' } ]; set({ statistics: mappedStats }); return { 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 || [] } }; } catch (err) { set({ statistics: [] }); return null; } finally { set({ loading: false }); } }, /** * Busca alertas de colaboradores */ fetchAlerts: async () => { try { const response = await rhService.getAlerts(); let raw = {}; if (response?.success && response?.data) { raw = response.data; } else if (response?.data) { raw = response.data; } else if (response && typeof response === 'object') { raw = response; } else { set({ alerts: [] }); return null; } const mappedAlerts = [ { label: 'CNH Vencida AGORA', value: Array.isArray(raw.cnh_vencida) ? raw.cnh_vencida.length : 0, trend: 'Bloqueio imediato', color: 'bg-rose-500/10 text-rose-500', negative: true, urgent: true }, { label: 'CNH a Vencer', value: Array.isArray(raw.cnh_proxima_vencer) ? raw.cnh_proxima_vencer.length : 0, trend: 'Próximos 30 dias', color: 'bg-amber-500/10 text-amber-500' }, { label: 'Férias Próximas', value: Array.isArray(raw.ferias_proximas) ? raw.ferias_proximas.length : 0, trend: 'Próximos 60 dias', color: 'bg-blue-500/10 text-blue-500' }, { label: 'Falta Telefone', value: Array.isArray(raw.sem_telefone) ? raw.sem_telefone.length : 0, trend: 'Contato urgente', color: 'bg-slate-500/10 text-slate-500', negative: true }, { label: 'Sem Email Corp.', value: Array.isArray(raw.sem_email_corporativo) ? raw.sem_email_corporativo.length : 0, trend: 'Pendência TI', color: 'bg-amber-500/10 text-amber-500' } ]; set({ alerts: mappedAlerts }); return raw; } catch (err) { set({ alerts: [] }); return null; } }, /** * Cria um novo colaborador */ createEmployee: async (payload) => { set({ loading: true }); try { const response = await rhService.createCollaborator(payload); if (response?.success || (response && !response.error)) { notify('success', 'Cadastro Concluído', 'O colaborador foi registrado com sucesso na base de dados.'); await get().fetchEmployees(); return true; } throw new Error(response?.error || 'Erro desconhecido'); } catch (err) { notify('error', 'Falha no Cadastro', err.message); return false; } finally { set({ loading: false }); } }, /** * Atualiza dados de um colaborador */ updateEmployee: async (id, payload) => { set({ loading: true }); try { const response = await rhService.updateCollaborator(id, payload); if (response?.success || (response && !response.error)) { notify('success', 'Registro Atualizado', 'As alterações foram salvas com sucesso.'); await get().fetchEmployees(); return true; } throw new Error(response?.error || 'Erro desconhecido'); } catch (err) { notify('error', 'Erro na Atualização', err.message); return false; } finally { set({ loading: false }); } }, /** * Inativar colaborador */ inactivateEmployee: async (id) => { set({ loading: true }); try { const response = await rhService.inactivateCollaborator(id); if (response?.success) { notify('success', 'Status Alterado', 'O colaborador foi inativado com sucesso.'); await get().fetchEmployees(); return true; } throw new Error(response?.error || 'Falha ao inativar'); } catch (err) { notify('error', 'Erro de Operação', err.message); return false; } finally { set({ loading: false }); } }, /** * Reativar colaborador */ reactivateEmployee: async (id) => { set({ loading: true }); try { const response = await rhService.reactivateCollaborator(id); if (response?.success) { notify('success', 'Status Alterado', 'O colaborador foi reativado com sucesso.'); await get().fetchEmployees(); return true; } throw new Error(response?.error || 'Falha ao reativar'); } catch (err) { notify('error', 'Erro de Operação', err.message); return false; } finally { set({ loading: false }); } }, /** * Chat / Busca Inteligente */ searchInChat: async (pergunta) => { try { const response = await rhService.searchChat(pergunta); return response; } catch (err) { notify('error', 'Erro na IA', 'Não foi possível completar a consulta inteligente.'); return null; } }, setEmployees: (employees) => set({ employees }) }));