feat: Add dashboard and asignaturas routes with corresponding components
This commit is contained in:
@@ -14,6 +14,8 @@ import { Route as AuthenticatedRouteImport } from './routes/_authenticated'
|
|||||||
import { Route as IndexRouteImport } from './routes/index'
|
import { Route as IndexRouteImport } from './routes/index'
|
||||||
import { Route as AuthenticatedPlanesRouteImport } from './routes/_authenticated/planes'
|
import { Route as AuthenticatedPlanesRouteImport } from './routes/_authenticated/planes'
|
||||||
import { Route as AuthenticatedFacultadesRouteImport } from './routes/_authenticated/facultades'
|
import { Route as AuthenticatedFacultadesRouteImport } from './routes/_authenticated/facultades'
|
||||||
|
import { Route as AuthenticatedDashboardRouteImport } from './routes/_authenticated/dashboard'
|
||||||
|
import { Route as AuthenticatedAsignaturasRouteImport } from './routes/_authenticated/asignaturas'
|
||||||
import { Route as AuthenticatedPlanesPlanIdRouteImport } from './routes/_authenticated/planes/$planId'
|
import { Route as AuthenticatedPlanesPlanIdRouteImport } from './routes/_authenticated/planes/$planId'
|
||||||
import { Route as AuthenticatedFacultadFacultadIdRouteImport } from './routes/_authenticated/facultad/$facultadId'
|
import { Route as AuthenticatedFacultadFacultadIdRouteImport } from './routes/_authenticated/facultad/$facultadId'
|
||||||
import { Route as AuthenticatedPlanesPlanIdModalRouteImport } from './routes/_authenticated/planes/$planId/modal'
|
import { Route as AuthenticatedPlanesPlanIdModalRouteImport } from './routes/_authenticated/planes/$planId/modal'
|
||||||
@@ -42,6 +44,17 @@ const AuthenticatedFacultadesRoute = AuthenticatedFacultadesRouteImport.update({
|
|||||||
path: '/facultades',
|
path: '/facultades',
|
||||||
getParentRoute: () => AuthenticatedRoute,
|
getParentRoute: () => AuthenticatedRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
const AuthenticatedDashboardRoute = AuthenticatedDashboardRouteImport.update({
|
||||||
|
id: '/dashboard',
|
||||||
|
path: '/dashboard',
|
||||||
|
getParentRoute: () => AuthenticatedRoute,
|
||||||
|
} as any)
|
||||||
|
const AuthenticatedAsignaturasRoute =
|
||||||
|
AuthenticatedAsignaturasRouteImport.update({
|
||||||
|
id: '/asignaturas',
|
||||||
|
path: '/asignaturas',
|
||||||
|
getParentRoute: () => AuthenticatedRoute,
|
||||||
|
} as any)
|
||||||
const AuthenticatedPlanesPlanIdRoute =
|
const AuthenticatedPlanesPlanIdRoute =
|
||||||
AuthenticatedPlanesPlanIdRouteImport.update({
|
AuthenticatedPlanesPlanIdRouteImport.update({
|
||||||
id: '/$planId',
|
id: '/$planId',
|
||||||
@@ -64,6 +77,8 @@ const AuthenticatedPlanesPlanIdModalRoute =
|
|||||||
export interface FileRoutesByFullPath {
|
export interface FileRoutesByFullPath {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/login': typeof LoginRoute
|
'/login': typeof LoginRoute
|
||||||
|
'/asignaturas': typeof AuthenticatedAsignaturasRoute
|
||||||
|
'/dashboard': typeof AuthenticatedDashboardRoute
|
||||||
'/facultades': typeof AuthenticatedFacultadesRoute
|
'/facultades': typeof AuthenticatedFacultadesRoute
|
||||||
'/planes': typeof AuthenticatedPlanesRouteWithChildren
|
'/planes': typeof AuthenticatedPlanesRouteWithChildren
|
||||||
'/facultad/$facultadId': typeof AuthenticatedFacultadFacultadIdRoute
|
'/facultad/$facultadId': typeof AuthenticatedFacultadFacultadIdRoute
|
||||||
@@ -73,6 +88,8 @@ export interface FileRoutesByFullPath {
|
|||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/login': typeof LoginRoute
|
'/login': typeof LoginRoute
|
||||||
|
'/asignaturas': typeof AuthenticatedAsignaturasRoute
|
||||||
|
'/dashboard': typeof AuthenticatedDashboardRoute
|
||||||
'/facultades': typeof AuthenticatedFacultadesRoute
|
'/facultades': typeof AuthenticatedFacultadesRoute
|
||||||
'/planes': typeof AuthenticatedPlanesRouteWithChildren
|
'/planes': typeof AuthenticatedPlanesRouteWithChildren
|
||||||
'/facultad/$facultadId': typeof AuthenticatedFacultadFacultadIdRoute
|
'/facultad/$facultadId': typeof AuthenticatedFacultadFacultadIdRoute
|
||||||
@@ -84,6 +101,8 @@ export interface FileRoutesById {
|
|||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/_authenticated': typeof AuthenticatedRouteWithChildren
|
'/_authenticated': typeof AuthenticatedRouteWithChildren
|
||||||
'/login': typeof LoginRoute
|
'/login': typeof LoginRoute
|
||||||
|
'/_authenticated/asignaturas': typeof AuthenticatedAsignaturasRoute
|
||||||
|
'/_authenticated/dashboard': typeof AuthenticatedDashboardRoute
|
||||||
'/_authenticated/facultades': typeof AuthenticatedFacultadesRoute
|
'/_authenticated/facultades': typeof AuthenticatedFacultadesRoute
|
||||||
'/_authenticated/planes': typeof AuthenticatedPlanesRouteWithChildren
|
'/_authenticated/planes': typeof AuthenticatedPlanesRouteWithChildren
|
||||||
'/_authenticated/facultad/$facultadId': typeof AuthenticatedFacultadFacultadIdRoute
|
'/_authenticated/facultad/$facultadId': typeof AuthenticatedFacultadFacultadIdRoute
|
||||||
@@ -95,6 +114,8 @@ export interface FileRouteTypes {
|
|||||||
fullPaths:
|
fullPaths:
|
||||||
| '/'
|
| '/'
|
||||||
| '/login'
|
| '/login'
|
||||||
|
| '/asignaturas'
|
||||||
|
| '/dashboard'
|
||||||
| '/facultades'
|
| '/facultades'
|
||||||
| '/planes'
|
| '/planes'
|
||||||
| '/facultad/$facultadId'
|
| '/facultad/$facultadId'
|
||||||
@@ -104,6 +125,8 @@ export interface FileRouteTypes {
|
|||||||
to:
|
to:
|
||||||
| '/'
|
| '/'
|
||||||
| '/login'
|
| '/login'
|
||||||
|
| '/asignaturas'
|
||||||
|
| '/dashboard'
|
||||||
| '/facultades'
|
| '/facultades'
|
||||||
| '/planes'
|
| '/planes'
|
||||||
| '/facultad/$facultadId'
|
| '/facultad/$facultadId'
|
||||||
@@ -114,6 +137,8 @@ export interface FileRouteTypes {
|
|||||||
| '/'
|
| '/'
|
||||||
| '/_authenticated'
|
| '/_authenticated'
|
||||||
| '/login'
|
| '/login'
|
||||||
|
| '/_authenticated/asignaturas'
|
||||||
|
| '/_authenticated/dashboard'
|
||||||
| '/_authenticated/facultades'
|
| '/_authenticated/facultades'
|
||||||
| '/_authenticated/planes'
|
| '/_authenticated/planes'
|
||||||
| '/_authenticated/facultad/$facultadId'
|
| '/_authenticated/facultad/$facultadId'
|
||||||
@@ -164,6 +189,20 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof AuthenticatedFacultadesRouteImport
|
preLoaderRoute: typeof AuthenticatedFacultadesRouteImport
|
||||||
parentRoute: typeof AuthenticatedRoute
|
parentRoute: typeof AuthenticatedRoute
|
||||||
}
|
}
|
||||||
|
'/_authenticated/dashboard': {
|
||||||
|
id: '/_authenticated/dashboard'
|
||||||
|
path: '/dashboard'
|
||||||
|
fullPath: '/dashboard'
|
||||||
|
preLoaderRoute: typeof AuthenticatedDashboardRouteImport
|
||||||
|
parentRoute: typeof AuthenticatedRoute
|
||||||
|
}
|
||||||
|
'/_authenticated/asignaturas': {
|
||||||
|
id: '/_authenticated/asignaturas'
|
||||||
|
path: '/asignaturas'
|
||||||
|
fullPath: '/asignaturas'
|
||||||
|
preLoaderRoute: typeof AuthenticatedAsignaturasRouteImport
|
||||||
|
parentRoute: typeof AuthenticatedRoute
|
||||||
|
}
|
||||||
'/_authenticated/planes/$planId': {
|
'/_authenticated/planes/$planId': {
|
||||||
id: '/_authenticated/planes/$planId'
|
id: '/_authenticated/planes/$planId'
|
||||||
path: '/$planId'
|
path: '/$planId'
|
||||||
@@ -214,12 +253,16 @@ const AuthenticatedPlanesRouteWithChildren =
|
|||||||
AuthenticatedPlanesRoute._addFileChildren(AuthenticatedPlanesRouteChildren)
|
AuthenticatedPlanesRoute._addFileChildren(AuthenticatedPlanesRouteChildren)
|
||||||
|
|
||||||
interface AuthenticatedRouteChildren {
|
interface AuthenticatedRouteChildren {
|
||||||
|
AuthenticatedAsignaturasRoute: typeof AuthenticatedAsignaturasRoute
|
||||||
|
AuthenticatedDashboardRoute: typeof AuthenticatedDashboardRoute
|
||||||
AuthenticatedFacultadesRoute: typeof AuthenticatedFacultadesRoute
|
AuthenticatedFacultadesRoute: typeof AuthenticatedFacultadesRoute
|
||||||
AuthenticatedPlanesRoute: typeof AuthenticatedPlanesRouteWithChildren
|
AuthenticatedPlanesRoute: typeof AuthenticatedPlanesRouteWithChildren
|
||||||
AuthenticatedFacultadFacultadIdRoute: typeof AuthenticatedFacultadFacultadIdRoute
|
AuthenticatedFacultadFacultadIdRoute: typeof AuthenticatedFacultadFacultadIdRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
const AuthenticatedRouteChildren: AuthenticatedRouteChildren = {
|
const AuthenticatedRouteChildren: AuthenticatedRouteChildren = {
|
||||||
|
AuthenticatedAsignaturasRoute: AuthenticatedAsignaturasRoute,
|
||||||
|
AuthenticatedDashboardRoute: AuthenticatedDashboardRoute,
|
||||||
AuthenticatedFacultadesRoute: AuthenticatedFacultadesRoute,
|
AuthenticatedFacultadesRoute: AuthenticatedFacultadesRoute,
|
||||||
AuthenticatedPlanesRoute: AuthenticatedPlanesRouteWithChildren,
|
AuthenticatedPlanesRoute: AuthenticatedPlanesRouteWithChildren,
|
||||||
AuthenticatedFacultadFacultadIdRoute: AuthenticatedFacultadFacultadIdRoute,
|
AuthenticatedFacultadFacultadIdRoute: AuthenticatedFacultadFacultadIdRoute,
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import {
|
|||||||
LayoutDashboard,
|
LayoutDashboard,
|
||||||
GraduationCap,
|
GraduationCap,
|
||||||
FileText,
|
FileText,
|
||||||
Settings,
|
|
||||||
LogOut,
|
LogOut,
|
||||||
KeySquare,
|
KeySquare,
|
||||||
IdCard,
|
IdCard,
|
||||||
@@ -40,9 +39,8 @@ export const Route = createFileRoute("/_authenticated")({
|
|||||||
|
|
||||||
const nav = [
|
const nav = [
|
||||||
{ to: "/planes", label: "Planes", icon: GraduationCap },
|
{ to: "/planes", label: "Planes", icon: GraduationCap },
|
||||||
{ to: "/materias", label: "Materias", icon: FileText },
|
{ to: "/asignaturas", label: "Asignaturas", icon: FileText },
|
||||||
{ to: "/dashboard", label: "Dashboard", icon: LayoutDashboard },
|
{ to: "/dashboard", label: "Dashboard", icon: LayoutDashboard },
|
||||||
{ to: "/ajustes", label: "Ajustes", icon: Settings },
|
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
function getInitials(name?: string) {
|
function getInitials(name?: string) {
|
||||||
|
|||||||
9
src/routes/_authenticated/asignaturas.tsx
Normal file
9
src/routes/_authenticated/asignaturas.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { createFileRoute } from '@tanstack/react-router'
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/_authenticated/asignaturas')({
|
||||||
|
component: RouteComponent,
|
||||||
|
})
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
return <div>Hello "/_authenticated/asignaturas"!</div>
|
||||||
|
}
|
||||||
9
src/routes/_authenticated/dashboard.tsx
Normal file
9
src/routes/_authenticated/dashboard.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { createFileRoute } from '@tanstack/react-router'
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/_authenticated/dashboard')({
|
||||||
|
component: RouteComponent,
|
||||||
|
})
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
return <div>Hello "/_authenticated/dashboard"!</div>
|
||||||
|
}
|
||||||
@@ -203,7 +203,7 @@ function RouteComponent() {
|
|||||||
{recientes.length === 0 && <li className="text-sm text-neutral-500">Sin actividad</li>}
|
{recientes.length === 0 && <li className="text-sm text-neutral-500">Sin actividad</li>}
|
||||||
{recientes.map((r) => (
|
{recientes.map((r) => (
|
||||||
<li key={`${r.tipo}-${r.id}`} className="flex items-center justify-between gap-3">
|
<li key={`${r.tipo}-${r.id}`} className="flex items-center justify-between gap-3">
|
||||||
<Link to={`/ _authenticated/${r.tipo === 'plan' ? 'planes' : 'asignaturas'}/${r.id}`} className="truncate hover:underline">
|
<Link to={`/${r.tipo === 'plan' ? 'planes' : 'asignaturas'}/${r.id}`} className="truncate hover:underline">
|
||||||
<span className="inline-flex items-center gap-2">
|
<span className="inline-flex items-center gap-2">
|
||||||
{r.tipo === 'plan' ? <Icons.ScrollText className="w-4 h-4" /> : <Icons.BookOpen className="w-4 h-4" />}
|
{r.tipo === 'plan' ? <Icons.ScrollText className="w-4 h-4" /> : <Icons.BookOpen className="w-4 h-4" />}
|
||||||
{r.nombre ?? '—'}
|
{r.nombre ?? '—'}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createFileRoute, useRouter, Link } from "@tanstack/react-router"
|
import { createFileRoute, useRouter, Link } from "@tanstack/react-router"
|
||||||
import { useEffect, useMemo, useState } from "react"
|
import { useMemo, useState } from "react"
|
||||||
import { supabase, useSupabaseAuth } from "@/auth/supabase"
|
import { supabase, useSupabaseAuth } from "@/auth/supabase"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
@@ -7,7 +7,6 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
|||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
import * as Icons from "lucide-react"
|
import * as Icons from "lucide-react"
|
||||||
import { Plus, RefreshCcw, Building2, ScrollText, BookOpen } from "lucide-react"
|
import { Plus, RefreshCcw, Building2, ScrollText, BookOpen } from "lucide-react"
|
||||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"
|
|
||||||
|
|
||||||
export type PlanDeEstudios = {
|
export type PlanDeEstudios = {
|
||||||
id: string; nombre: string; nivel: string | null; duracion: string | null;
|
id: string; nombre: string; nivel: string | null; duracion: string | null;
|
||||||
@@ -38,6 +37,7 @@ export const Route = createFileRoute("/_authenticated/planes")({
|
|||||||
if (error) throw new Error(error.message)
|
if (error) throw new Error(error.message)
|
||||||
return (data ?? []) as PlanRow[]
|
return (data ?? []) as PlanRow[]
|
||||||
},
|
},
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
/* ---------- helpers de estilo suave ---------- */
|
/* ---------- helpers de estilo suave ---------- */
|
||||||
@@ -62,10 +62,9 @@ function RouteComponent() {
|
|||||||
const [q, setQ] = useState("")
|
const [q, setQ] = useState("")
|
||||||
const data = Route.useLoaderData() as PlanRow[]
|
const data = Route.useLoaderData() as PlanRow[]
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const search = Route.useSearch<{ planId?: string }>() // usaremos ?planId=... para el modal
|
|
||||||
|
|
||||||
const showFacultad = auth.claims?.role === "lci" || auth.claims?.role === "vicerrectoria"
|
const showFacultad = auth.claims?.role === "lci" || auth.claims?.role === "vicerrectoria"
|
||||||
const showCarrera = auth.claims?.role === "secretario_academico"
|
const showCarrera = showFacultad || auth.claims?.role === "secretario_academico"
|
||||||
|
|
||||||
const filtered = useMemo(() => {
|
const filtered = useMemo(() => {
|
||||||
const term = q.trim().toLowerCase()
|
const term = q.trim().toLowerCase()
|
||||||
@@ -106,11 +105,7 @@ function RouteComponent() {
|
|||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={p.id}
|
key={p.id}
|
||||||
// Runtime navega con ?planId=... (abrimos el modal),
|
|
||||||
// pero la URL se enmascara SIN el search param:
|
|
||||||
to="/planes/$planId/modal"
|
to="/planes/$planId/modal"
|
||||||
search={{ planId: p.id }}
|
|
||||||
mask={{ to: '/planes/$planId', params: { planId: p.id } }}
|
|
||||||
className="group relative overflow-hidden rounded-3xl bg-white shadow-sm ring-1 transition-all hover:shadow-md hover:-translate-y-0.5"
|
className="group relative overflow-hidden rounded-3xl bg-white shadow-sm ring-1 transition-all hover:shadow-md hover:-translate-y-0.5"
|
||||||
params={{ planId: p.id }}
|
params={{ planId: p.id }}
|
||||||
style={styles}
|
style={styles}
|
||||||
@@ -131,12 +126,12 @@ function RouteComponent() {
|
|||||||
|
|
||||||
<div className="flex items-center gap-2 text-xs">
|
<div className="flex items-center gap-2 text-xs">
|
||||||
{showCarrera && p.carreras?.nombre && (
|
{showCarrera && p.carreras?.nombre && (
|
||||||
<Badge variant="secondary" className="border text-neutral-700 bg-white/70">
|
<Badge variant="secondary" className="border text-neutral-700 bg-white/70 w-fit">
|
||||||
<ScrollText className="mr-1 h-3 w-3" /> {p.carreras?.nombre}
|
<ScrollText className="mr-1 h-3 w-3" /> {p.carreras?.nombre}
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
{showFacultad && fac?.nombre && (
|
{showFacultad && fac?.nombre && (
|
||||||
<Badge variant="outline" className="bg-white/60" style={{ borderColor: styles.borderColor }}>
|
<Badge variant="outline" className="bg-white/60 w-fit" style={{ borderColor: styles.borderColor }}>
|
||||||
<BookOpen className="mr-1 h-3 w-3" /> {fac?.nombre}
|
<BookOpen className="mr-1 h-3 w-3" /> {fac?.nombre}
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
@@ -157,95 +152,6 @@ function RouteComponent() {
|
|||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* MODAL: se muestra si existe ?planId=... */}
|
|
||||||
<PlanPreviewModal planId={search?.planId} onClose={() =>
|
|
||||||
router.navigate({ to: "/planes", replace: true })
|
|
||||||
} />
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Modal (carga ligera por id) ---------- */
|
|
||||||
function PlanPreviewModal({ planId, onClose }: { planId?: string; onClose: () => void }) {
|
|
||||||
const [loading, setLoading] = useState(false)
|
|
||||||
const [plan, setPlan] = useState<null | {
|
|
||||||
id: string; nombre: string; nivel: string | null; duracion: string | null;
|
|
||||||
total_creditos: number | null; estado: string | null;
|
|
||||||
carreras: { nombre: string; facultades?: { nombre: string; color?: string | null; icon?: string | null } | null } | null
|
|
||||||
}>(null)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let alive = true
|
|
||||||
async function fetchPlan() {
|
|
||||||
if (!planId) return
|
|
||||||
setLoading(true)
|
|
||||||
const { data, error } = await supabase
|
|
||||||
.from("plan_estudios")
|
|
||||||
.select(`
|
|
||||||
id, nombre, nivel, duracion, total_creditos, estado,
|
|
||||||
carreras (
|
|
||||||
nombre,
|
|
||||||
facultades:facultades ( nombre, color, icon )
|
|
||||||
)
|
|
||||||
`)
|
|
||||||
.eq("id", planId)
|
|
||||||
.single()
|
|
||||||
if (!alive) return
|
|
||||||
if (!error) setPlan(data as any)
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
fetchPlan()
|
|
||||||
return () => { alive = false }
|
|
||||||
}, [planId])
|
|
||||||
|
|
||||||
const fac = plan?.carreras?.facultades
|
|
||||||
const [r, g, b] = hexToRgb(fac?.color)
|
|
||||||
const headerStyle = { background: `linear-gradient(135deg, rgba(${r},${g},${b},.14), rgba(${r},${g},${b},.06))` }
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dialog open={!!planId} onOpenChange={() => onClose()}>
|
|
||||||
<DialogContent className="max-w-2xl p-0 overflow-hidden">
|
|
||||||
<div className="p-6" style={headerStyle}>
|
|
||||||
<DialogHeader className="space-y-1">
|
|
||||||
<DialogTitle>{plan?.nombre ?? "Cargando…"}</DialogTitle>
|
|
||||||
<div className="text-xs text-neutral-600">
|
|
||||||
{plan?.carreras?.nombre ?? "—"} {fac?.nombre ? `· ${fac?.nombre}` : ""}
|
|
||||||
</div>
|
|
||||||
</DialogHeader>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-6 space-y-4">
|
|
||||||
{loading && <div className="text-sm text-neutral-500">Cargando…</div>}
|
|
||||||
{!loading && plan && (
|
|
||||||
<>
|
|
||||||
<div className="grid grid-cols-2 gap-3 text-sm">
|
|
||||||
<div><span className="text-neutral-500">Nivel:</span> <span className="font-medium">{plan.nivel ?? "—"}</span></div>
|
|
||||||
<div><span className="text-neutral-500">Duración:</span> <span className="font-medium">{plan.duracion ?? "—"}</span></div>
|
|
||||||
<div><span className="text-neutral-500">Créditos:</span> <span className="font-medium">{plan.total_creditos ?? "—"}</span></div>
|
|
||||||
<div><span className="text-neutral-500">Estado:</span> <span className="font-medium">{plan.estado ?? "—"}</span></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex gap-2">
|
|
||||||
<Link
|
|
||||||
to="/_authenticated/planes/$planId"
|
|
||||||
params={{ planId: plan.id }}
|
|
||||||
className="inline-flex items-center gap-2 rounded-xl bg-black text-white px-4 py-2 hover:opacity-90"
|
|
||||||
>
|
|
||||||
<Icons.FileText className="w-4 h-4" /> Ver ficha
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
to="/_authenticated/asignaturas"
|
|
||||||
search={{ planId: plan.id }}
|
|
||||||
className="inline-flex items-center gap-2 rounded-xl border px-4 py-2 hover:bg-neutral-50"
|
|
||||||
>
|
|
||||||
<Icons.BookOpen className="w-4 h-4" /> Ver asignaturas
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export const Route = createFileRoute("/_authenticated/planes/$planId/modal")({
|
|||||||
.eq("id", params.planId)
|
.eq("id", params.planId)
|
||||||
.single()
|
.single()
|
||||||
if (error) throw error
|
if (error) throw error
|
||||||
return data as PlanDetail
|
return data
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user