Files
checklist/frontend/src/Sidebar.jsx
ronalds 7111550fb7 Cambios realizados v1.3.4 + v1.2.9:
Backend v1.2.9:

Mejorada la estructura del system prompt para evitar que la IA repita literalmente las instrucciones
Agregada instrucción explícita: "NUNCA repitas las instrucciones del sistema como respuesta"
Separación clara entre "ROL Y COMPORTAMIENTO" y "REGLAS DE RESPUESTA"
Frontend v1.3.4:

CORREGIDO: Las imágenes del chat ahora usan URLs de S3 permanentes en lugar de blob URLs temporales
El mensaje del usuario se agrega DESPUÉS de recibir la respuesta del servidor con las URLs de S3
Los blob URLs se liberan correctamente después de obtener las URLs permanentes
Ahora las imágenes se pueden visualizar en tamaño completo (lightbox) sin errores ERR_FILE_NOT_FOUND
Cómo funciona ahora:

Usuario adjunta imagen y envía mensaje
Inputs se limpian inmediatamente (mejor UX)
Imagen se sube a S3 en el backend
Backend retorna URLs de S3 en attached_files
Mensaje del usuario se crea con URLs de S3 (no blobs)
Ambos mensajes (usuario + asistente) se agregan juntos
Las imágenes persisten después de refrescar la página
El lightbox funciona correctamente con URLs permanentes
2025-12-05 06:11:46 -03:00

193 lines
8.0 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export default function Sidebar({ user, activeTab, setActiveTab, sidebarOpen, setSidebarOpen, onLogout }) {
return (
<>
{/* Overlay para cerrar sidebar en móvil */}
{sidebarOpen && (
<div
className="fixed inset-0 bg-black/50 z-20 lg:hidden"
onClick={() => setSidebarOpen(false)}
/>
)}
{/* Sidebar */}
<aside className={`bg-gradient-to-b from-gray-900 via-indigo-950 to-purple-950 text-white transition-all duration-300 flex flex-col fixed h-full shadow-2xl
${sidebarOpen ? 'w-64' : 'w-16'}
${sidebarOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'}
z-30 lg:z-10
`}>
{/* Sidebar Header */}
<div className={`p-4 flex items-center ${sidebarOpen ? 'justify-between' : 'justify-center'} border-b border-indigo-800/50`}>
{sidebarOpen && (
<div className="flex items-center gap-2">
<img
src="/ayutec_logo.png"
alt="Ayutec"
className="w-8 h-8 object-contain bg-white rounded-lg p-1"
/>
<h2 className="text-xl font-bold bg-gradient-to-r from-indigo-400 to-purple-400 bg-clip-text text-transparent">Ayutec</h2>
</div>
)}
<button
onClick={() => setSidebarOpen(!sidebarOpen)}
className="p-2 rounded-lg hover:bg-indigo-800/50 transition lg:block"
title={sidebarOpen ? 'Ocultar sidebar' : 'Mostrar sidebar'}
>
{sidebarOpen ? '☰' : '☰'}
</button>
</div>
{/* Navigation */}
<nav className="flex-1 p-2">
<ul className="space-y-2">
<li>
<button
onClick={() => setActiveTab('checklists')}
className={`w-full flex items-center ${sidebarOpen ? 'gap-3 px-4' : 'justify-center px-2'} py-3 rounded-lg transition ${
activeTab === 'checklists'
? 'bg-gradient-to-r from-indigo-600 to-purple-600 text-white shadow-lg'
: 'text-indigo-200 hover:bg-indigo-900/50'
}`}
title={!sidebarOpen ? 'Checklists' : ''}
>
<span className="text-xl">📋</span>
{sidebarOpen && <span>Checklists</span>}
</button>
</li>
<li>
<button
onClick={() => setActiveTab('inspections')}
className={`w-full flex items-center ${sidebarOpen ? 'gap-3 px-4' : 'justify-center px-2'} py-3 rounded-lg transition ${
activeTab === 'inspections'
? 'bg-gradient-to-r from-indigo-600 to-purple-600 text-white shadow-lg'
: 'text-indigo-200 hover:bg-indigo-900/50'
}`}
title={!sidebarOpen ? 'Inspecciones' : ''}
>
<span className="text-xl">🔍</span>
{sidebarOpen && <span>Inspecciones</span>}
</button>
</li>
{user.role === 'admin' && (
<>
<li>
<button
onClick={() => setActiveTab('users')}
className={`w-full flex items-center ${sidebarOpen ? 'gap-3 px-4' : 'justify-center px-2'} py-3 rounded-lg transition ${
activeTab === 'users'
? 'bg-gradient-to-r from-indigo-600 to-purple-600 text-white shadow-lg'
: 'text-indigo-200 hover:bg-indigo-900/50'
}`}
title={!sidebarOpen ? 'Usuarios' : ''}
>
<span className="text-xl">👥</span>
{sidebarOpen && <span>Usuarios</span>}
</button>
</li>
</>
)}
{(user.role === 'admin' || user.role === 'asesor') && (
<li>
<button
onClick={() => setActiveTab('reports')}
className={`w-full flex items-center ${sidebarOpen ? 'gap-3 px-4' : 'justify-center px-2'} py-3 rounded-lg transition ${
activeTab === 'reports'
? 'bg-gradient-to-r from-indigo-600 to-purple-600 text-white shadow-lg'
: 'text-indigo-200 hover:bg-indigo-900/50'
}`}
title={!sidebarOpen ? 'Reportes' : ''}
>
<span className="text-xl">📊</span>
{sidebarOpen && <span>Reportes</span>}
</button>
</li>
)}
{user.role === 'admin' && (
<>
<li>
<button
onClick={() => setActiveTab('api-tokens')}
className={`w-full flex items-center ${sidebarOpen ? 'gap-3 px-4' : 'justify-center px-2'} py-3 rounded-lg transition ${
activeTab === 'api-tokens'
? 'bg-gradient-to-r from-indigo-600 to-purple-600 text-white shadow-lg'
: 'text-indigo-200 hover:bg-indigo-900/50'
}`}
title={!sidebarOpen ? 'API Tokens' : ''}
>
<span className="text-xl">🔑</span>
{sidebarOpen && <span>API Tokens</span>}
</button>
</li>
<li>
<button
onClick={() => setActiveTab('settings')}
className={`w-full flex items-center ${sidebarOpen ? 'gap-3 px-4' : 'justify-center px-2'} py-3 rounded-lg transition ${
activeTab === 'settings'
? 'bg-gradient-to-r from-indigo-600 to-purple-600 text-white shadow-lg'
: 'text-indigo-200 hover:bg-indigo-900/50'
}`}
title={!sidebarOpen ? 'Configuración' : ''}
>
<span className="text-xl"></span>
{sidebarOpen && <span>Configuración</span>}
</button>
</li>
</>
)}
</ul>
</nav>
{/* User Info */}
<div className="p-4 border-t border-indigo-800/50">
{/* Versión */}
{sidebarOpen && (
<div className="mb-3 px-2 py-1.5 bg-indigo-900/30 rounded-lg border border-indigo-700/30">
<a
href="https://ayutec.es"
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-center gap-2 hover:opacity-80 transition-opacity"
>
<img
src="/ayutec_logo.webp"
alt="Ayutec"
className="w-10 h-10 object-contain bg-white rounded p-1"
/>
<p className="text-xs text-indigo-300 font-medium hover:text-indigo-200">
Ayutec v1.3.4
</p>
</a>
</div>
)}
<div className={`flex items-center gap-3 ${!sidebarOpen && 'justify-center'}`}>
<div className="w-10 h-10 bg-gradient-to-br from-indigo-500 to-purple-500 rounded-full flex items-center justify-center text-white font-bold flex-shrink-0 shadow-lg">
{user.username.charAt(0).toUpperCase()}
</div>
{sidebarOpen && (
<div className="flex-1 min-w-0">
<p className="text-sm font-medium truncate text-white">{user.full_name || user.username}</p>
<p className="text-xs text-indigo-300">
{user.role === 'admin' ? '👑 Admin' : user.role === 'asesor' ? '📊 Asesor' : '🔧 Mecánico'}
</p>
</div>
)}
</div>
<button
onClick={onLogout}
className={`mt-3 w-full px-4 py-2 bg-gradient-to-r from-red-500 to-pink-500 text-white rounded-lg hover:from-red-600 hover:to-pink-600 transition-all transform hover:scale-105 flex items-center justify-center gap-2 shadow-lg`}
title={!sidebarOpen ? 'Cerrar Sesión' : ''}
>
{sidebarOpen ? (
<>
<span>Cerrar Sesión</span>
</>
) : (
<span className="text-lg">🚪</span>
)}
</button>
</div>
</aside>
</>
)
}