Merge pull request 'Que no sean INPUTS #72' (#86) from issue/72-que-no-sean-inputs into main

Reviewed-on: #86
This commit was merged in pull request #86.
This commit is contained in:
2026-02-06 22:01:49 +00:00

View File

@@ -1,4 +1,4 @@
/* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/label-has-associated-control */ /* eslint-disable jsx-a11y/label-has-associated-control */
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from '@tanstack/react-router'
import { import {
@@ -7,6 +7,7 @@ import {
AlertTriangle, AlertTriangle,
GripVertical, GripVertical,
Trash2, Trash2,
Pencil,
} from 'lucide-react' } from 'lucide-react'
import { useMemo, useState, useEffect } from 'react' import { useMemo, useState, useEffect } from 'react'
@@ -239,8 +240,13 @@ function MapaCurricularPage() {
}, },
) )
} }
const guardarEdicionLinea = (id: string) => { const guardarEdicionLinea = (id: string, nuevoNombre?: string) => {
if (!tempNombreLinea.trim()) { // Usamos el nombre que viene por parámetro o el del estado como fallback
const nombreAFijar = (
nuevoNombre !== undefined ? nuevoNombre : tempNombreLinea
).trim()
if (!nombreAFijar) {
setEditingLineaId(null) setEditingLineaId(null)
return return
} }
@@ -248,11 +254,10 @@ function MapaCurricularPage() {
updateLineaApi( updateLineaApi(
{ {
lineaId: id, lineaId: id,
patch: { nombre: tempNombreLinea.trim() }, patch: { nombre: nombreAFijar },
}, },
{ {
onSuccess: (lineaActualizada) => { onSuccess: (lineaActualizada) => {
// ACTUALIZACIÓN MANUAL DEL ESTADO LOCAL
setLineas((prev) => setLineas((prev) =>
prev.map((l) => prev.map((l) =>
l.id === id ? { ...l, nombre: lineaActualizada.nombre } : l, l.id === id ? { ...l, nombre: lineaActualizada.nombre } : l,
@@ -261,6 +266,10 @@ function MapaCurricularPage() {
setEditingLineaId(null) setEditingLineaId(null)
setTempNombreLinea('') setTempNombreLinea('')
}, },
onError: (err) => {
console.error('Error al actualizar linea:', err)
// Opcional: revertir cambios o avisar al usuario
},
}, },
) )
} }
@@ -454,6 +463,33 @@ function MapaCurricularPage() {
[asignaturas], [asignaturas],
) )
const handleKeyDownLinea = (
e: React.KeyboardEvent<HTMLSpanElement>,
id: string,
) => {
if (e.key === 'Enter') {
e.preventDefault()
e.currentTarget.blur()
}
}
const handleBlurLinea = (
e: React.FocusEvent<HTMLSpanElement>,
id: string,
) => {
const nuevoNombre = e.currentTarget.textContent?.trim() || ''
// Buscamos la línea original para comparar
const lineaOriginal = lineas.find((l) => l.id === id)
if (nuevoNombre !== lineaOriginal?.nombre) {
// IMPORTANTE: Pasamos nuevoNombre directamente
guardarEdicionLinea(id, nuevoNombre)
} else {
setEditingLineaId(null)
}
}
if (loadingAsig || loadingLineas) if (loadingAsig || loadingLineas)
return <div className="p-10 text-center">Cargando mapa curricular...</div> return <div className="p-10 text-center">Cargando mapa curricular...</div>
@@ -568,36 +604,52 @@ function MapaCurricularPage() {
}} }}
> >
<div <div
className={`flex items-center justify-between rounded-xl border-l-4 p-4 ${lineColors[idx % lineColors.length]}`} className={`group relative flex items-center justify-between rounded-xl border-l-4 p-4 transition-all ${
lineColors[idx % lineColors.length]
} ${editingLineaId === linea.id ? 'bg-white ring-2 ring-teal-500/20' : ''}`}
> >
{editingLineaId === linea.id ? ( <div className="flex-1 overflow-hidden">
<Input
className="h-7 bg-white text-xs"
value={tempNombreLinea}
onChange={(e) => setTempNombreLinea(e.target.value)}
onBlur={() => guardarEdicionLinea(linea.id)}
onKeyDown={(e) =>
e.key === 'Enter' && guardarEdicionLinea(linea.id)
}
/>
) : (
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
<span <span
className="cursor-pointer text-xs font-bold hover:underline" contentEditable={editingLineaId === linea.id}
suppressContentEditableWarning
spellCheck={false}
onKeyDown={(e) => handleKeyDownLinea(e, linea.id)}
onBlur={(e) => handleBlurLinea(e, linea.id)}
onClick={() => { onClick={() => {
setEditingLineaId(linea.id) if (editingLineaId !== linea.id) {
setTempNombreLinea(linea.nombre) setEditingLineaId(linea.id)
setTempNombreLinea(linea.nombre)
}
}} }}
className={`block w-full text-xs font-bold break-words outline-none ${
editingLineaId === linea.id
? 'cursor-text border-b border-teal-500/50 pb-1'
: 'cursor-pointer'
}`}
> >
{linea.nombre} {linea.nombre}
</span> </span>
)} </div>
<Trash2 <div className="flex items-center gap-2">
size={14} {/* Botón de edición que aparece en hover o si está editando */}
className="cursor-pointer text-slate-400 hover:text-red-500" <button
onClick={() => borrarLinea(linea.id)} // Aquí también podrías añadir una mutación delete onClick={() => setEditingLineaId(linea.id)}
/> className={`text-slate-400 transition-opacity hover:text-teal-600 ${
editingLineaId === linea.id
? 'opacity-0'
: 'opacity-0 group-hover:opacity-100'
}`}
>
<Pencil size={12} />
</button>
<Trash2
size={14}
className="cursor-pointer text-slate-400 opacity-0 transition-opacity group-hover:opacity-100 hover:text-red-500"
onClick={() => borrarLinea(linea.id)}
/>
</div>
</div> </div>
{ciclosArray.map((ciclo) => ( {ciclosArray.map((ciclo) => (