This commit is contained in:
2026-01-22 15:48:49 -06:00
11 changed files with 217 additions and 227 deletions

7
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
"recommendations": [
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"bradlc.vscode-tailwindcss"
]
}

View File

@@ -22,5 +22,11 @@
], ],
"files.associations": { "files.associations": {
"*.css": "tailwindcss" "*.css": "tailwindcss"
} },
"[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
"[javascriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
"[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
"[typescriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
"[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
"prettier.requireConfig": true
} }

View File

@@ -44,7 +44,7 @@ export function PasoBasicosForm({
<div className="grid gap-4 sm:grid-cols-2"> <div className="grid gap-4 sm:grid-cols-2">
<div className="grid gap-1 sm:col-span-2"> <div className="grid gap-1 sm:col-span-2">
<Label htmlFor="nombrePlan"> <Label htmlFor="nombrePlan">
Nombre del plan <span className="text-destructive">*</span> Nombre del plan {/* <span className="text-destructive">*</span> */}
</Label> </Label>
<Input <Input
id="nombrePlan" id="nombrePlan"

View File

@@ -65,7 +65,12 @@ export function PasoDetallesPanel({
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<Label htmlFor="notas">Notas adicionales</Label> <Label htmlFor="notas">
Notas adicionales
<span className="text-xs font-normal text-gray-500 dark:text-gray-400">
(Opcional)
</span>
</Label>
<textarea <textarea
id="notas" id="notas"
className="bg-background text-foreground ring-offset-background focus-visible:ring-ring min-h-24 w-full rounded-md border px-3 py-2 text-sm shadow-sm focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none" className="bg-background text-foreground ring-offset-background focus-visible:ring-ring min-h-24 w-full rounded-md border px-3 py-2 text-sm shadow-sm focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none"

View File

@@ -1,24 +1,105 @@
import { useNavigate } from '@tanstack/react-router'
import type { NewPlanWizardState } from '@/features/planes/nuevo/types'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { useGeneratePlanAI } from '@/data/hooks/usePlans'
export function WizardControls({ export function WizardControls({
errorMessage, errorMessage,
onPrev, onPrev,
onNext, onNext,
onCreate,
disablePrev, disablePrev,
disableNext, disableNext,
disableCreate, disableCreate,
isLastStep, isLastStep,
wizard,
setWizard,
}: { }: {
errorMessage?: string | null errorMessage?: string | null
onPrev: () => void onPrev: () => void
onNext: () => void onNext: () => void
onCreate: () => void
disablePrev: boolean disablePrev: boolean
disableNext: boolean disableNext: boolean
disableCreate: boolean disableCreate: boolean
isLastStep: boolean isLastStep: boolean
wizard: NewPlanWizardState
setWizard: React.Dispatch<React.SetStateAction<NewPlanWizardState>>
}) { }) {
const navigate = useNavigate()
const generatePlanAI = useGeneratePlanAI()
// const persistPlanFromAI = usePersistPlanFromAI()
const handleCreate = async () => {
// Start loading
setWizard(
(w: NewPlanWizardState): NewPlanWizardState => ({
...w,
isLoading: true,
errorMessage: null,
}),
)
try {
if (wizard.tipoOrigen === 'IA') {
const tipoCicloSafe = (wizard.datosBasicos.tipoCiclo ||
'Semestre') as any
const numCiclosSafe =
typeof wizard.datosBasicos.numCiclos === 'number'
? wizard.datosBasicos.numCiclos
: 1
const aiInput = {
datosBasicos: {
nombrePlan: wizard.datosBasicos.nombrePlan,
carreraId: wizard.datosBasicos.carreraId,
facultadId: wizard.datosBasicos.facultadId || undefined,
nivel: wizard.datosBasicos.nivel as string,
tipoCiclo: tipoCicloSafe,
numCiclos: numCiclosSafe,
estructuraPlanId: wizard.datosBasicos.estructuraPlanId as string,
},
iaConfig: {
descripcionEnfoque: wizard.iaConfig?.descripcionEnfoque || '',
notasAdicionales: wizard.iaConfig?.notasAdicionales || '',
archivosReferencia: wizard.iaConfig?.archivosReferencia || [],
repositoriosIds: wizard.iaConfig?.repositoriosReferencia || [],
archivosAdjuntos: wizard.iaConfig?.archivosAdjuntos || [],
},
}
console.log(`${new Date().toISOString()} - Enviando a generar plan IA`)
const data = await generatePlanAI.mutateAsync(aiInput as any)
console.log(`${new Date().toISOString()} - Plan IA generado`, data)
navigate({ to: `/planes/${data.plan.id}` })
return
}
// Fallback mocks for non-IA origins
await new Promise((r) => setTimeout(r, 900))
const nuevoId = (() => {
if (wizard.tipoOrigen === 'MANUAL') return 'plan_new_manual_001'
if (
wizard.tipoOrigen === 'CLONADO_INTERNO' ||
wizard.tipoOrigen === 'CLONADO_TRADICIONAL'
)
return 'plan_new_clone_001'
return 'plan_new_import_001'
})()
navigate({ to: `/planes/${nuevoId}` })
} catch (err: any) {
setWizard((w) => ({
...w,
isLoading: false,
errorMessage: err?.message ?? 'Error generando el plan',
}))
} finally {
setWizard((w) => ({ ...w, isLoading: false }))
}
}
return ( return (
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex-1"> <div className="flex-1">
@@ -33,7 +114,7 @@ export function WizardControls({
Anterior Anterior
</Button> </Button>
{isLastStep ? ( {isLastStep ? (
<Button onClick={onCreate} disabled={disableCreate}> <Button onClick={handleCreate} disabled={disableCreate}>
Crear plan Crear plan
</Button> </Button>
) : ( ) : (

View File

@@ -116,11 +116,27 @@ export function useCreatePlanManual() {
} }
export function useGeneratePlanAI() { export function useGeneratePlanAI() {
const qc = useQueryClient()
return useMutation({ return useMutation({
mutationFn: ai_generate_plan, mutationFn: ai_generate_plan,
onSuccess: (data) => {
// Asumiendo que la Edge Function devuelve { ok: true, plan: { id: ... } }
console.log('success de ai_generate_plan')
const newPlan = data.plan
if (newPlan) {
// 1. Invalidar la lista para que aparezca el nuevo plan
qc.invalidateQueries({ queryKey: ['planes', 'list'] })
// 2. (Opcional) Pre-cargar el dato individual para que la navegación sea instantánea
// qc.setQueryData(["planes", "detail", newPlan.id], newPlan);
}
},
}) })
} }
// Funcion obsoleta porque ahora el plan se persiste directamente en useGeneratePlanAI
export function usePersistPlanFromAI() { export function usePersistPlanFromAI() {
const qc = useQueryClient() const qc = useQueryClient()

View File

@@ -3,7 +3,7 @@ import * as Icons from 'lucide-react'
import { useNuevoPlanWizard } from './hooks/useNuevoPlanWizard' import { useNuevoPlanWizard } from './hooks/useNuevoPlanWizard'
import type { NewPlanWizardState } from './types' // import type { NewPlanWizardState } from './types'
import { PasoBasicosForm } from '@/components/planes/wizard/PasoBasicosForm/PasoBasicosForm' import { PasoBasicosForm } from '@/components/planes/wizard/PasoBasicosForm/PasoBasicosForm'
import { PasoDetallesPanel } from '@/components/planes/wizard/PasoDetallesPanel/PasoDetallesPanel' import { PasoDetallesPanel } from '@/components/planes/wizard/PasoDetallesPanel/PasoDetallesPanel'
@@ -25,7 +25,7 @@ import {
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from '@/components/ui/dialog' } from '@/components/ui/dialog'
import { useGeneratePlanAI } from '@/data/hooks/usePlans' // import { useGeneratePlanAI } from '@/data/hooks/usePlans'
// Mock de permisos/rol // Mock de permisos/rol
const auth_get_current_user_role = () => 'JEFE_CARRERA' as const const auth_get_current_user_role = () => 'JEFE_CARRERA' as const
@@ -48,8 +48,7 @@ const Wizard = defineStepper(
export default function NuevoPlanModalContainer() { export default function NuevoPlanModalContainer() {
const navigate = useNavigate() const navigate = useNavigate()
const role = auth_get_current_user_role() const role = auth_get_current_user_role()
const generatePlanAI = useGeneratePlanAI() // const generatePlanAI = useGeneratePlanAI()
// const persistPlanFromAI = usePersistPlanFromAI()
const { const {
wizard, wizard,
@@ -63,74 +62,7 @@ export default function NuevoPlanModalContainer() {
navigate({ to: '/planes', resetScroll: false }) navigate({ to: '/planes', resetScroll: false })
} }
const crearPlan = async () => { // Crear plan: ahora la lógica vive en WizardControls
setWizard(
(w: NewPlanWizardState): NewPlanWizardState => ({
...w,
isLoading: true,
errorMessage: null,
}),
)
try {
if (wizard.tipoOrigen === 'IA') {
const tipoCicloSafe = (wizard.datosBasicos.tipoCiclo ||
'Semestre') as any
const numCiclosSafe =
typeof wizard.datosBasicos.numCiclos === 'number'
? wizard.datosBasicos.numCiclos
: 1
const aiInput = {
datosBasicos: {
nombrePlan: wizard.datosBasicos.nombrePlan,
carreraId: wizard.datosBasicos.carreraId,
facultadId: wizard.datosBasicos.facultadId || undefined,
nivel: wizard.datosBasicos.nivel as string,
tipoCiclo: tipoCicloSafe,
numCiclos: numCiclosSafe,
estructuraPlanId: wizard.datosBasicos.estructuraPlanId as string,
},
iaConfig: {
descripcionEnfoque: wizard.iaConfig?.descripcionEnfoque || '',
notasAdicionales: wizard.iaConfig?.notasAdicionales || '',
archivosReferencia: wizard.iaConfig?.archivosReferencia || [],
repositoriosIds: wizard.iaConfig?.repositoriosReferencia || [],
archivosAdjuntos: wizard.iaConfig?.archivosAdjuntos || [],
},
}
const response = await generatePlanAI.mutateAsync(aiInput as any)
// const createdPlan = await persistPlanFromAI.mutateAsync({
// jsonPlan: generatedJson,
// })
// navigate({ to: `/planes/${createdPlan.id}` })
console.log('Plan generado por IA:', response)
return
}
// Fallback: comportamiento previo para otros modos (mock IDs)
await new Promise((r) => setTimeout(r, 900))
const nuevoId = (() => {
if (wizard.tipoOrigen === 'MANUAL') return 'plan_new_manual_001'
if (
wizard.tipoOrigen === 'CLONADO_INTERNO' ||
wizard.tipoOrigen === 'CLONADO_TRADICIONAL'
)
return 'plan_new_clone_001'
return 'plan_new_import_001'
})()
navigate({ to: `/planes/${nuevoId}` })
} catch (err: any) {
setWizard((w) => ({
...w,
isLoading: false,
errorMessage: err?.message ?? 'Error generando el plan con IA',
}))
} finally {
setWizard((w) => ({ ...w, isLoading: false }))
}
}
return ( return (
<Dialog open={true} onOpenChange={(open) => !open && handleClose()}> <Dialog open={true} onOpenChange={(open) => !open && handleClose()}>
@@ -233,7 +165,6 @@ export default function NuevoPlanModalContainer() {
errorMessage={wizard.errorMessage} errorMessage={wizard.errorMessage}
onPrev={() => methods.prev()} onPrev={() => methods.prev()}
onNext={() => methods.next()} onNext={() => methods.next()}
onCreate={crearPlan}
disablePrev={ disablePrev={
Wizard.utils.getIndex(methods.current.id) === 0 || Wizard.utils.getIndex(methods.current.id) === 0 ||
wizard.isLoading wizard.isLoading
@@ -252,6 +183,8 @@ export default function NuevoPlanModalContainer() {
Wizard.utils.getIndex(methods.current.id) >= Wizard.utils.getIndex(methods.current.id) >=
Wizard.steps.length - 1 Wizard.steps.length - 1
} }
wizard={wizard}
setWizard={setWizard}
/> />
</Wizard.Stepper.Controls> </Wizard.Stepper.Controls>
</div> </div>

View File

@@ -1,17 +1,17 @@
import { useState } from "react"; import { useState } from 'react'
import type { NewPlanWizardState } from "../types"; import type { NewPlanWizardState } from '../types'
export function useNuevoPlanWizard() { export function useNuevoPlanWizard() {
const [wizard, setWizard] = useState<NewPlanWizardState>({ const [wizard, setWizard] = useState<NewPlanWizardState>({
step: 1, step: 1,
tipoOrigen: null, tipoOrigen: null,
datosBasicos: { datosBasicos: {
nombrePlan: "", nombrePlan: '',
carreraId: "", carreraId: '',
facultadId: "", facultadId: '',
nivel: "", nivel: '',
tipoCiclo: "", tipoCiclo: '',
numCiclos: undefined, numCiclos: undefined,
estructuraPlanId: null, estructuraPlanId: null,
}, },
@@ -34,8 +34,8 @@ export function useNuevoPlanWizard() {
archivoAsignaturasExcelId: null, archivoAsignaturasExcelId: null,
}, },
iaConfig: { iaConfig: {
descripcionEnfoque: "", descripcionEnfoque: '',
notasAdicionales: "", notasAdicionales: '',
archivosReferencia: [], archivosReferencia: [],
repositoriosReferencia: [], repositoriosReferencia: [],
archivosAdjuntos: [], archivosAdjuntos: [],
@@ -43,42 +43,43 @@ export function useNuevoPlanWizard() {
resumen: {}, resumen: {},
isLoading: false, isLoading: false,
errorMessage: null, errorMessage: null,
}); })
const canContinueDesdeModo = wizard.tipoOrigen === "MANUAL" || const canContinueDesdeModo =
wizard.tipoOrigen === "IA" || wizard.tipoOrigen === 'MANUAL' ||
(wizard.tipoOrigen === "CLONADO_INTERNO" || wizard.tipoOrigen === 'IA' ||
wizard.tipoOrigen === "CLONADO_TRADICIONAL"); wizard.tipoOrigen === 'CLONADO_INTERNO' ||
wizard.tipoOrigen === 'CLONADO_TRADICIONAL'
const canContinueDesdeBasicos = !!wizard.datosBasicos.nombrePlan && const canContinueDesdeBasicos =
!!wizard.datosBasicos.nombrePlan &&
!!wizard.datosBasicos.carreraId && !!wizard.datosBasicos.carreraId &&
!!wizard.datosBasicos.facultadId && !!wizard.datosBasicos.facultadId &&
!!wizard.datosBasicos.nivel && !!wizard.datosBasicos.nivel &&
(wizard.datosBasicos.numCiclos !== undefined && wizard.datosBasicos.numCiclos !== undefined &&
wizard.datosBasicos.numCiclos > 0) && wizard.datosBasicos.numCiclos > 0 &&
// Requerir ambas plantillas (plan y mapa) con versión // Requerir ambas plantillas (plan y mapa) con versión
!!wizard.datosBasicos.estructuraPlanId; !!wizard.datosBasicos.estructuraPlanId
const canContinueDesdeDetalles = (() => { const canContinueDesdeDetalles = (() => {
if (wizard.tipoOrigen === "MANUAL") return true; if (wizard.tipoOrigen === 'MANUAL') return true
if (wizard.tipoOrigen === "IA") { if (wizard.tipoOrigen === 'IA') {
// Requerimos descripción del enfoque y notas adicionales // Requerimos descripción del enfoque y notas adicionales
return !!wizard.iaConfig?.descripcionEnfoque && return !!wizard.iaConfig?.descripcionEnfoque
!!wizard.iaConfig.notasAdicionales;
} }
if (wizard.tipoOrigen === "CLONADO_INTERNO") { if (wizard.tipoOrigen === 'CLONADO_INTERNO') {
return !!wizard.clonInterno?.planOrigenId; return !!wizard.clonInterno?.planOrigenId
} }
if (wizard.tipoOrigen === "CLONADO_TRADICIONAL") { if (wizard.tipoOrigen === 'CLONADO_TRADICIONAL') {
const t = wizard.clonTradicional; const t = wizard.clonTradicional
if (!t) return false; if (!t) return false
const tieneWord = !!t.archivoWordPlanId; const tieneWord = !!t.archivoWordPlanId
const tieneAlMenosUnExcel = !!t.archivoMapaExcelId || const tieneAlMenosUnExcel =
!!t.archivoAsignaturasExcelId; !!t.archivoMapaExcelId || !!t.archivoAsignaturasExcelId
return tieneWord && tieneAlMenosUnExcel; return tieneWord && tieneAlMenosUnExcel
} }
return false; return false
})(); })()
return { return {
wizard, wizard,
@@ -86,5 +87,5 @@ export function useNuevoPlanWizard() {
canContinueDesdeModo, canContinueDesdeModo,
canContinueDesdeBasicos, canContinueDesdeBasicos,
canContinueDesdeDetalles, canContinueDesdeDetalles,
}; }
} }

View File

@@ -1,65 +1,61 @@
import type { UploadedFile } from "@/components/planes/wizard/PasoDetallesPanel/FileDropZone"; import type { UploadedFile } from '@/components/planes/wizard/PasoDetallesPanel/FileDropZone'
import type { import type {
NivelPlanEstudio, NivelPlanEstudio,
TipoCiclo, TipoCiclo,
TipoOrigen, TipoOrigen,
} from "@/data/types/domain"; } from '@/data/types/domain'
export type PlanPreview = { export type PlanPreview = {
nombrePlan: string; nombrePlan: string
nivel: NivelPlanEstudio; nivel: NivelPlanEstudio
tipoCiclo: TipoCiclo; tipoCiclo: TipoCiclo
numCiclos: number; numCiclos: number
numAsignaturasAprox?: number; numAsignaturasAprox?: number
secciones?: Array<{ id: string; titulo: string; resumen: string }>; secciones?: Array<{ id: string; titulo: string; resumen: string }>
}; }
export type NewPlanWizardState = { export type NewPlanWizardState = {
step: 1 | 2 | 3 | 4; step: 1 | 2 | 3 | 4
tipoOrigen: TipoOrigen | null; tipoOrigen: TipoOrigen | null
datosBasicos: { datosBasicos: {
nombrePlan: string; nombrePlan: string
carreraId: string; carreraId: string
facultadId: string; facultadId: string
nivel: NivelPlanEstudio | ""; nivel: NivelPlanEstudio | ''
tipoCiclo: TipoCiclo | ""; tipoCiclo: TipoCiclo | ''
numCiclos: number | undefined; numCiclos: number | undefined
// Selección de plantillas (obligatorias) // Selección de plantillas (obligatorias)
estructuraPlanId: string | null; estructuraPlanId: string | null
};
clonInterno?: { planOrigenId: string | null };
clonTradicional?: {
archivoWordPlanId:
| {
id: string;
name: string;
size: string;
type: string;
} }
| null; clonInterno?: { planOrigenId: string | null }
clonTradicional?: {
archivoWordPlanId: {
id: string
name: string
size: string
type: string
} | null
archivoMapaExcelId: { archivoMapaExcelId: {
id: string; id: string
name: string; name: string
size: string; size: string
type: string; type: string
} | null; } | null
archivoAsignaturasExcelId: { archivoAsignaturasExcelId: {
id: string; id: string
name: string; name: string
size: string; size: string
type: string; type: string
} | null; } | null
}; }
iaConfig?: { iaConfig?: {
descripcionEnfoque: string; descripcionEnfoque: string
notasAdicionales: string; notasAdicionales?: string
archivosReferencia: Array<string>; archivosReferencia: Array<string>
repositoriosReferencia?: Array<string>; repositoriosReferencia?: Array<string>
archivosAdjuntos?: Array< archivosAdjuntos?: Array<UploadedFile>
UploadedFile }
>; resumen: { previewPlan?: PlanPreview }
}; isLoading: boolean
resumen: { previewPlan?: PlanPreview }; errorMessage: string | null
isLoading: boolean; }
errorMessage: string | null;
};

View File

@@ -12,7 +12,6 @@ import { Route as rootRouteImport } from './routes/__root'
import { Route as LoginRouteImport } from './routes/login' import { Route as LoginRouteImport } from './routes/login'
import { Route as DashboardRouteImport } from './routes/dashboard' import { Route as DashboardRouteImport } from './routes/dashboard'
import { Route as IndexRouteImport } from './routes/index' import { Route as IndexRouteImport } from './routes/index'
import { Route as PlanesPlanesListRouteRouteImport } from './routes/planes/PlanesListRoute'
import { Route as DemoTanstackQueryRouteImport } from './routes/demo/tanstack-query' import { Route as DemoTanstackQueryRouteImport } from './routes/demo/tanstack-query'
import { Route as PlanesListaRouteRouteImport } from './routes/planes/_lista/route' import { Route as PlanesListaRouteRouteImport } from './routes/planes/_lista/route'
import { Route as PlanesPlanIdIndexRouteImport } from './routes/planes/$planId/index' import { Route as PlanesPlanIdIndexRouteImport } from './routes/planes/$planId/index'
@@ -46,11 +45,6 @@ const IndexRoute = IndexRouteImport.update({
path: '/', path: '/',
getParentRoute: () => rootRouteImport, getParentRoute: () => rootRouteImport,
} as any) } as any)
const PlanesPlanesListRouteRoute = PlanesPlanesListRouteRouteImport.update({
id: '/planes/PlanesListRoute',
path: '/planes/PlanesListRoute',
getParentRoute: () => rootRouteImport,
} as any)
const DemoTanstackQueryRoute = DemoTanstackQueryRouteImport.update({ const DemoTanstackQueryRoute = DemoTanstackQueryRouteImport.update({
id: '/demo/tanstack-query', id: '/demo/tanstack-query',
path: '/demo/tanstack-query', path: '/demo/tanstack-query',
@@ -154,8 +148,7 @@ export interface FileRoutesByFullPath {
'/login': typeof LoginRoute '/login': typeof LoginRoute
'/planes': typeof PlanesListaRouteRouteWithChildren '/planes': typeof PlanesListaRouteRouteWithChildren
'/demo/tanstack-query': typeof DemoTanstackQueryRoute '/demo/tanstack-query': typeof DemoTanstackQueryRoute
'/planes/PlanesListRoute': typeof PlanesPlanesListRouteRoute '/planes/$planId': typeof PlanesPlanIdIndexRoute
'/planes/$planId': typeof PlanesPlanIdDetalleRouteRouteWithChildren
'/planes/$planId/asignaturas': typeof PlanesPlanIdAsignaturasListaRouteRouteWithChildren '/planes/$planId/asignaturas': typeof PlanesPlanIdAsignaturasListaRouteRouteWithChildren
'/planes/nuevo': typeof PlanesListaNuevoRoute '/planes/nuevo': typeof PlanesListaNuevoRoute
'/planes/$planId/': typeof PlanesPlanIdIndexRoute '/planes/$planId/': typeof PlanesPlanIdIndexRoute
@@ -176,7 +169,10 @@ export interface FileRoutesByTo {
'/login': typeof LoginRoute '/login': typeof LoginRoute
'/planes': typeof PlanesListaRouteRouteWithChildren '/planes': typeof PlanesListaRouteRouteWithChildren
'/demo/tanstack-query': typeof DemoTanstackQueryRoute '/demo/tanstack-query': typeof DemoTanstackQueryRoute
<<<<<<< HEAD
'/planes/PlanesListRoute': typeof PlanesPlanesListRouteRoute '/planes/PlanesListRoute': typeof PlanesPlanesListRouteRoute
=======
>>>>>>> 4950f7efbf664bbd31ac8a673fe594af5baf07f6
'/planes/$planId': typeof PlanesPlanIdIndexRoute '/planes/$planId': typeof PlanesPlanIdIndexRoute
'/planes/nuevo': typeof PlanesListaNuevoRoute '/planes/nuevo': typeof PlanesListaNuevoRoute
'/planes/$planId/asignaturas/$asignaturaId': typeof PlanesPlanIdAsignaturasAsignaturaIdRouteRoute '/planes/$planId/asignaturas/$asignaturaId': typeof PlanesPlanIdAsignaturasAsignaturaIdRouteRoute
@@ -197,7 +193,6 @@ export interface FileRoutesById {
'/login': typeof LoginRoute '/login': typeof LoginRoute
'/planes/_lista': typeof PlanesListaRouteRouteWithChildren '/planes/_lista': typeof PlanesListaRouteRouteWithChildren
'/demo/tanstack-query': typeof DemoTanstackQueryRoute '/demo/tanstack-query': typeof DemoTanstackQueryRoute
'/planes/PlanesListRoute': typeof PlanesPlanesListRouteRoute
'/planes/$planId/_detalle': typeof PlanesPlanIdDetalleRouteRouteWithChildren '/planes/$planId/_detalle': typeof PlanesPlanIdDetalleRouteRouteWithChildren
'/planes/$planId/asignaturas': typeof PlanesPlanIdAsignaturasRouteRouteWithChildren '/planes/$planId/asignaturas': typeof PlanesPlanIdAsignaturasRouteRouteWithChildren
'/planes/_lista/nuevo': typeof PlanesListaNuevoRoute '/planes/_lista/nuevo': typeof PlanesListaNuevoRoute
@@ -222,7 +217,6 @@ export interface FileRouteTypes {
| '/login' | '/login'
| '/planes' | '/planes'
| '/demo/tanstack-query' | '/demo/tanstack-query'
| '/planes/PlanesListRoute'
| '/planes/$planId' | '/planes/$planId'
| '/planes/$planId/asignaturas' | '/planes/$planId/asignaturas'
| '/planes/nuevo' | '/planes/nuevo'
@@ -244,7 +238,6 @@ export interface FileRouteTypes {
| '/login' | '/login'
| '/planes' | '/planes'
| '/demo/tanstack-query' | '/demo/tanstack-query'
| '/planes/PlanesListRoute'
| '/planes/$planId' | '/planes/$planId'
| '/planes/nuevo' | '/planes/nuevo'
| '/planes/$planId/asignaturas/$asignaturaId' | '/planes/$planId/asignaturas/$asignaturaId'
@@ -264,7 +257,6 @@ export interface FileRouteTypes {
| '/login' | '/login'
| '/planes/_lista' | '/planes/_lista'
| '/demo/tanstack-query' | '/demo/tanstack-query'
| '/planes/PlanesListRoute'
| '/planes/$planId/_detalle' | '/planes/$planId/_detalle'
| '/planes/$planId/asignaturas' | '/planes/$planId/asignaturas'
| '/planes/_lista/nuevo' | '/planes/_lista/nuevo'
@@ -288,7 +280,6 @@ export interface RootRouteChildren {
LoginRoute: typeof LoginRoute LoginRoute: typeof LoginRoute
PlanesListaRouteRoute: typeof PlanesListaRouteRouteWithChildren PlanesListaRouteRoute: typeof PlanesListaRouteRouteWithChildren
DemoTanstackQueryRoute: typeof DemoTanstackQueryRoute DemoTanstackQueryRoute: typeof DemoTanstackQueryRoute
PlanesPlanesListRouteRoute: typeof PlanesPlanesListRouteRoute
PlanesPlanIdDetalleRouteRoute: typeof PlanesPlanIdDetalleRouteRouteWithChildren PlanesPlanIdDetalleRouteRoute: typeof PlanesPlanIdDetalleRouteRouteWithChildren
PlanesPlanIdAsignaturasRouteRoute: typeof PlanesPlanIdAsignaturasRouteRouteWithChildren PlanesPlanIdAsignaturasRouteRoute: typeof PlanesPlanIdAsignaturasRouteRouteWithChildren
PlanesPlanIdIndexRoute: typeof PlanesPlanIdIndexRoute PlanesPlanIdIndexRoute: typeof PlanesPlanIdIndexRoute
@@ -317,13 +308,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof IndexRouteImport preLoaderRoute: typeof IndexRouteImport
parentRoute: typeof rootRouteImport parentRoute: typeof rootRouteImport
} }
'/planes/PlanesListRoute': {
id: '/planes/PlanesListRoute'
path: '/planes/PlanesListRoute'
fullPath: '/planes/PlanesListRoute'
preLoaderRoute: typeof PlanesPlanesListRouteRouteImport
parentRoute: typeof rootRouteImport
}
'/demo/tanstack-query': { '/demo/tanstack-query': {
id: '/demo/tanstack-query' id: '/demo/tanstack-query'
path: '/demo/tanstack-query' path: '/demo/tanstack-query'
@@ -341,7 +325,11 @@ declare module '@tanstack/react-router' {
'/planes/$planId/': { '/planes/$planId/': {
id: '/planes/$planId/' id: '/planes/$planId/'
path: '/planes/$planId' path: '/planes/$planId'
<<<<<<< HEAD
fullPath: '/planes/$planId/' fullPath: '/planes/$planId/'
=======
fullPath: '/planes/$planId'
>>>>>>> 4950f7efbf664bbd31ac8a673fe594af5baf07f6
preLoaderRoute: typeof PlanesPlanIdIndexRouteImport preLoaderRoute: typeof PlanesPlanIdIndexRouteImport
parentRoute: typeof rootRouteImport parentRoute: typeof rootRouteImport
} }
@@ -524,7 +512,6 @@ const rootRouteChildren: RootRouteChildren = {
LoginRoute: LoginRoute, LoginRoute: LoginRoute,
PlanesListaRouteRoute: PlanesListaRouteRouteWithChildren, PlanesListaRouteRoute: PlanesListaRouteRouteWithChildren,
DemoTanstackQueryRoute: DemoTanstackQueryRoute, DemoTanstackQueryRoute: DemoTanstackQueryRoute,
PlanesPlanesListRouteRoute: PlanesPlanesListRouteRoute,
PlanesPlanIdDetalleRouteRoute: PlanesPlanIdDetalleRouteRouteWithChildren, PlanesPlanIdDetalleRouteRoute: PlanesPlanIdDetalleRouteRouteWithChildren,
PlanesPlanIdAsignaturasRouteRoute: PlanesPlanIdAsignaturasRouteRoute:
PlanesPlanIdAsignaturasRouteRouteWithChildren, PlanesPlanIdAsignaturasRouteRouteWithChildren,

View File

@@ -1,42 +0,0 @@
import { createFileRoute } from '@tanstack/react-router'
import { useMemo, useState } from 'react'
import { usePlanes } from '@/data'
export const Route = createFileRoute('/planes/PlanesListRoute')({
component: RouteComponent,
})
function RouteComponent() {
const [search, setSearch] = useState('')
const filters = useMemo(
() => ({ search, limit: 20, offset: 0, activo: true }),
[search],
)
const { data, isLoading, isError, error } = usePlanes(filters)
return (
<div style={{ padding: 16 }}>
<h1>Planes</h1>
<input
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="Buscar…"
/>
{isLoading && <div>Cargando</div>}
{isError && <div>Error: {(error as any).message}</div>}
<ul>
{(data?.data ?? []).map((p) => (
<li key={p.id}>
<pre>{JSON.stringify(p, null, 2)}</pre>
</li>
))}
</ul>
</div>
)
}