From daac6f3f6dcd0817da7b6305a2430f0e01cfba55 Mon Sep 17 00:00:00 2001 From: "Roberto.silva" Date: Thu, 30 Oct 2025 14:50:48 -0600 Subject: [PATCH] Se agregan filtros de plan de estudios, carrera y se limpian filtros --- src/routes/_authenticated/asignaturas.tsx | 130 ++++++++++++++++++---- 1 file changed, 109 insertions(+), 21 deletions(-) diff --git a/src/routes/_authenticated/asignaturas.tsx b/src/routes/_authenticated/asignaturas.tsx index b6a1160..425225c 100644 --- a/src/routes/_authenticated/asignaturas.tsx +++ b/src/routes/_authenticated/asignaturas.tsx @@ -2,7 +2,7 @@ import { createFileRoute, Link, useRouter } from '@tanstack/react-router' import { useSuspenseQuery, queryOptions, useQueryClient } from '@tanstack/react-query' import { supabase } from '@/auth/supabase' import * as Icons from 'lucide-react' -import { useMemo, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from '@/components/ui/select' @@ -10,6 +10,7 @@ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuIte import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog' import { Label } from '@/components/ui/label' import { toast } from 'sonner' +import { InfoChip } from '@/components/planes/InfoChip' /* ================== Tipos ================== */ type FacMini = { id: string; nombre: string; color?: string | null; icon?: string | null } @@ -79,7 +80,8 @@ async function fetchPlanIdsByScope(search: Pick { const planIds = await fetchPlanIdsByScope(search) if (planIds && planIds.length === 0) return [] - + console.log(AsignaturaCard); + let query = supabase .from('asignaturas') .select(` @@ -172,6 +174,30 @@ function RouteComponent() { const [facultad, setFacultad] = useState("todas") const [carrera, setCarrera] = useState("todas") +/* useEffect(() => { + const timeout = setTimeout(() => { + router.navigate({ + to: '/asignaturas', + search: { ...search, q }, + replace: true, + }) + }, 400) + return () => clearTimeout(timeout) +}, [q]) */ + + +function handleChange(e: React.ChangeEvent) { + const value = e.target.value + setQ(value) + router.navigate({ + to: '/asignaturas', + search: { + ...search, + q: value, + }, + replace: true, // evita recargar o empujar al historial + }) + } // 🟣 Lista única de facultades const facultadesList = useMemo(() => { @@ -260,6 +286,7 @@ const carrerasList = useMemo(() => { const tipoOK = tipo === 'todos' || (a.tipo ?? '—') === tipo const carreraOK = carrera === 'todas' || a.plan?.carrera?.id === carrera const facultadOK = facultad === 'todas' || a.plan?.carrera?.facultad?.id === facultad + const planOK = !search.planId || a.plan?.id === search.planId const flagOK = !flag || @@ -267,7 +294,7 @@ const carrerasList = useMemo(() => { (flag === 'sinCriterios' && (!a.criterios_evaluacion || !a.criterios_evaluacion.trim())) || (flag === 'sinContenidos' && (!a.contenidos || Object.keys(a.contenidos ?? {}).length === 0)) - return matchesQ && semOK && tipoOK && flagOK && carreraOK && facultadOK + return matchesQ && semOK && tipoOK && flagOK && carreraOK && facultadOK && planOK }) }, [q, sem, tipo, flag, carrera, facultad, asignaturas]) @@ -289,7 +316,19 @@ const carrerasList = useMemo(() => { }, [filtered, groupBy]) // Helpers - const clearFilters = () => { setQ(''); setSem('todos'); setTipo('todos'); setCarrera('todas'); setFlag('') } + const clearFilters = () => { setQ(''); setSem('todos'); setTipo('todos'); setCarrera('todas'); setFlag('') ; setFacultad('todas') + // Actualiza la URL limpiando todos los query params + router.navigate({ + to: '/asignaturas', + search: { + q: '', + planId: '', + carreraId: '', + facultadId: '', + f: '' + }, + }) + } // NEW: util para clonar 1 asignatura async function cloneOne(src: Asignatura, overrides: { @@ -324,6 +363,8 @@ const carrerasList = useMemo(() => { if (error) throw error } + + // NEW: abrir modal clon individual function openClone(a: Asignatura) { setCloneTarget(a) @@ -352,6 +393,8 @@ const carrerasList = useMemo(() => { setCart([]) } + + // NEW: clonado en lote async function cloneBulk() { if (!bulk.plan_destino_id) { toast.error('Selecciona un plan de destino'); return } @@ -426,34 +469,43 @@ const carrerasList = useMemo(() => { {/* Filtros */} -
+
+ {/* 🔍 Búsqueda */}
setQ(e.target.value)} + onChange={handleChange} placeholder="Nombre, clave, plan, carrera, facultad…" />
+ {/* 📘 Semestre */}
+ {/* 🏛️ Facultad */}
- {facultad && facultad !== "todas" && ( -
+ {/* 🎓 Carrera */} +
- )} + + {/* 📜 Plan */} +
+ + +
+ {/* Chips de salud */}
{ label="Sin contenidos" value={salud.sinContenidos} /> - {(q || sem !== 'todos' || tipo !== 'todos' || flag) && ( + {/*(q || sem !== 'todos' || tipo !== 'todos' || flag || carrera=='todos')*/ true && ( @@ -750,9 +829,15 @@ function AsignaturaCard({ a, onClone, onAddToCart }: { a: Asignatura; onClone: ( const horasP = a.horas_practicas ?? 0 const meta = tipoMeta(a.tipo) const FacIcon = (Icons as any)[a.plan?.carrera?.facultad?.icon ?? 'Building2'] || Icons.Building2 - + console.log(a); + return ( -
  • +
  • @@ -803,14 +888,17 @@ function AsignaturaCard({ a, onClone, onAddToCart }: { a: Asignatura; onClone: ( Plan:{a.plan.nombre} {a.plan.carrera && ( - - Carrera: {a.plan.carrera.nombre} - + } + label={a.plan.carrera.nombre} + /> )} {a.plan.carrera?.facultad && ( - - {a.plan.carrera.facultad.nombre} - + } + label={a.plan.carrera.facultad.nombre} + tint={a.plan.carrera.facultad.color} + /> )}
    )}