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 (
{/* SECCIÓN IA: GOOGLE GEMINI API */}

Google Gemini API (Shift Copilot AI) Motor IA

Permite al asistente realizar análisis automáticos de almuerzos, tardanzas, contratos y nómina.

setGeminiApiKey(e.target.value)} placeholder="Pega tu API Key: AIzaSy..." className="w-full p-4 bg-white/10 border border-white/20 rounded-2xl text-xs font-mono font-bold text-white outline-none focus:border-indigo-400 placeholder:text-slate-400" />
{aiStatusMsg && (

{aiStatusMsg}

)}

Puedes generar tu API Key gratuita en Google AI Studio.

{/* SECCIÓN 1: IDENTIDAD CORPORATIVA */}

Identidad Corporativa

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.

Vista Previa Actual {companyLogoUrl ? ( Logo Empresa ) : ( Sin logo configurado )}
{/* SECCIÓN 2: POLÍTICAS DE TARDANZAS Y ALMUERZOS */}

Políticas de Tardanzas y Tolerancia

Límites de tiempo y penalizaciones automáticas del sistema

setGracePeriodMinutes(e.target.value)} className="w-full p-4 bg-slate-50 border rounded-2xl font-bold text-xs outline-none" />
setMaxTardinessAllowed(e.target.value)} className="w-full p-4 bg-slate-50 border rounded-2xl font-bold text-xs outline-none" />
setLunchLimitMinutes(e.target.value)} className="w-full p-4 bg-slate-50 border rounded-2xl font-bold text-xs outline-none" />
{/* SECCIÓN 3: LEYES LABORALES Y TASAS DE PLANILLA */}

Leyes Laborales y Tasas de Nómina (Nicaragua)

Tasas patronales de seguridad social y acumulación vacacional de ley

setInssRate(e.target.value)} className="w-full p-4 bg-slate-50 border rounded-2xl font-bold text-xs outline-none" /> 21.5% para empresas de menos de 50 trabajadores • 22.5% para 50 a más.
setVacRate(e.target.value)} className="w-full p-4 bg-slate-50 border rounded-2xl font-bold text-xs outline-none" /> Estándar Código del Trabajo Art. 76 (2.5 días por mes trabajado).
{/* BOTÓN GENERAL DE GUARDADO */} {/* MODAL FLOTANTE DE RECORTE Y ZOOM */} {showCropModal && (
setShowCropModal(false)}>
e.stopPropagation()}>

Ajustar y Recortar Logo

Arrastra para mover y usa el zoom para encuadrar

Zoom {zoomScale.toFixed(1)}x
setZoomScale(parseFloat(e.target.value))} className="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-indigo-600" />
)}
); };