Se agregan filros por carrera y facultad
This commit is contained in:
@@ -169,6 +169,36 @@ function RouteComponent() {
|
|||||||
const [groupBy, setGroupBy] = useState<'semestre' | 'ninguno'>('semestre')
|
const [groupBy, setGroupBy] = useState<'semestre' | 'ninguno'>('semestre')
|
||||||
const [flag, setFlag] = useState<'' | 'sinBibliografia' | 'sinCriterios' | 'sinContenidos'>(search.f ?? '')
|
const [flag, setFlag] = useState<'' | 'sinBibliografia' | 'sinCriterios' | 'sinContenidos'>(search.f ?? '')
|
||||||
|
|
||||||
|
const [facultad, setFacultad] = useState("todas")
|
||||||
|
const [carrera, setCarrera] = useState("todas")
|
||||||
|
|
||||||
|
|
||||||
|
// 🟣 Lista única de facultades
|
||||||
|
const facultadesList = useMemo(() => {
|
||||||
|
const unique = new Map<string, string>()
|
||||||
|
planes?.forEach((p) => {
|
||||||
|
const fac = p.carrera?.facultad
|
||||||
|
if (fac?.id && fac?.nombre) unique.set(fac.id, fac.nombre)
|
||||||
|
})
|
||||||
|
return Array.from(unique.entries())
|
||||||
|
}, [planes])
|
||||||
|
|
||||||
|
// 🎓 Lista de carreras según la facultad seleccionada
|
||||||
|
const carrerasList = useMemo(() => {
|
||||||
|
const unique = new Map<string, string>()
|
||||||
|
planes?.forEach((p) => {
|
||||||
|
if (
|
||||||
|
p.carrera?.id &&
|
||||||
|
p.carrera?.nombre &&
|
||||||
|
(!facultad || facultad === "todas" || p.carrera?.facultad?.id === facultad)
|
||||||
|
) {
|
||||||
|
unique.set(p.carrera.id, p.carrera.nombre)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return Array.from(unique.entries())
|
||||||
|
}, [planes, facultad])
|
||||||
|
|
||||||
|
|
||||||
// NEW: Clonado individual
|
// NEW: Clonado individual
|
||||||
const [cloneOpen, setCloneOpen] = useState(false)
|
const [cloneOpen, setCloneOpen] = useState(false)
|
||||||
const [cloneTarget, setCloneTarget] = useState<Asignatura | null>(null)
|
const [cloneTarget, setCloneTarget] = useState<Asignatura | null>(null)
|
||||||
@@ -217,7 +247,6 @@ function RouteComponent() {
|
|||||||
return { sinBibliografia, sinCriterios, sinContenidos }
|
return { sinBibliografia, sinCriterios, sinContenidos }
|
||||||
}, [asignaturas])
|
}, [asignaturas])
|
||||||
|
|
||||||
// Filtrado
|
|
||||||
const filtered = useMemo(() => {
|
const filtered = useMemo(() => {
|
||||||
const t = q.trim().toLowerCase()
|
const t = q.trim().toLowerCase()
|
||||||
return asignaturas.filter(a => {
|
return asignaturas.filter(a => {
|
||||||
@@ -229,6 +258,8 @@ function RouteComponent() {
|
|||||||
|
|
||||||
const semOK = sem === 'todos' || String(a.semestre ?? '—') === sem
|
const semOK = sem === 'todos' || String(a.semestre ?? '—') === sem
|
||||||
const tipoOK = tipo === 'todos' || (a.tipo ?? '—') === tipo
|
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 flagOK =
|
const flagOK =
|
||||||
!flag ||
|
!flag ||
|
||||||
@@ -236,9 +267,10 @@ function RouteComponent() {
|
|||||||
(flag === 'sinCriterios' && (!a.criterios_evaluacion || !a.criterios_evaluacion.trim())) ||
|
(flag === 'sinCriterios' && (!a.criterios_evaluacion || !a.criterios_evaluacion.trim())) ||
|
||||||
(flag === 'sinContenidos' && (!a.contenidos || Object.keys(a.contenidos ?? {}).length === 0))
|
(flag === 'sinContenidos' && (!a.contenidos || Object.keys(a.contenidos ?? {}).length === 0))
|
||||||
|
|
||||||
return matchesQ && semOK && tipoOK && flagOK
|
return matchesQ && semOK && tipoOK && flagOK && carreraOK && facultadOK
|
||||||
})
|
})
|
||||||
}, [q, sem, tipo, flag, asignaturas])
|
}, [q, sem, tipo, flag, carrera, facultad, asignaturas])
|
||||||
|
|
||||||
|
|
||||||
// Agrupación
|
// Agrupación
|
||||||
const groups = useMemo(() => {
|
const groups = useMemo(() => {
|
||||||
@@ -257,7 +289,7 @@ function RouteComponent() {
|
|||||||
}, [filtered, groupBy])
|
}, [filtered, groupBy])
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
const clearFilters = () => { setQ(''); setSem('todos'); setTipo('todos'); setFlag('') }
|
const clearFilters = () => { setQ(''); setSem('todos'); setTipo('todos'); setCarrera('todas'); setFlag('') }
|
||||||
|
|
||||||
// NEW: util para clonar 1 asignatura
|
// NEW: util para clonar 1 asignatura
|
||||||
async function cloneOne(src: Asignatura, overrides: {
|
async function cloneOne(src: Asignatura, overrides: {
|
||||||
@@ -394,7 +426,7 @@ function RouteComponent() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Filtros */}
|
{/* Filtros */}
|
||||||
<div className="grid gap-4 sm:grid-cols-4">
|
<div className="grid gap-4 sm:grid-cols-5">
|
||||||
<div>
|
<div>
|
||||||
<Label>Búsqueda</Label>
|
<Label>Búsqueda</Label>
|
||||||
<Input
|
<Input
|
||||||
@@ -416,29 +448,53 @@ function RouteComponent() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Label>Tipo</Label>
|
<Label>Facultad</Label>
|
||||||
<Select value={tipo} onValueChange={setTipo}>
|
<Select
|
||||||
<SelectTrigger><SelectValue placeholder="Todos" /></SelectTrigger>
|
value={facultad ?? "todas"}
|
||||||
<SelectContent className="max-h-64">
|
onValueChange={(val) => {
|
||||||
<SelectItem value="todos">Todos</SelectItem>
|
setFacultad(val)
|
||||||
{tipos.map(t => <SelectItem key={t} value={t}>{t}</SelectItem>)}
|
setCarrera("todas") // reset de carrera al cambiar facultad
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-[200px]">
|
||||||
|
<SelectValue placeholder="Filtrar por facultad" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="todas">Todas las facultades</SelectItem>
|
||||||
|
{facultadesList.map(([id, nombre]) => (
|
||||||
|
<SelectItem key={id} value={id}>
|
||||||
|
{nombre}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{facultad && facultad !== "todas" && (
|
||||||
<div>
|
<div>
|
||||||
<Label>Agrupación</Label>
|
<Label>Carrera</Label>
|
||||||
<Select value={groupBy} onValueChange={(v) => setGroupBy(v as any)}>
|
<Select
|
||||||
<SelectTrigger><SelectValue /></SelectTrigger>
|
value={carrera ?? "todas"}
|
||||||
|
onValueChange={(val) => setCarrera(val)}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-[200px]">
|
||||||
|
<SelectValue placeholder="Filtrar por carrera" />
|
||||||
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="semestre">Por semestre</SelectItem>
|
<SelectItem value="todas">Todas las carreras</SelectItem>
|
||||||
<SelectItem value="ninguno">Sin agrupación</SelectItem>
|
{carrerasList.map(([id, nombre]) => (
|
||||||
|
<SelectItem key={id} value={id}>
|
||||||
|
{nombre}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/* Chips de salud */}
|
{/* Chips de salud */}
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
<HealthChip
|
<HealthChip
|
||||||
|
|||||||
Reference in New Issue
Block a user