diff --git a/src/components/asignaturas/detalle/ContenidoTematico.tsx b/src/components/asignaturas/detalle/ContenidoTematico.tsx
index 9297b1e..8ef2d1c 100644
--- a/src/components/asignaturas/detalle/ContenidoTematico.tsx
+++ b/src/components/asignaturas/detalle/ContenidoTematico.tsx
@@ -8,9 +8,10 @@ import {
Trash2,
Clock,
} from 'lucide-react'
-import { useEffect, useState } from 'react'
+import { useEffect, useRef, useState } from 'react'
import type { ContenidoApi, ContenidoTemaApi } from '@/data/api/subjects.api'
+import type { FocusEvent, KeyboardEvent } from 'react'
import {
AlertDialog,
@@ -167,16 +168,29 @@ export function ContenidoTematico() {
const { data: data, isLoading: isLoading } = useSubject(asignaturaId)
const [unidades, setUnidades] = useState>([])
const [expandedUnits, setExpandedUnits] = useState>(new Set())
+ const unitContainerRefs = useRef
-
{unidades.map((unidad) => (
-
{
+ if (el) unitContainerRefs.current.set(unidad.id, el)
+ else unitContainerRefs.current.delete(unidad.id)
+ }}
>
- toggleUnit(unidad.id)}
- >
-
-
-
-
-
-
-
- Unidad {unidad.numero}
-
+
+ toggleUnit(unidad.id)}
+ >
+
+
+
+
+
+
+
+ Unidad {unidad.numero}
+
- {editingUnit === unidad.id ? (
-
- updateUnidadNombre(unidad.id, e.target.value)
- }
- onBlur={() => {
- setEditingUnit(null)
- void persistUnidades(unidades)
- }}
- onKeyDown={(e) => {
- if (e.key === 'Enter') {
- setEditingUnit(null)
- void persistUnidades(unidades)
- }
- }}
- className="h-8 max-w-md bg-white"
- />
- ) : (
-
setEditingUnit(unidad.id)}
- >
- {unidad.nombre}
-
- )}
-
-
-
- {' '}
- {unidad.temas.reduce(
- (sum, t) => sum + (t.horasEstimadas || 0),
- 0,
- )}
- h
-
-
-
-
-
-
-
-
- {unidad.temas.map((tema, idx) => (
-
- setEditingTema({ unitId: unidad.id, temaId: tema.id })
- }
- onStopEditing={() => {
- setEditingTema(null)
- void persistUnidades(unidades)
+ {editingUnit === unidad.id ? (
+ setUnitDraftNombre(e.target.value)}
+ onBlur={() => {
+ if (cancelNextBlurRef.current) {
+ cancelNextBlurRef.current = false
+ return
+ }
+ commitEditUnit()
}}
- onUpdate={(updates) =>
- updateTema(unidad.id, tema.id, updates)
- }
- onDelete={() =>
- setDeleteDialog({
- type: 'tema',
- id: tema.id,
- parentId: unidad.id,
- })
- }
+ onKeyDown={(e) => {
+ if (e.key === 'Enter') {
+ e.preventDefault()
+ e.currentTarget.blur()
+ return
+ }
+ if (e.key === 'Escape') {
+ e.preventDefault()
+ cancelNextBlurRef.current = true
+ cancelEditUnit()
+ e.currentTarget.blur()
+ }
+ }}
+ className="h-8 max-w-md bg-white"
/>
- ))}
-
+ ) : (
+ beginEditUnit(unidad.id)}
+ >
+ {unidad.nombre}
+
+ )}
+
+
+
+ {' '}
+ {unidad.temas.reduce(
+ (sum, t) => sum + (t.horasEstimadas || 0),
+ 0,
+ )}
+ h
+
+
+
-
-
-
-
+
+
+
+
+ {unidad.temas.map((tema, idx) => (
+
beginEditTema(unidad.id, tema.id)}
+ onDraftNombreChange={setTemaDraftNombre}
+ onDraftHorasChange={setTemaDraftHoras}
+ onEditorBlurCapture={handleTemaEditorBlurCapture}
+ onEditorKeyDownCapture={
+ handleTemaEditorKeyDownCapture
+ }
+ onNombreInputRef={(el) => {
+ temaNombreInputElRef.current = el
+ }}
+ onDelete={() =>
+ setDeleteDialog({
+ type: 'tema',
+ id: tema.id,
+ parentId: unidad.id,
+ })
+ }
+ />
+ ))}
+
+
+
+
+
+
+
))}
+
+
+
+
void
- onStopEditing: () => void
- onUpdate: (updates: Partial) => void
+ draftNombre: string
+ draftHoras: string
+ onBeginEdit: () => void
+ onDraftNombreChange: (value: string) => void
+ onDraftHorasChange: (value: string) => void
+ onEditorBlurCapture: (e: FocusEvent) => void
+ onEditorKeyDownCapture: (e: KeyboardEvent) => void
+ onNombreInputRef: (el: HTMLInputElement | null) => void
onDelete: () => void
}
@@ -475,9 +633,14 @@ function TemaRow({
tema,
index,
isEditing,
- onEdit,
- onStopEditing,
- onUpdate,
+ draftNombre,
+ draftHoras,
+ onBeginEdit,
+ onDraftNombreChange,
+ onDraftHorasChange,
+ onEditorBlurCapture,
+ onEditorKeyDownCapture,
+ onNombreInputRef,
onDelete,
}: TemaRowProps) {
return (
@@ -489,47 +652,49 @@ function TemaRow({
>
{index}.
{isEditing ? (
-
+
onUpdate({ nombre: e.target.value })}
+ ref={onNombreInputRef}
+ value={draftNombre}
+ onChange={(e) => onDraftNombreChange(e.target.value)}
className="h-8 flex-1 bg-white"
placeholder="Nombre"
/>
- onUpdate({ horasEstimadas: parseInt(e.target.value) || 0 })
- }
+ value={draftHoras}
+ onChange={(e) => onDraftHorasChange(e.target.value)}
className="h-8 w-16 bg-white"
/>
-
) : (
<>
-
- {tema.horasEstimadas}h
-
@@ -537,7 +702,10 @@ function TemaRow({
variant="ghost"
size="icon"
className="h-7 w-7 text-slate-400 hover:text-red-500"
- onClick={onDelete}
+ onClick={(e) => {
+ e.stopPropagation()
+ onDelete()
+ }}
>