const { useState, useRef, useEffect } = React; window.AdminAjustes = function({ isMaster, companyLogoUrl, setCompanyLogoUrl, showCompanyLogo, setShowCompanyLogo, inssRate, setInssRate, vacRate, setVacRate, lunchLimitMinutes, setLunchLimitMinutes, gracePeriodMinutes, setGracePeriodMinutes, maxTardinessAllowed, setMaxTardinessAllowed, tardinessPenaltyAction, setTardinessPenaltyAction, saveCompanySettings, newReasonInput, setNewReasonInput, setReasonsList, reasonsList }) { // ESTADOS ORIGINALES DE RECORTE DE LOGO const [showCropModal, setShowCropModal] = useState(false); const [rawImageSrc, setRawImageSrc] = useState(null); const [zoomScale, setZoomScale] = useState(1); const [panOffset, setPanOffset] = useState({ x: 0, y: 0 }); const [isDragging, setIsDragging] = useState(false); const [dragStart, setDragStart] = useState({ x: 0, y: 0 }); const [isSavingLogo, setIsSavingLogo] = useState(false); // ESTADOS DE IA (GOOGLE GEMINI API) const [geminiApiKey, setGeminiApiKey] = useState(''); const [showKey, setShowKey] = useState(false); const [testingAi, setTestingAi] = useState(false); const [aiStatusMsg, setAiStatusMsg] = useState(''); const canvasRef = useRef(null); const imageObjRef = useRef(null); // Cargar la API Key guardada en la base de datos al montar el componente useEffect(() => { const loadSavedSettings = async () => { try { const res = await window.apiCall('get_initial_data', {}); if (res && res.success && res.data && res.data.settings) { if (res.data.settings.geminiApiKey) { setGeminiApiKey(res.data.settings.geminiApiKey); } } } catch (e) {} }; loadSavedSettings(); }, []); const handleFileSelect = (e) => { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = (ev) => { const img = new Image(); img.onload = () => { imageObjRef.current = img; setRawImageSrc(ev.target.result); setZoomScale(1); setPanOffset({ x: 0, y: 0 }); setShowCropModal(true); }; img.src = ev.target.result; }; reader.readAsDataURL(file); }; const drawCanvas = () => { const canvas = canvasRef.current; const img = imageObjRef.current; if (!canvas || !img) return; const ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.save(); ctx.translate(canvas.width / 2 + panOffset.x, canvas.height / 2 + panOffset.y); ctx.scale(zoomScale, zoomScale); const hRatio = (canvas.width * 0.85) / img.width; const vRatio = (canvas.height * 0.85) / img.height; const ratio = Math.min(hRatio, vRatio); const drawW = img.width * ratio; const drawH = img.height * ratio; ctx.drawImage(img, -drawW / 2, -drawH / 2, drawW, drawH); ctx.restore(); }; useEffect(() => { if (showCropModal) { drawCanvas(); } }, [showCropModal, zoomScale, panOffset]); const handleMouseDown = (e) => { setIsDragging(true); setDragStart({ x: e.clientX - panOffset.x, y: e.clientY - panOffset.y }); }; const handleMouseMove = (e) => { if (!isDragging) return; setPanOffset({ x: e.clientX - dragStart.x, y: e.clientY - dragStart.y }); }; const handleMouseUp = () => setIsDragging(false); const handleApplyCropAndSave = async () => { const canvas = canvasRef.current; if (!canvas) return; setIsSavingLogo(true); const croppedBase64 = canvas.toDataURL('image/png', 0.95); try { const res = await window.apiCall('upload_company_logo', { logo_base64: croppedBase64 }); if (res && res.success) { const finalUrl = res.logo_url; setCompanyLogoUrl(finalUrl); if (window.SHIFT_CONFIG) { window.SHIFT_CONFIG.companyLogo = finalUrl; } setShowCropModal(false); } else { alert("Error del servidor: " + (res.error || "No se pudo guardar el logo")); } } catch (err) { console.error("Error al subir logo:", err); } finally { setIsSavingLogo(false); } }; // Alternar visibilidad del logo y guardar inmediatamente en base de datos const handleToggleShowLogo = async (e) => { const newValue = e.target.checked; setShowCompanyLogo(newValue); await saveCompanySettings({ show_company_logo: newValue ? 1 : 0 }); }; // Probar conexión directa con Google Gemini const handleTestGeminiKey = async () => { if (!geminiApiKey.trim()) return alert("Ingresa primero una API Key de Google Gemini."); setTestingAi(true); setAiStatusMsg(''); try { const res = await window.apiCall('ask_ai_copilot', { prompt: "Hola, responde brevemente con un saludo confirmando que la conexión está activa.", customApiKey: geminiApiKey.trim() }); if (res && res.success && res.response) { setAiStatusMsg("✅ Conexión con Gemini exitosa"); } else { setAiStatusMsg("❌ " + (res?.error || "Error al conectar con la API de Gemini")); } } catch (err) { setAiStatusMsg("❌ Error: " + err.message); } finally { setTestingAi(false); } }; // Guardado general de todos los ajustes (incluye la API Key) const handleSaveAllSettings = async () => { await saveCompanySettings({ gemini_api_key: geminiApiKey.trim() }); }; return (
Permite al asistente realizar análisis automáticos de almuerzos, tardanzas, contratos y nómina.
{aiStatusMsg}
)}Puedes generar tu API Key gratuita en Google AI Studio.
Logo oficial de la empresa visible en la App del personal y reportes
Al seleccionar un archivo se abrirá el editor de recorte y encuadre.
Límites de tiempo y penalizaciones automáticas del sistema
Tasas patronales de seguridad social y acumulación vacacional de ley
Arrastra para mover y usa el zoom para encuadrar