From 64d9aa336f15459f9cc1c23f97763660f85cf42a Mon Sep 17 00:00:00 2001 From: "Roberto.silva" Date: Fri, 30 Jan 2026 15:51:43 -0600 Subject: [PATCH] Se agrega persistencia a planes en datos, se arregla bug de nombre de claves en asignaturas, se cambia en historial clves por los titulos corresppndientes --- .../detalle/AsignaturaDetailPage.tsx | 9 +--- .../planes/$planId/_detalle/historial.tsx | 10 +++- src/routes/planes/$planId/_detalle/index.tsx | 47 ++++++++++++++++--- src/routes/planes/$planId/_detalle/mapa.tsx | 7 ++- src/routes/planes/$planId/_detalle/route.tsx | 18 ++++++- 5 files changed, 72 insertions(+), 19 deletions(-) diff --git a/src/components/asignaturas/detalle/AsignaturaDetailPage.tsx b/src/components/asignaturas/detalle/AsignaturaDetailPage.tsx index ceb7179..7b339a0 100644 --- a/src/components/asignaturas/detalle/AsignaturaDetailPage.tsx +++ b/src/components/asignaturas/detalle/AsignaturaDetailPage.tsx @@ -442,20 +442,13 @@ function DatosGenerales({ ? config.examples[0] : '' - // 2. CONTENIDO REAL (Viene de data.datos -> valoresActuales) - // El problema: Si 'description' en 'datos' es igual a la de la 'estructura', - // el usuario aún no ha redactado nada real. - const valActual = valoresActuales[key] - // Lógica para determinar si mostrar el contenido o dejarlo vacío (para que salga el placeholder) - // Si el contenido en 'datos' es idéntico a la instrucción de la 'estructura', - // asumimos que no hay contenido real todavía. const isContentEmpty = !valActual?.description || valActual.description === config.description - const currentContent = valActual?.description ?? '' + const currentContent = valActual ?? '' return ( ({ + structure: search.structure ?? null, + }), }) const getEventConfig = (tipo: string, campo: string) => { @@ -58,6 +61,9 @@ const getEventConfig = (tipo: string, campo: string) => { function RouteComponent() { const { planId } = Route.useParams() const { data: rawData, isLoading } = usePlanHistorial(planId) + const { structure } = Route.useSearch() + console.log(structure?.vigencia?.title) + console.log(structure) // ESTADOS PARA EL MODAL const [selectedEvent, setSelectedEvent] = useState(null) @@ -77,7 +83,9 @@ function RouteComponent() { description: item.campo === 'datos' ? `Actualización general de: ${item.valor_nuevo?.nombre || 'información del plan'}` - : `Se modificó el campo ${item.campo}`, + : `Se modificó el campo ${ + structure?.[item.campo]?.title ?? item.campo + }`, date: parseISO(item.cambiado_en), icon: config.icon, campo: item.campo, diff --git a/src/routes/planes/$planId/_detalle/index.tsx b/src/routes/planes/$planId/_detalle/index.tsx index a7b303c..d4582e4 100644 --- a/src/routes/planes/$planId/_detalle/index.tsx +++ b/src/routes/planes/$planId/_detalle/index.tsx @@ -18,7 +18,7 @@ import { TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip' -import { usePlan } from '@/data' +import { usePlan, useUpdatePlanFields } from '@/data' // import { toast } from 'sonner' // Asegúrate de tener sonner instalado o quita la línea export const Route = createFileRoute('/planes/$planId/_detalle/')({ @@ -39,7 +39,7 @@ function DatosGeneralesPage() { const [editingId, setEditingId] = useState(null) const [editValue, setEditValue] = useState('') const location = useLocation() - + const updatePlan = useUpdatePlanFields() // Confetti al llegar desde creación useEffect(() => { if (location.state.showConfetti) { @@ -122,14 +122,47 @@ function DatosGeneralesPage() { setEditValue('') } - const handleSave = (id: string) => { - // Actualizamos el estado local de la lista + const handleSave = (campo: DatosGeneralesField) => { + if (!data?.datos) return + + const currentValue = (data.datos as any)[campo.clave] + + let newValue: any + + if ( + typeof currentValue === 'object' && + currentValue !== null && + 'description' in currentValue + ) { + // Caso 1: objeto con description + newValue = { + ...currentValue, + description: editValue, + } + } else { + // Caso 2: valor plano (string, number, etc) + newValue = editValue + } + + const datosActualizados = { + ...data.datos, + [campo.clave]: newValue, + } + + updatePlan.mutate({ + planId, + patch: { + datos: datosActualizados, + }, + }) + + // UI optimista setCampos((prev) => - prev.map((c) => (c.id === id ? { ...c, value: editValue } : c)), + prev.map((c) => (c.id === campo.id ? { ...c, value: editValue } : c)), ) + setEditingId(null) setEditValue('') - // toast.success('Cambios guardados localmente') } const handleIARequest = (clave: string) => { @@ -245,7 +278,7 @@ function DatosGeneralesPage() { diff --git a/src/routes/planes/$planId/_detalle/mapa.tsx b/src/routes/planes/$planId/_detalle/mapa.tsx index 47adae2..edfa4e5 100644 --- a/src/routes/planes/$planId/_detalle/mapa.tsx +++ b/src/routes/planes/$planId/_detalle/mapa.tsx @@ -157,10 +157,15 @@ function AsignaturaCardItem({ export const Route = createFileRoute('/planes/$planId/_detalle/mapa')({ component: MapaCurricularPage, + validateSearch: (search: { ciclo?: number }) => ({ + ciclo: search.ciclo ?? null, + }), }) function MapaCurricularPage() { const { planId } = Route.useParams() // Idealmente usa el ID de la ruta + const { ciclo } = Route.useSearch() + console.log(ciclo) // 1. Fetch de Datos const { data: asignaturasApi, isLoading: loadingAsig } = @@ -249,7 +254,7 @@ function MapaCurricularPage() { if (lineasApi) setLineas(mapLineasToLineaCurricular(lineasApi)) }, [lineasApi]) - const ciclosTotales = 9 + const ciclosTotales = Number(ciclo) const ciclosArray = Array.from({ length: ciclosTotales }, (_, i) => i + 1) // Nuevo estado para controlar los datos temporales del modal de edición diff --git a/src/routes/planes/$planId/_detalle/route.tsx b/src/routes/planes/$planId/_detalle/route.tsx index bd774ee..8fbc854 100644 --- a/src/routes/planes/$planId/_detalle/route.tsx +++ b/src/routes/planes/$planId/_detalle/route.tsx @@ -219,7 +219,11 @@ function RouteComponent() { Datos Generales - + Mapa Curricular @@ -234,7 +238,13 @@ function RouteComponent() { Documento - + Historial @@ -288,16 +298,20 @@ const InfoCard = forwardRef< function Tab({ to, params, + search, children, }: { to: string params?: any + search?: any children: React.ReactNode }) { + console.log(search) return (