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
This commit is contained in:
@@ -442,20 +442,13 @@ function DatosGenerales({
|
|||||||
? config.examples[0]
|
? 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]
|
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 =
|
const isContentEmpty =
|
||||||
!valActual?.description ||
|
!valActual?.description ||
|
||||||
valActual.description === config.description
|
valActual.description === config.description
|
||||||
|
|
||||||
const currentContent = valActual?.description ?? ''
|
const currentContent = valActual ?? ''
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InfoCard
|
<InfoCard
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ import { usePlanHistorial } from '@/data/hooks/usePlans'
|
|||||||
|
|
||||||
export const Route = createFileRoute('/planes/$planId/_detalle/historial')({
|
export const Route = createFileRoute('/planes/$planId/_detalle/historial')({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
|
validateSearch: (search: { structure?: any }) => ({
|
||||||
|
structure: search.structure ?? null,
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
const getEventConfig = (tipo: string, campo: string) => {
|
const getEventConfig = (tipo: string, campo: string) => {
|
||||||
@@ -58,6 +61,9 @@ const getEventConfig = (tipo: string, campo: string) => {
|
|||||||
function RouteComponent() {
|
function RouteComponent() {
|
||||||
const { planId } = Route.useParams()
|
const { planId } = Route.useParams()
|
||||||
const { data: rawData, isLoading } = usePlanHistorial(planId)
|
const { data: rawData, isLoading } = usePlanHistorial(planId)
|
||||||
|
const { structure } = Route.useSearch()
|
||||||
|
console.log(structure?.vigencia?.title)
|
||||||
|
console.log(structure)
|
||||||
|
|
||||||
// ESTADOS PARA EL MODAL
|
// ESTADOS PARA EL MODAL
|
||||||
const [selectedEvent, setSelectedEvent] = useState<any>(null)
|
const [selectedEvent, setSelectedEvent] = useState<any>(null)
|
||||||
@@ -77,7 +83,9 @@ function RouteComponent() {
|
|||||||
description:
|
description:
|
||||||
item.campo === 'datos'
|
item.campo === 'datos'
|
||||||
? `Actualización general de: ${item.valor_nuevo?.nombre || 'información del plan'}`
|
? `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),
|
date: parseISO(item.cambiado_en),
|
||||||
icon: config.icon,
|
icon: config.icon,
|
||||||
campo: item.campo,
|
campo: item.campo,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from '@/components/ui/tooltip'
|
} 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
|
// import { toast } from 'sonner' // Asegúrate de tener sonner instalado o quita la línea
|
||||||
export const Route = createFileRoute('/planes/$planId/_detalle/')({
|
export const Route = createFileRoute('/planes/$planId/_detalle/')({
|
||||||
@@ -39,7 +39,7 @@ function DatosGeneralesPage() {
|
|||||||
const [editingId, setEditingId] = useState<string | null>(null)
|
const [editingId, setEditingId] = useState<string | null>(null)
|
||||||
const [editValue, setEditValue] = useState('')
|
const [editValue, setEditValue] = useState('')
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const updatePlan = useUpdatePlanFields()
|
||||||
// Confetti al llegar desde creación
|
// Confetti al llegar desde creación
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (location.state.showConfetti) {
|
if (location.state.showConfetti) {
|
||||||
@@ -122,14 +122,47 @@ function DatosGeneralesPage() {
|
|||||||
setEditValue('')
|
setEditValue('')
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSave = (id: string) => {
|
const handleSave = (campo: DatosGeneralesField) => {
|
||||||
// Actualizamos el estado local de la lista
|
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) =>
|
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)
|
setEditingId(null)
|
||||||
setEditValue('')
|
setEditValue('')
|
||||||
// toast.success('Cambios guardados localmente')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleIARequest = (clave: string) => {
|
const handleIARequest = (clave: string) => {
|
||||||
@@ -245,7 +278,7 @@ function DatosGeneralesPage() {
|
|||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
className="bg-teal-600 hover:bg-teal-700"
|
className="bg-teal-600 hover:bg-teal-700"
|
||||||
onClick={() => handleSave(campo.id)}
|
onClick={() => handleSave(campo)}
|
||||||
>
|
>
|
||||||
<Check size={14} className="mr-1" /> Guardar
|
<Check size={14} className="mr-1" /> Guardar
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -157,10 +157,15 @@ function AsignaturaCardItem({
|
|||||||
|
|
||||||
export const Route = createFileRoute('/planes/$planId/_detalle/mapa')({
|
export const Route = createFileRoute('/planes/$planId/_detalle/mapa')({
|
||||||
component: MapaCurricularPage,
|
component: MapaCurricularPage,
|
||||||
|
validateSearch: (search: { ciclo?: number }) => ({
|
||||||
|
ciclo: search.ciclo ?? null,
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
function MapaCurricularPage() {
|
function MapaCurricularPage() {
|
||||||
const { planId } = Route.useParams() // Idealmente usa el ID de la ruta
|
const { planId } = Route.useParams() // Idealmente usa el ID de la ruta
|
||||||
|
const { ciclo } = Route.useSearch()
|
||||||
|
console.log(ciclo)
|
||||||
|
|
||||||
// 1. Fetch de Datos
|
// 1. Fetch de Datos
|
||||||
const { data: asignaturasApi, isLoading: loadingAsig } =
|
const { data: asignaturasApi, isLoading: loadingAsig } =
|
||||||
@@ -249,7 +254,7 @@ function MapaCurricularPage() {
|
|||||||
if (lineasApi) setLineas(mapLineasToLineaCurricular(lineasApi))
|
if (lineasApi) setLineas(mapLineasToLineaCurricular(lineasApi))
|
||||||
}, [lineasApi])
|
}, [lineasApi])
|
||||||
|
|
||||||
const ciclosTotales = 9
|
const ciclosTotales = Number(ciclo)
|
||||||
const ciclosArray = Array.from({ length: ciclosTotales }, (_, i) => i + 1)
|
const ciclosArray = Array.from({ length: ciclosTotales }, (_, i) => i + 1)
|
||||||
|
|
||||||
// Nuevo estado para controlar los datos temporales del modal de edición
|
// Nuevo estado para controlar los datos temporales del modal de edición
|
||||||
|
|||||||
@@ -219,7 +219,11 @@ function RouteComponent() {
|
|||||||
<Tab to="/planes/$planId/" params={{ planId }}>
|
<Tab to="/planes/$planId/" params={{ planId }}>
|
||||||
Datos Generales
|
Datos Generales
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab to="/planes/$planId/mapa" params={{ planId }}>
|
<Tab
|
||||||
|
to="/planes/$planId/mapa"
|
||||||
|
params={{ planId }}
|
||||||
|
search={{ ciclo: data?.numero_ciclos }}
|
||||||
|
>
|
||||||
Mapa Curricular
|
Mapa Curricular
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab to="/planes/$planId/asignaturas" params={{ planId }}>
|
<Tab to="/planes/$planId/asignaturas" params={{ planId }}>
|
||||||
@@ -234,7 +238,13 @@ function RouteComponent() {
|
|||||||
<Tab to="/planes/$planId/documento" params={{ planId }}>
|
<Tab to="/planes/$planId/documento" params={{ planId }}>
|
||||||
Documento
|
Documento
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab to="/planes/$planId/historial" params={{ planId }}>
|
<Tab
|
||||||
|
to="/planes/$planId/historial"
|
||||||
|
params={{ planId }}
|
||||||
|
search={{
|
||||||
|
structure: data?.estructuras_plan?.definicion?.properties,
|
||||||
|
}}
|
||||||
|
>
|
||||||
Historial
|
Historial
|
||||||
</Tab>
|
</Tab>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -288,16 +298,20 @@ const InfoCard = forwardRef<
|
|||||||
function Tab({
|
function Tab({
|
||||||
to,
|
to,
|
||||||
params,
|
params,
|
||||||
|
search,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
to: string
|
to: string
|
||||||
params?: any
|
params?: any
|
||||||
|
search?: any
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
|
console.log(search)
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
to={to}
|
to={to}
|
||||||
params={params}
|
params={params}
|
||||||
|
search={search}
|
||||||
className="border-b-2 border-transparent pb-3 text-sm font-medium text-slate-500 transition-all hover:text-slate-800"
|
className="border-b-2 border-transparent pb-3 text-sm font-medium text-slate-500 transition-all hover:text-slate-800"
|
||||||
activeProps={{ className: 'border-teal-600 text-teal-700 font-bold' }}
|
activeProps={{ className: 'border-teal-600 text-teal-700 font-bold' }}
|
||||||
activeOptions={{
|
activeOptions={{
|
||||||
|
|||||||
Reference in New Issue
Block a user