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 }) { 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); const canvasRef = useRef(null); const imageObjRef = useRef(null); 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 }); }; return (
{/* 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" />
)}
); };