feat: Implement a new _auth layout with a dashboard map, refactor the login form, and add logout functionality.

This commit is contained in:
Jrodenas
2026-03-15 19:56:14 +01:00
parent 45da7f62fe
commit 08d0a5a099
12 changed files with 307 additions and 148 deletions

View File

@@ -14,13 +14,14 @@ export const useLogin = () => {
mutationKey: ["login"],
mutationFn: async (data: TLoginForm) => {
const response = await user.login({ data })
if (response.error) {
throw new Error(response.message)
}
},
onSuccess: () => {
navigate({
to: "/"
to: "/dashboard"
})
}
})

View File

@@ -12,17 +12,13 @@ import { Route as rootRouteImport } from './routes/__root'
import { Route as LogoutRouteImport } from './routes/logout'
import { Route as LoginRouteImport } from './routes/login'
import { Route as AccessRouteImport } from './routes/access'
import { Route as AuthedRouteImport } from './routes/_authed'
import { Route as AuthRouteImport } from './routes/_auth'
import { Route as IndexRouteImport } from './routes/index'
import { Route as DemoTanstackQueryRouteImport } from './routes/demo/tanstack-query'
import { Route as DemoI18nRouteImport } from './routes/demo.i18n'
<<<<<<< HEAD
import { Route as AccessRegisterRouteImport } from './routes/access.register'
import { Route as AccessLoginRouteImport } from './routes/access.login'
import { Route as AuthedDashboardRouteImport } from './routes/_authed/dashboard'
=======
import { Route as AuthDashboardRouteImport } from './routes/auth/dashboard'
>>>>>>> main
import { Route as AuthDashboardRouteImport } from './routes/_auth/dashboard'
import { Route as DemoSentryTestingRouteImport } from './routes/demo/sentry.testing'
const LogoutRoute = LogoutRouteImport.update({
@@ -40,8 +36,8 @@ const AccessRoute = AccessRouteImport.update({
path: '/access',
getParentRoute: () => rootRouteImport,
} as any)
const AuthedRoute = AuthedRouteImport.update({
id: '/_authed',
const AuthRoute = AuthRouteImport.update({
id: '/_auth',
getParentRoute: () => rootRouteImport,
} as any)
const IndexRoute = IndexRouteImport.update({
@@ -59,7 +55,6 @@ const DemoI18nRoute = DemoI18nRouteImport.update({
path: '/demo/i18n',
getParentRoute: () => rootRouteImport,
} as any)
<<<<<<< HEAD
const AccessRegisterRoute = AccessRegisterRouteImport.update({
id: '/register',
path: '/register',
@@ -70,16 +65,10 @@ const AccessLoginRoute = AccessLoginRouteImport.update({
path: '/login',
getParentRoute: () => AccessRoute,
} as any)
const AuthedDashboardRoute = AuthedDashboardRouteImport.update({
const AuthDashboardRoute = AuthDashboardRouteImport.update({
id: '/dashboard',
path: '/dashboard',
getParentRoute: () => AuthedRoute,
=======
const AuthDashboardRoute = AuthDashboardRouteImport.update({
id: '/auth/dashboard',
path: '/auth/dashboard',
getParentRoute: () => rootRouteImport,
>>>>>>> main
getParentRoute: () => AuthRoute,
} as any)
const DemoSentryTestingRoute = DemoSentryTestingRouteImport.update({
id: '/demo/sentry/testing',
@@ -89,34 +78,24 @@ const DemoSentryTestingRoute = DemoSentryTestingRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
<<<<<<< HEAD
'/access': typeof AccessRouteWithChildren
'/login': typeof LoginRoute
'/logout': typeof LogoutRoute
'/dashboard': typeof AuthedDashboardRoute
'/dashboard': typeof AuthDashboardRoute
'/access/login': typeof AccessLoginRoute
'/access/register': typeof AccessRegisterRoute
=======
'/login': typeof LoginRouteRoute
'/auth/dashboard': typeof AuthDashboardRoute
>>>>>>> main
'/demo/i18n': typeof DemoI18nRoute
'/demo/tanstack-query': typeof DemoTanstackQueryRoute
'/demo/sentry/testing': typeof DemoSentryTestingRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
<<<<<<< HEAD
'/access': typeof AccessRouteWithChildren
'/login': typeof LoginRoute
'/logout': typeof LogoutRoute
'/dashboard': typeof AuthedDashboardRoute
'/dashboard': typeof AuthDashboardRoute
'/access/login': typeof AccessLoginRoute
'/access/register': typeof AccessRegisterRoute
=======
'/login': typeof LoginRouteRoute
'/auth/dashboard': typeof AuthDashboardRoute
>>>>>>> main
'/demo/i18n': typeof DemoI18nRoute
'/demo/tanstack-query': typeof DemoTanstackQueryRoute
'/demo/sentry/testing': typeof DemoSentryTestingRoute
@@ -124,18 +103,13 @@ export interface FileRoutesByTo {
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
<<<<<<< HEAD
'/_authed': typeof AuthedRouteWithChildren
'/_auth': typeof AuthRouteWithChildren
'/access': typeof AccessRouteWithChildren
'/login': typeof LoginRoute
'/logout': typeof LogoutRoute
'/_authed/dashboard': typeof AuthedDashboardRoute
'/_auth/dashboard': typeof AuthDashboardRoute
'/access/login': typeof AccessLoginRoute
'/access/register': typeof AccessRegisterRoute
=======
'/login': typeof LoginRouteRoute
'/auth/dashboard': typeof AuthDashboardRoute
>>>>>>> main
'/demo/i18n': typeof DemoI18nRoute
'/demo/tanstack-query': typeof DemoTanstackQueryRoute
'/demo/sentry/testing': typeof DemoSentryTestingRoute
@@ -146,14 +120,10 @@ export interface FileRouteTypes {
| '/'
| '/access'
| '/login'
<<<<<<< HEAD
| '/logout'
| '/dashboard'
| '/access/login'
| '/access/register'
=======
| '/auth/dashboard'
>>>>>>> main
| '/demo/i18n'
| '/demo/tanstack-query'
| '/demo/sentry/testing'
@@ -162,31 +132,23 @@ export interface FileRouteTypes {
| '/'
| '/access'
| '/login'
<<<<<<< HEAD
| '/logout'
| '/dashboard'
| '/access/login'
| '/access/register'
=======
| '/auth/dashboard'
>>>>>>> main
| '/demo/i18n'
| '/demo/tanstack-query'
| '/demo/sentry/testing'
id:
| '__root__'
| '/'
| '/_authed'
| '/_auth'
| '/access'
| '/login'
<<<<<<< HEAD
| '/logout'
| '/_authed/dashboard'
| '/_auth/dashboard'
| '/access/login'
| '/access/register'
=======
| '/auth/dashboard'
>>>>>>> main
| '/demo/i18n'
| '/demo/tanstack-query'
| '/demo/sentry/testing'
@@ -194,15 +156,10 @@ export interface FileRouteTypes {
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
<<<<<<< HEAD
AuthedRoute: typeof AuthedRouteWithChildren
AuthRoute: typeof AuthRouteWithChildren
AccessRoute: typeof AccessRouteWithChildren
LoginRoute: typeof LoginRoute
LogoutRoute: typeof LogoutRoute
=======
LoginRouteRoute: typeof LoginRouteRoute
AuthDashboardRoute: typeof AuthDashboardRoute
>>>>>>> main
DemoI18nRoute: typeof DemoI18nRoute
DemoTanstackQueryRoute: typeof DemoTanstackQueryRoute
DemoSentryTestingRoute: typeof DemoSentryTestingRoute
@@ -231,11 +188,11 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AccessRouteImport
parentRoute: typeof rootRouteImport
}
'/_authed': {
id: '/_authed'
'/_auth': {
id: '/_auth'
path: ''
fullPath: '/'
preLoaderRoute: typeof AuthedRouteImport
preLoaderRoute: typeof AuthRouteImport
parentRoute: typeof rootRouteImport
}
'/': {
@@ -259,7 +216,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof DemoI18nRouteImport
parentRoute: typeof rootRouteImport
}
<<<<<<< HEAD
'/access/register': {
id: '/access/register'
path: '/register'
@@ -274,20 +230,12 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AccessLoginRouteImport
parentRoute: typeof AccessRoute
}
'/_authed/dashboard': {
id: '/_authed/dashboard'
'/_auth/dashboard': {
id: '/_auth/dashboard'
path: '/dashboard'
fullPath: '/dashboard'
preLoaderRoute: typeof AuthedDashboardRouteImport
parentRoute: typeof AuthedRoute
=======
'/auth/dashboard': {
id: '/auth/dashboard'
path: '/auth/dashboard'
fullPath: '/auth/dashboard'
preLoaderRoute: typeof AuthDashboardRouteImport
parentRoute: typeof rootRouteImport
>>>>>>> main
parentRoute: typeof AuthRoute
}
'/demo/sentry/testing': {
id: '/demo/sentry/testing'
@@ -299,16 +247,15 @@ declare module '@tanstack/react-router' {
}
}
interface AuthedRouteChildren {
AuthedDashboardRoute: typeof AuthedDashboardRoute
interface AuthRouteChildren {
AuthDashboardRoute: typeof AuthDashboardRoute
}
const AuthedRouteChildren: AuthedRouteChildren = {
AuthedDashboardRoute: AuthedDashboardRoute,
const AuthRouteChildren: AuthRouteChildren = {
AuthDashboardRoute: AuthDashboardRoute,
}
const AuthedRouteWithChildren =
AuthedRoute._addFileChildren(AuthedRouteChildren)
const AuthRouteWithChildren = AuthRoute._addFileChildren(AuthRouteChildren)
interface AccessRouteChildren {
AccessLoginRoute: typeof AccessLoginRoute
@@ -325,15 +272,10 @@ const AccessRouteWithChildren =
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
<<<<<<< HEAD
AuthedRoute: AuthedRouteWithChildren,
AuthRoute: AuthRouteWithChildren,
AccessRoute: AccessRouteWithChildren,
LoginRoute: LoginRoute,
LogoutRoute: LogoutRoute,
=======
LoginRouteRoute: LoginRouteRoute,
AuthDashboardRoute: AuthDashboardRoute,
>>>>>>> main
DemoI18nRoute: DemoI18nRoute,
DemoTanstackQueryRoute: DemoTanstackQueryRoute,
DemoSentryTestingRoute: DemoSentryTestingRoute,

View File

@@ -1,3 +1,4 @@
import { ToastProvider } from "@heroui/react"
import type { QueryClient } from "@tanstack/react-query"
import {
createRootRouteWithContext,
@@ -55,6 +56,7 @@ function RootDocument({ children }: { children: React.ReactNode }) {
<HeadContent />
</head>
<body>
<ToastProvider />
{children}
<Devtools />
<Scripts />

View File

@@ -1,8 +1,8 @@
import { createFileRoute, Link, Outlet } from "@tanstack/react-router"
export const Route = createFileRoute("/_authed")({
export const Route = createFileRoute("/_auth")({
beforeLoad: ({ context }) => {
if (context.error) {
if (context.user.error) {
throw new Error("Not authenticated")
}
},

View File

@@ -5,13 +5,13 @@ import { useState } from "react"
import {
Map as MapComponent,
MapMarker,
MapViewport,
type MapViewport,
MarkerContent,
MarkerPopup,
MarkerTooltip
} from "@/components/maps/map"
export const Route = createFileRoute("/auth/dashboard")({
export const Route = createFileRoute("/_auth/dashboard")({
component: RouteComponent
})
@@ -44,7 +44,7 @@ function RouteComponent() {
})
return (
<div>
<Card className="h-[800px] p-0 overflow-hidden">
<Card className="h-200 p-0 overflow-hidden">
<MapComponent
center={[40.5874827, -1.7925343]}
zoom={10}

View File

@@ -1,9 +0,0 @@
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/_authed/dashboard')({
component: RouteComponent,
})
function RouteComponent() {
return <div>Hello "/_authed/dashboard"!</div>
}

View File

@@ -1,4 +1,14 @@
import { Button, Card, Form, Input, Label, Spinner } from "@heroui/react"
import {
Button,
Card,
FieldError,
Fieldset,
Form,
Input,
Label,
Spinner,
TextField
} from "@heroui/react"
import { createFileRoute } from "@tanstack/react-router"
import { LogIn } from "lucide-react"
import { useLogin } from "@/lib/hooks/useLogin"
@@ -23,28 +33,38 @@ function RouteComponent() {
<div>
<Card.Content>
<Form onSubmit={handleFormSubmit} className="flex flex-col gap-4">
<Label isRequired className="ml-4 text-lg">
Correo
</Label>
<Input
placeholder="Introduce tu correo"
type="email"
name="email"
variant="secondary"
className="py-4 text-lg "
required
/>
<Label isRequired className="ml-4 text-lg">
Contraseña
</Label>
<Input
placeholder="Introduce tu contraseña"
type="password"
name="password"
variant="secondary"
className="py-4 text-lg "
required
/>
<Fieldset>
<Fieldset.Group>
<TextField
type="email"
name="email"
variant="secondary"
className="py-4 text-lg"
isRequired
defaultValue={import.meta.env.VITE_LOGIN_USER}
>
<Label isRequired className="ml-4 text-lg">
Correo
</Label>
<Input placeholder="Introduce tu correo" />
<FieldError />
</TextField>
<TextField
type="password"
name="password"
variant="secondary"
className="py-4 text-lg"
isRequired
defaultValue={import.meta.env.VITE_PASSWORD_USER}
>
<Label isRequired className="ml-4 text-lg">
Contraseña
</Label>
<Input placeholder="Introduce tu contraseña" />
<FieldError />
</TextField>
</Fieldset.Group>
</Fieldset>
<div className="flex justify-end">
<Button
type="submit"

View File

@@ -12,6 +12,8 @@ import {
export const Route = createFileRoute("/")({ component: App })
function App() {
const navigate = Route.useNavigate()
const features = [
{
icon: <Zap className="w-12 h-12 text-cyan-400" />,
@@ -53,7 +55,17 @@ function App() {
return (
<div className="min-h-screen bg-linear-to-b from-slate-900 via-slate-800 to-slate-900">
<Button> Hola</Button>
<Button
onPress={() => {
navigate({
to: "/login",
viewTransition: true
})
}}
>
{" "}
Hola
</Button>
<section className="relative py-20 px-6 text-center overflow-hidden">
<div className="absolute inset-0 bg-linear-to-r from-cyan-500/10 via-blue-500/10 to-purple-500/10"></div>
<div className="relative max-w-5xl mx-auto">

View File

@@ -1,5 +1,9 @@
import { createFileRoute } from "@tanstack/react-router"
import { user } from "@/lib/server/user"
export const Route = createFileRoute("/logout")({
beforeLoad: async ({ context }) => {}
beforeLoad: async () => {
await user.logout()
},
preload: false
})