<!DOCTYPE html>

<html lang="es">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

    <title>TeamFlow Pro | Gestión de Equipos</title>

   

    <!-- Configuración para App Móvil (PWA) -->

    <meta name="apple-mobile-web-app-capable" content="yes">

    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

    <meta name="theme-color" content="#4f46e5">

    <link rel="apple-touch-icon" href="https://cdn-icons-png.flaticon.com/512/2098/2098402.png">

    <!-- Tailwind CSS -->

    <script src="https://cdn.tailwindcss.com"></script>

   

    <!-- Google Fonts: Inter -->

    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;900&display=swap" rel="stylesheet">

   

    <!-- React & Babel -->

    <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>

    <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>

    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

   

    <!-- Lucide Icons -->

    <script src="https://unpkg.com/lucide@latest"></script>

    <script src="https://unpkg.com/lucide-react@latest"></script>

    <style>

        body {

            font-family: 'Inter', sans-serif;

            -webkit-font-smoothing: antialiased;

            -webkit-tap-highlight-color: transparent;

        }

        .no-scrollbar::-webkit-scrollbar { display: none; }

        .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }

       

        .glass-effect {

            background: rgba(255, 255, 255, 0.8);

            backdrop-filter: blur(12px);

            -webkit-backdrop-filter: blur(12px);

        }

        @keyframes slideUp {

            from { transform: translateY(20px); opacity: 0; }

            to { transform: translateY(0); opacity: 1; }

        }

        .animate-slide-up { animation: slideUp 0.4s ease-out forwards; }

    </style>

</head>

<body class="bg-slate-50 text-slate-900">

    <div id="root"></div>

    <!-- Firebase SDK (ES Modules) -->

    <script type="module">

        import { initializeApp } from "https://www.gstatic.com/firebasejs/11.1.0/firebase-app.js";

        import { getFirestore, collection, addDoc, onSnapshot, updateDoc, deleteDoc, doc } from "https://www.gstatic.com/firebasejs/11.1.0/firebase-firestore.js";

        import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from "https://www.gstatic.com/firebasejs/11.1.0/firebase-auth.js";

        window.AppFirebase = {

            initializeApp, getFirestore, collection, addDoc, onSnapshot,

            updateDoc, deleteDoc, doc, getAuth, signInAnonymously,

            signInWithCustomToken, onAuthStateChanged

        };

    </script>

    <script type="text/babel">

        const { useState, useEffect, useMemo } = React;

        const {

            Plus, Search, Calendar, User, CheckCircle2,

            Clock, AlertCircle, Trash2, LayoutDashboard,

            ListTodo, Download, XCircle, CheckCircle, ChevronRight, Filter

        } = lucideReact;

        // --- Configuración e Inicialización ---

        // El sistema inyecta automáticamente __firebase_config y __app_id

        const firebaseConfig = JSON.parse(__firebase_config);

        const appId = typeof __app_id !== 'undefined' ? __app_id : 'teamflow-pro-prod';

        const PRIORITIES = {

            Crítica: { color: 'bg-rose-100 text-rose-700 border-rose-200', icon: AlertCircle },

            Alta: { color: 'bg-orange-100 text-orange-700 border-orange-200', icon: AlertCircle },

            Media: { color: 'bg-amber-100 text-amber-700 border-amber-200', icon: Clock },

            Baja: { color: 'bg-emerald-100 text-emerald-700 border-emerald-200', icon: CheckCircle2 },

        };

        const STATUSES = {

            'Pendiente': 'bg-slate-100 text-slate-500 border-slate-200',

            'En Proceso': 'bg-indigo-100 text-indigo-700 border-indigo-200',

            'Revisión': 'bg-purple-100 text-purple-700 border-purple-200',

            'Completado': 'bg-teal-100 text-teal-700 border-teal-200',

        };

        function App() {

            const [tasks, setTasks] = useState([]);

            const [user, setUser] = useState(null);

            const [loading, setLoading] = useState(true);

            const [view, setView] = useState('board');

            const [isModalOpen, setIsModalOpen] = useState(false);

            const [searchTerm, setSearchTerm] = useState('');

            const [filterPriority, setFilterPriority] = useState('Todas');

            const [newTask, setNewTask] = useState({ title: '', assignee: '', priority: 'Media', status: 'Pendiente', dueDate: '', description: '' });

            useEffect(() => {

                const interval = setInterval(() => {

                    if (window.AppFirebase) {

                        clearInterval(interval);

                        initSession();

                    }

                }, 100);

            }, []);

            const initSession = async () => {

                const { AppFirebase: FB } = window;

                const app = FB.initializeApp(firebaseConfig);

                const auth = FB.getAuth(app);

                const db = FB.getFirestore(app);

                // Autenticación según las reglas del entorno

                if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) {

                    await FB.signInWithCustomToken(auth, __initial_auth_token);

                } else {

                    await FB.signInAnonymously(auth);

                }

                FB.onAuthStateChanged(auth, (usr) => {

                    setUser(usr);

                    if (usr) {

                        // Escuchar datos en tiempo real usando la ruta obligatoria

                        const tasksCol = FB.collection(db, 'artifacts', appId, 'public', 'data', 'tasks');

                        FB.onSnapshot(tasksCol, (snapshot) => {

                            const data = snapshot.docs.map(d => ({ id: d.id, ...d.data() }));

                            setTasks(data.sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0)));

                            setLoading(false);

                        });

                    }

                });

            };

            const stats = useMemo(() => ({

                total: tasks.length,

                completed: tasks.filter(t => t.status === 'Completado').length,

                urgent: tasks.filter(t => (t.priority === 'Crítica' || t.priority === 'Alta') && t.status !== 'Completado').length,

                progress: tasks.length > 0 ? Math.round((tasks.filter(t => t.status === 'Completado').length / tasks.length) * 100) : 0

            }), [tasks]);

            const filteredTasks = tasks.filter(task => {

                const matchesSearch = task.title.toLowerCase().includes(searchTerm.toLowerCase()) ||

                                     task.assignee.toLowerCase().includes(searchTerm.toLowerCase());

                const matchesPriority = filterPriority === 'Todas' || task.priority === filterPriority;

                return matchesSearch && matchesPriority;

            });

            const addTask = async (e) => {

                e.preventDefault();

                if (!user) return;

                const { AppFirebase: FB } = window;

                const db = FB.getFirestore();

                await FB.addDoc(FB.collection(db, 'artifacts', appId, 'public', 'data', 'tasks'), {

                    ...newTask,

                    createdAt: Date.now(),

                    createdBy: user.uid

                });

                setNewTask({ title: '', assignee: '', priority: 'Media', status: 'Pendiente', dueDate: '', description: '' });

                setIsModalOpen(false);

            };

            const updateStatus = async (id, newStatus) => {

                const { AppFirebase: FB } = window;

                const db = FB.getFirestore();

                await FB.updateDoc(FB.doc(db, 'artifacts', appId, 'public', 'data', 'tasks', id), { status: newStatus });

            };

            const removeTask = async (id) => {

                if (!confirm('¿Deseas eliminar esta tarea?')) return;

                const { AppFirebase: FB } = window;

                const db = FB.getFirestore();

                await FB.deleteDoc(FB.doc(db, 'artifacts', appId, 'public', 'data', 'tasks', id));

            };

            const downloadCSV = () => {

                const headers = ['ID', 'Tarea', 'Responsable', 'Prioridad', 'Estado', 'Vencimiento'];

                const rows = tasks.map(t => [t.id, t.title, t.assignee, t.priority, t.status, t.dueDate]);

                const csv = [headers, ...rows].map(e => e.join(",")).join("\n");

                const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });

                const link = document.createElement("a");

                link.href = URL.createObjectURL(blob);

                link.download = `equipo_flow_${new Date().toLocaleDateString()}.csv`;

                link.click();

            };

            if (loading) return (

                <div className="min-h-screen flex items-center justify-center bg-white">

                    <div className="flex flex-col items-center gap-4">

                        <div className="w-12 h-12 border-4 border-indigo-600 border-t-transparent rounded-full animate-spin"></div>

                        <p className="text-slate-400 font-black text-[10px] uppercase tracking-[0.3em]">Sincronizando Oficina</p>

                    </div>

                </div>

            );

            return (

                <div className="min-h-screen pb-12">

                    {/* Navegación Superior */}

                    <header className="glass-effect sticky top-0 z-40 border-b border-slate-100 px-6 py-6 sm:px-12">

                        <div className="max-w-7xl mx-auto flex flex-col md:flex-row md:items-center justify-between gap-6">

                            <div className="flex items-center gap-5">

                                <div className="h-14 w-14 bg-indigo-600 rounded-[1.25rem] flex items-center justify-center shadow-xl shadow-indigo-200">

                                    <LayoutDashboard className="text-white" size={28} />

                                </div>

                                <div>

                                    <h1 className="text-2xl font-black text-slate-800 tracking-tighter">TeamFlow <span className="text-indigo-600">Pro</span></h1>

                                    <p className="text-[10px] font-bold text-slate-400 uppercase tracking-widest mt-0.5">Entorno Colaborativo</p>

                                </div>

                            </div>

                            <div className="flex gap-2">

                                <button onClick={downloadCSV} className="flex-1 md:flex-none flex items-center justify-center gap-2 px-5 py-3 bg-white border border-slate-200 rounded-2xl text-slate-600 font-bold text-xs hover:bg-slate-50 transition-all">

                                    <Download size={16} /> <span className="hidden sm:inline">CSV</span>

                                </button>

                                <button onClick={() => setIsModalOpen(true)} className="flex-1 md:flex-none flex items-center justify-center gap-2 px-6 py-3 bg-indigo-600 text-white rounded-2xl font-bold text-xs hover:bg-indigo-700 transition-all shadow-lg shadow-indigo-100">

                                    <Plus size={18} /> Nueva Tarea

                                </button>

                            </div>

                        </div>

                    </header>

                    <div className="max-w-7xl mx-auto px-6 sm:px-12 py-10">

                        {/* Panel de Estadísticas */}

                        <section className="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-10">

                            <StatCard label="Total" value={stats.total} icon={<ListTodo />} color="text-indigo-600" />

                            <StatCard label="Críticas" value={stats.urgent} icon={<AlertCircle />} color="text-rose-600" />

                            <StatCard label="Hechas" value={stats.completed} icon={<CheckCircle />} color="text-teal-600" />

                            <div className="bg-white p-6 rounded-[2rem] border border-slate-100 shadow-sm flex flex-col justify-center">

                                <div className="flex justify-between items-center mb-2">

                                    <span className="text-[9px] font-black text-slate-400 uppercase">Progreso</span>

                                    <span className="text-xs font-black text-indigo-600">{stats.progress}%</span>

                                </div>

                                <div className="w-full bg-slate-100 h-2.5 rounded-full overflow-hidden">

                                    <div className="bg-indigo-600 h-full transition-all duration-700" style={{ width: `${stats.progress}%` }}></div>

                                </div>

                            </div>

                        </section>

                        {/* Filtros */}

                        <div className="flex flex-col md:flex-row gap-4 mb-8 bg-white p-4 rounded-[2rem] border border-slate-100 shadow-sm">

                            <div className="relative flex-1">

                                <Search className="absolute left-4 top-1/2 -translate-y-1/2 text-slate-300" size={18} />

                                <input type="text" placeholder="Buscar..." className="w-full pl-11 pr-4 py-3 bg-slate-50 border-none rounded-xl outline-none text-sm font-bold placeholder:text-slate-300" value={searchTerm} onChange={e => setSearchTerm(e.target.value)} />

                            </div>

                            <div className="flex gap-2">

                                <select className="px-4 py-3 bg-slate-50 border-none rounded-xl text-[10px] font-black text-slate-500 uppercase tracking-widest outline-none cursor-pointer" value={filterPriority} onChange={e => setFilterPriority(e.target.value)}>

                                    <option value="Todas">Prioridad: Todas</option>

                                    {Object.keys(PRIORITIES).map(p => <option key={p} value={p}>{p}</option>)}

                                </select>

                                <div className="flex bg-slate-100 p-1 rounded-xl">

                                    <button onClick={() => setView('board')} className={`p-2 rounded-lg transition-all ${view === 'board' ? 'bg-white shadow-sm text-indigo-600' : 'text-slate-400'}`}><LayoutDashboard size={20} /></button>

                                    <button onClick={() => setView('list')} className={`p-2 rounded-lg transition-all ${view === 'list' ? 'bg-white shadow-sm text-indigo-600' : 'text-slate-400'}`}><ListTodo size={20} /></button>

                                </div>

                            </div>

                        </div>

                        {/* Contenido según la Vista */}

                        {view === 'board' ? (

                            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 items-start overflow-x-auto no-scrollbar pb-6">

                                {Object.keys(STATUSES).map(status => (

                                    <div key={status} className="flex flex-col gap-5 min-w-[280px]">

                                        <h3 className="text-[10px] font-black text-slate-400 uppercase tracking-[0.2em] px-3 flex justify-between items-center">

                                            {status}

                                            <span className="bg-slate-200 text-slate-600 px-2 py-0.5 rounded-full text-[9px]">{tasks.filter(t => t.status === status).length}</span>

                                        </h3>

                                        <div className="flex flex-col gap-4 p-2 rounded-[2.25rem] bg-slate-100/40 border border-dashed border-slate-200/60 min-h-[400px]">

                                            {filteredTasks.filter(t => t.status === status).map(task => (

                                                <TaskCard key={task.id} task={task} onUpdate={updateStatus} onDelete={removeTask} />

                                            ))}

                                        </div>

                                    </div>

                                ))}

                            </div>

                        ) : (

                            <div className="bg-white rounded-[2.5rem] border border-slate-100 shadow-sm overflow-hidden animate-slide-up">

                                <div className="overflow-x-auto">

                                    <table className="w-full text-left">

                                        <thead className="bg-slate-50/50 border-b border-slate-100 text-[10px] font-black text-slate-400 uppercase tracking-widest">

                                            <tr>

                                                <th className="px-8 py-6">Tarea</th>

                                                <th className="px-6 py-6">Responsable</th>

                                                <th className="px-6 py-6">Prioridad</th>

                                                <th className="px-6 py-6">Estado</th>

                                                <th className="px-6 py-6 text-right">Acción</th>

                                            </tr>

                                        </thead>

                                        <tbody className="divide-y divide-slate-50">

                                            {filteredTasks.map(task => (

                                                <tr key={task.id} className="hover:bg-slate-50/50 transition-colors">

                                                    <td className="px-8 py-5">

                                                        <div className="font-bold text-sm text-slate-800">{task.title}</div>

                                                        <div className="text-[10px] text-slate-400 line-clamp-1">{task.description || 'Sin notas adicionales'}</div>

                                                    </td>

                                                    <td className="px-6 py-5">

                                                        <div className="flex items-center gap-2">

                                                            <div className="h-7 w-7 bg-indigo-50 rounded-full flex items-center justify-center text-[9px] font-black text-indigo-500 uppercase">{task.assignee.charAt(0)}</div>

                                                            <span className="text-xs font-bold text-slate-600">{task.assignee}</span>

                                                        </div>

                                                    </td>

                                                    <td className="px-6 py-5">

                                                        <span className={`px-2.5 py-1 rounded-full text-[9px] font-black uppercase border tracking-tight ${PRIORITIES[task.priority].color}`}>

                                                            {task.priority}

                                                        </span>

                                                    </td>

                                                    <td className="px-6 py-5">

                                                        <select value={task.status} onChange={e => updateStatus(task.id, e.target.value)} className={`px-3 py-1.5 rounded-xl text-[10px] font-black cursor-pointer border-none focus:ring-0 ${STATUSES[task.status]}`}>

                                                            {Object.keys(STATUSES).map(s => <option key={s} value={s}>{s}</option>)}

                                                        </select>

                                                    </td>

                                                    <td className="px-6 py-5 text-right">

                                                        <button onClick={() => removeTask(task.id)} className="text-slate-200 hover:text-rose-500 p-2"><Trash2 size={16} /></button>

                                                    </td>

                                                </tr>

                                            ))}

                                        </tbody>

                                    </table>

                                </div>

                            </div>

                        )}

                    </div>

                    {/* Modal Crear Tarea */}

                    {isModalOpen && (

                        <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-slate-900/40 backdrop-blur-md animate-slide-up">

                            <div className="bg-white rounded-[3rem] w-full max-w-lg shadow-2xl overflow-hidden">

                                <div className="px-10 py-8 border-b border-slate-50 flex items-center justify-between">

                                    <div>

                                        <h2 className="text-2xl font-black text-slate-800 tracking-tight">Nueva Tarea</h2>

                                        <p className="text-[10px] font-black text-indigo-600 uppercase tracking-widest mt-1">Sincronización en la Nube</p>

                                    </div>

                                    <button onClick={() => setIsModalOpen(false)} className="text-slate-300 hover:text-slate-600 transition-transform hover:rotate-90">

                                        <XCircle size={32} />

                                    </button>

                                </div>

                                <form onSubmit={addTask} className="p-10 space-y-6">

                                    <div className="space-y-2">

                                        <label className="text-[10px] font-black text-slate-400 uppercase tracking-widest ml-1">Título</label>

                                        <input required className="w-full px-6 py-4 bg-slate-50 border-none rounded-2xl outline-none font-bold text-sm focus:ring-2 focus:ring-indigo-500/10" placeholder="¿Qué hay que hacer?" value={newTask.title} onChange={e => setNewTask({...newTask, title: e.target.value})} />

                                    </div>

                                    <div className="grid grid-cols-2 gap-4">

                                        <div className="space-y-2">

                                            <label className="text-[10px] font-black text-slate-400 uppercase tracking-widest ml-1">Responsable</label>

                                            <input required className="w-full px-6 py-4 bg-slate-50 border-none rounded-2xl outline-none font-bold text-sm focus:ring-2 focus:ring-indigo-500/10" placeholder="Nombre" value={newTask.assignee} onChange={e => setNewTask({...newTask, assignee: e.target.value})} />

                                        </div>

                                        <div className="space-y-2">

                                            <label className="text-[10px] font-black text-slate-400 uppercase tracking-widest ml-1">Prioridad</label>

                                            <select className="w-full px-6 py-4 bg-slate-50 border-none rounded-2xl outline-none font-black text-xs uppercase cursor-pointer" value={newTask.priority} onChange={e => setNewTask({...newTask, priority: e.target.value})}>

                                                {Object.keys(PRIORITIES).map(p => <option key={p} value={p}>{p}</option>)}

                                            </select>

                                        </div>

                                    </div>

                                    <div className="space-y-2">

                                        <label className="text-[10px] font-black text-slate-400 uppercase tracking-widest ml-1">Descripción</label>

                                        <textarea className="w-full px-6 py-4 bg-slate-50 border-none rounded-2xl outline-none font-medium text-sm focus:ring-2 focus:ring-indigo-500/10" rows="3" placeholder="Detalles de la tarea..." value={newTask.description} onChange={e => setNewTask({...newTask, description: e.target.value})}></textarea>

                                    </div>

                                    <button type="submit" className="w-full py-5 bg-indigo-600 text-white font-black rounded-2xl hover:bg-indigo-700 shadow-xl shadow-indigo-100 transition-all uppercase tracking-[0.2em] text-[10px]">

                                        Publicar Tarea

                                    </button>

                                </form>

                            </div>

                        </div>

                    )}

                </div>

            );

        }

        function TaskCard({ task, onUpdate, onDelete }) {

            const Icon = PRIORITIES[task.priority].icon;

            return (

                <div className="bg-white p-6 rounded-[2.5rem] border border-slate-100 shadow-sm hover:shadow-xl hover:border-indigo-100 transition-all group animate-slide-up">

                    <div className="flex justify-between items-start mb-4">

                        <span className={`px-3 py-1 rounded-full text-[8px] font-black uppercase border tracking-widest ${PRIORITIES[task.priority].color} flex items-center gap-1.5`}>

                            <Icon size={12} /> {task.priority}

                        </span>

                        <button onClick={() => onDelete(task.id)} className="opacity-0 group-hover:opacity-100 p-2 text-slate-200 hover:text-rose-500 transition-all"><Trash2 size={14} /></button>

                    </div>

                    <h4 className="font-bold text-slate-800 text-sm mb-1 leading-tight group-hover:text-indigo-600 transition-colors">{task.title}</h4>

                    <p className="text-[10px] text-slate-400 line-clamp-2 mb-5 font-medium leading-relaxed">{task.description || 'Sin descripción'}</p>

                    <div className="flex items-center justify-between pt-4 border-t border-slate-50">

                        <div className="flex items-center gap-2">

                            <div className="h-6 w-6 bg-slate-100 rounded-full flex items-center justify-center text-[8px] font-black text-slate-400 uppercase">{task.assignee.charAt(0)}</div>

                            <span className="text-[10px] font-bold text-slate-600">{task.assignee}</span>

                        </div>

                        <div className="flex gap-1.5">

                            {Object.keys(STATUSES).map(s => (

                                <button key={s} title={s} onClick={() => onUpdate(task.id, s)} className={`h-1.5 w-4 rounded-full transition-all ${task.status === s ? STATUSES[s].split(' ')[1].replace('text-', 'bg-') : 'bg-slate-100'}`}></button>

                            ))}

                        </div>

                    </div>

                </div>

            );

        }

        function StatCard({ label, value, icon, color }) {

            return (

                <div className="bg-white p-6 rounded-[2.25rem] border border-slate-100 shadow-sm flex items-center gap-5 group hover:bg-slate-50 transition-colors">

                    <div className={`p-4 bg-slate-50 rounded-2xl ${color} group-hover:bg-white transition-colors`}>{React.cloneElement(icon, { size: 24 })}</div>

                    <div>

                        <p className="text-[9px] font-black uppercase tracking-widest text-slate-400 mb-0.5">{label}</p>

                        <p className="text-2xl font-black text-slate-800 leading-none">{value}</p>

                    </div>

                </div>

            );

        }

        const root = ReactDOM.createRoot(document.getElementById('root'));

        root.render(<App />);

    </script>

</body>

</html>