/** * Tipos para usuarios de Dolibarr */ // Respuesta cruda de la API de Dolibarr para usuarios export interface DolibarrUser { id: string; ref: string; login: string; entity: string; // Información personal firstname: string | null; lastname: string; gender: string | null; birth: string; civility_id: string | null; civility_code: string | null; // Contacto email: string | null; email_oauth2: string | null; personal_email: string | null; office_phone: string | null; office_fax: string | null; user_mobile: string | null; personal_mobile: string | null; // Dirección address: string | null; zip: string | null; town: string | null; country_id: string; country_code: string; state_id: string; // Trabajo employee: string; job: string | null; salary: string | null; salaryextra: string | null; weeklyhours: string | null; thm: string | null; // taux horaire moyen tjm: string | null; // taux journalier moyen dateemployment: string; dateemploymentend: string; ref_employee: string | null; fk_establishment: string; label_establishment: string | null; // Estado y permisos status: string; statut: string; admin: string; // Empresa/Tercero asociado socid: string | null; // Sesión y actividad datelastlogin: number | null; datepreviouslogin: string; iplastlogin: string | null; ippreviouslogin: string | null; datestartvalidity: string; dateendvalidity: string; // Otros photo: string | null; lang: string | null; color: string | null; signature: string | null; national_registration_number: string | null; // Metadatos date_creation: string | null; date_modification: string | null; datec: string; datem: number | null; // Social socialnetworks: Record | string[]; // Configuración rights: DolibarrUserRights; conf: Record; array_options: Record | unknown[]; } export interface DolibarrUserRights { user?: { user?: Record; self?: Record; user_advance?: Record; self_advance?: Record; group_advance?: Record; }; [key: string]: unknown; } // Tipo UI para mostrar en la aplicación export interface UserProfile { id: string; login: string; // Nombre completo firstname: string; lastname: string; fullName: string; initials: string; // Contacto email: string | null; personalEmail: string | null; phone: string | null; mobile: string | null; // Ubicación address: string | null; city: string | null; postalCode: string | null; country: string | null; // Trabajo job: string | null; isEmployee: boolean; employmentStartDate: Date | null; employmentEndDate: Date | null; establishment: string | null; // Estado isActive: boolean; isAdmin: boolean; // Actividad lastLogin: Date | null; lastLoginIp: string | null; // Otros photo: string | null; language: string | null; // Datos crudos para campos adicionales raw: DolibarrUser; } /** * Mapea respuesta de Dolibarr a tipo UI */ export function mapDolibarrUser(raw: DolibarrUser): UserProfile { const firstname = raw.firstname || ''; const lastname = raw.lastname || ''; const fullName = [firstname, lastname].filter(Boolean).join(' ') || raw.login; // Generar iniciales const initials = firstname && lastname ? `${firstname.charAt(0)}${lastname.charAt(0)}`.toUpperCase() : fullName.substring(0, 2).toUpperCase(); return { id: raw.id, login: raw.login, firstname, lastname, fullName, initials, email: raw.email, personalEmail: raw.personal_email, phone: raw.office_phone, mobile: raw.user_mobile || raw.personal_mobile, address: raw.address, city: raw.town, postalCode: raw.zip, country: raw.country_code || null, job: raw.job, isEmployee: raw.employee === '1', employmentStartDate: raw.dateemployment ? new Date(raw.dateemployment) : null, employmentEndDate: raw.dateemploymentend ? new Date(raw.dateemploymentend) : null, establishment: raw.label_establishment, isActive: raw.status === '1', isAdmin: raw.admin === '1', lastLogin: raw.datelastlogin ? new Date(raw.datelastlogin * 1000) : null, lastLoginIp: raw.iplastlogin, photo: raw.photo, language: raw.lang, raw, }; } /** * Helper para obtener nombre a mostrar */ export function getDisplayName(user: UserProfile): string { return user.fullName || user.login; } /** * Helper para formatear fecha de último login */ export function formatLastLogin(date: Date | null): string { if (!date) return 'Nunca'; const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffMins = Math.floor(diffMs / 60000); const diffHours = Math.floor(diffMs / 3600000); const diffDays = Math.floor(diffMs / 86400000); if (diffMins < 1) return 'Hace un momento'; if (diffMins < 60) return `Hace ${diffMins} minuto${diffMins !== 1 ? 's' : ''}`; if (diffHours < 24) return `Hace ${diffHours} hora${diffHours !== 1 ? 's' : ''}`; if (diffDays < 7) return `Hace ${diffDays} día${diffDays !== 1 ? 's' : ''}`; return date.toLocaleDateString('es-ES', { day: 'numeric', month: 'short', year: 'numeric', }); }