Skip to content

Commit

Permalink
auth, middleware for auth routes
Browse files Browse the repository at this point in the history
  • Loading branch information
abezborody committed Dec 16, 2024
1 parent 9ef1627 commit 76db1dd
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 101 deletions.
2 changes: 1 addition & 1 deletion frontend/index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8" />
Expand Down
16 changes: 16 additions & 0 deletions frontend/src/lib/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
import { hc } from "hono/client"
import { type ApiRoutes } from "@server/app"
import { queryOptions } from "@tanstack/react-query"

const client = hc<ApiRoutes>("/")

export const api = client.api

async function getCurrentUser() {
const result = await api.me.$get()
if (!result.ok) {
throw new Error('error')
}
const data = await result.json()
return data
}

export const userQueryOptions = queryOptions({
queryKey: ['getCurrentUser'],
queryFn: getCurrentUser,
staleTime: Infinity
})
2 changes: 1 addition & 1 deletion frontend/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const queryClient = new QueryClient()
import { routeTree } from "./routeTree.gen"

// Create a new router instance
const router = createRouter({ routeTree })
const router = createRouter({ routeTree, context: { queryClient } })

// Register the router instance for type safety
declare module "@tanstack/react-router" {
Expand Down
185 changes: 127 additions & 58 deletions frontend/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,61 @@
// Import Routes

import { Route as rootRoute } from './routes/__root'
import { Route as ExpensesImport } from './routes/expenses'
import { Route as CreateExpenseImport } from './routes/create-expense'
import { Route as AboutImport } from './routes/about'
import { Route as IndexImport } from './routes/index'
import { Route as AuthenticatedImport } from './routes/_authenticated'
import { Route as AuthenticatedIndexImport } from './routes/_authenticated/index'
import { Route as AuthenticatedProfileImport } from './routes/_authenticated/profile'
import { Route as AuthenticatedExpensesImport } from './routes/_authenticated/expenses'
import { Route as AuthenticatedCreateExpenseImport } from './routes/_authenticated/create-expense'

// Create/Update Routes

const ExpensesRoute = ExpensesImport.update({
id: '/expenses',
path: '/expenses',
getParentRoute: () => rootRoute,
} as any)

const CreateExpenseRoute = CreateExpenseImport.update({
id: '/create-expense',
path: '/create-expense',
getParentRoute: () => rootRoute,
} as any)

const AboutRoute = AboutImport.update({
id: '/about',
path: '/about',
getParentRoute: () => rootRoute,
} as any)

const IndexRoute = IndexImport.update({
const AuthenticatedRoute = AuthenticatedImport.update({
id: '/_authenticated',
getParentRoute: () => rootRoute,
} as any)

const AuthenticatedIndexRoute = AuthenticatedIndexImport.update({
id: '/',
path: '/',
getParentRoute: () => rootRoute,
getParentRoute: () => AuthenticatedRoute,
} as any)

const AuthenticatedProfileRoute = AuthenticatedProfileImport.update({
id: '/profile',
path: '/profile',
getParentRoute: () => AuthenticatedRoute,
} as any)

const AuthenticatedExpensesRoute = AuthenticatedExpensesImport.update({
id: '/expenses',
path: '/expenses',
getParentRoute: () => AuthenticatedRoute,
} as any)

const AuthenticatedCreateExpenseRoute = AuthenticatedCreateExpenseImport.update(
{
id: '/create-expense',
path: '/create-expense',
getParentRoute: () => AuthenticatedRoute,
} as any,
)

// Populate the FileRoutesByPath interface

declare module '@tanstack/react-router' {
interface FileRoutesByPath {
'/': {
id: '/'
path: '/'
fullPath: '/'
preLoaderRoute: typeof IndexImport
'/_authenticated': {
id: '/_authenticated'
path: ''
fullPath: ''
preLoaderRoute: typeof AuthenticatedImport
parentRoute: typeof rootRoute
}
'/about': {
Expand All @@ -60,68 +75,108 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AboutImport
parentRoute: typeof rootRoute
}
'/create-expense': {
id: '/create-expense'
'/_authenticated/create-expense': {
id: '/_authenticated/create-expense'
path: '/create-expense'
fullPath: '/create-expense'
preLoaderRoute: typeof CreateExpenseImport
parentRoute: typeof rootRoute
preLoaderRoute: typeof AuthenticatedCreateExpenseImport
parentRoute: typeof AuthenticatedImport
}
'/expenses': {
id: '/expenses'
'/_authenticated/expenses': {
id: '/_authenticated/expenses'
path: '/expenses'
fullPath: '/expenses'
preLoaderRoute: typeof ExpensesImport
parentRoute: typeof rootRoute
preLoaderRoute: typeof AuthenticatedExpensesImport
parentRoute: typeof AuthenticatedImport
}
'/_authenticated/profile': {
id: '/_authenticated/profile'
path: '/profile'
fullPath: '/profile'
preLoaderRoute: typeof AuthenticatedProfileImport
parentRoute: typeof AuthenticatedImport
}
'/_authenticated/': {
id: '/_authenticated/'
path: '/'
fullPath: '/'
preLoaderRoute: typeof AuthenticatedIndexImport
parentRoute: typeof AuthenticatedImport
}
}
}

// Create and export the route tree

interface AuthenticatedRouteChildren {
AuthenticatedCreateExpenseRoute: typeof AuthenticatedCreateExpenseRoute
AuthenticatedExpensesRoute: typeof AuthenticatedExpensesRoute
AuthenticatedProfileRoute: typeof AuthenticatedProfileRoute
AuthenticatedIndexRoute: typeof AuthenticatedIndexRoute
}

const AuthenticatedRouteChildren: AuthenticatedRouteChildren = {
AuthenticatedCreateExpenseRoute: AuthenticatedCreateExpenseRoute,
AuthenticatedExpensesRoute: AuthenticatedExpensesRoute,
AuthenticatedProfileRoute: AuthenticatedProfileRoute,
AuthenticatedIndexRoute: AuthenticatedIndexRoute,
}

const AuthenticatedRouteWithChildren = AuthenticatedRoute._addFileChildren(
AuthenticatedRouteChildren,
)

export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'': typeof AuthenticatedRouteWithChildren
'/about': typeof AboutRoute
'/create-expense': typeof CreateExpenseRoute
'/expenses': typeof ExpensesRoute
'/create-expense': typeof AuthenticatedCreateExpenseRoute
'/expenses': typeof AuthenticatedExpensesRoute
'/profile': typeof AuthenticatedProfileRoute
'/': typeof AuthenticatedIndexRoute
}

export interface FileRoutesByTo {
'/': typeof IndexRoute
'/about': typeof AboutRoute
'/create-expense': typeof CreateExpenseRoute
'/expenses': typeof ExpensesRoute
'/create-expense': typeof AuthenticatedCreateExpenseRoute
'/expenses': typeof AuthenticatedExpensesRoute
'/profile': typeof AuthenticatedProfileRoute
'/': typeof AuthenticatedIndexRoute
}

export interface FileRoutesById {
__root__: typeof rootRoute
'/': typeof IndexRoute
'/_authenticated': typeof AuthenticatedRouteWithChildren
'/about': typeof AboutRoute
'/create-expense': typeof CreateExpenseRoute
'/expenses': typeof ExpensesRoute
'/_authenticated/create-expense': typeof AuthenticatedCreateExpenseRoute
'/_authenticated/expenses': typeof AuthenticatedExpensesRoute
'/_authenticated/profile': typeof AuthenticatedProfileRoute
'/_authenticated/': typeof AuthenticatedIndexRoute
}

export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: '/' | '/about' | '/create-expense' | '/expenses'
fullPaths: '' | '/about' | '/create-expense' | '/expenses' | '/profile' | '/'
fileRoutesByTo: FileRoutesByTo
to: '/' | '/about' | '/create-expense' | '/expenses'
id: '__root__' | '/' | '/about' | '/create-expense' | '/expenses'
to: '/about' | '/create-expense' | '/expenses' | '/profile' | '/'
id:
| '__root__'
| '/_authenticated'
| '/about'
| '/_authenticated/create-expense'
| '/_authenticated/expenses'
| '/_authenticated/profile'
| '/_authenticated/'
fileRoutesById: FileRoutesById
}

export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
AuthenticatedRoute: typeof AuthenticatedRouteWithChildren
AboutRoute: typeof AboutRoute
CreateExpenseRoute: typeof CreateExpenseRoute
ExpensesRoute: typeof ExpensesRoute
}

const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
AuthenticatedRoute: AuthenticatedRouteWithChildren,
AboutRoute: AboutRoute,
CreateExpenseRoute: CreateExpenseRoute,
ExpensesRoute: ExpensesRoute,
}

export const routeTree = rootRoute
Expand All @@ -134,23 +189,37 @@ export const routeTree = rootRoute
"__root__": {
"filePath": "__root.tsx",
"children": [
"/",
"/about",
"/create-expense",
"/expenses"
"/_authenticated",
"/about"
]
},
"/": {
"filePath": "index.tsx"
"/_authenticated": {
"filePath": "_authenticated.tsx",
"children": [
"/_authenticated/create-expense",
"/_authenticated/expenses",
"/_authenticated/profile",
"/_authenticated/"
]
},
"/about": {
"filePath": "about.tsx"
},
"/create-expense": {
"filePath": "create-expense.tsx"
"/_authenticated/create-expense": {
"filePath": "_authenticated/create-expense.tsx",
"parent": "/_authenticated"
},
"/_authenticated/expenses": {
"filePath": "_authenticated/expenses.tsx",
"parent": "/_authenticated"
},
"/_authenticated/profile": {
"filePath": "_authenticated/profile.tsx",
"parent": "/_authenticated"
},
"/expenses": {
"filePath": "expenses.tsx"
"/_authenticated/": {
"filePath": "_authenticated/index.tsx",
"parent": "/_authenticated"
}
}
}
Expand Down
20 changes: 16 additions & 4 deletions frontend/src/routes/__root.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
import { Link, Outlet, createRootRoute } from "@tanstack/react-router"
import { type QueryClient } from "@tanstack/react-query"
import {
Link,
Outlet,
createRootRouteWithContext,
} from "@tanstack/react-router"

export const Route = createRootRoute({
interface MyRouterContext {
queryClient: QueryClient
}

export const Route = createRootRouteWithContext<MyRouterContext>()({
component: Root,
})

function NavBar() {
return (
<div className="flex p-2 gap-2 justify-center">
<div className="flex py-2 gap-2 max-w-xl m-auto">
<Link to="/" className="[&.active]:font-bold">
Home
</Link>
<Link to="/about" className="[&.active]:font-bold">
About
</Link>{" "}
</Link>
<Link to="/expenses" className="[&.active]:font-bold">
Expenses
</Link>
<Link to="/create-expense" className="[&.active]:font-bold">
Create expense
</Link>
<Link to="/profile" className="[&.active]:font-bold">
Profile
</Link>
</div>
)
}
Expand Down
43 changes: 43 additions & 0 deletions frontend/src/routes/_authenticated.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Button } from "@/components/ui/button"
import { userQueryOptions } from "@/lib/api"
import { createFileRoute, Outlet } from "@tanstack/react-router"

const Login = () => {
return (
<div className="flex items-center gap-2 max-w-xl m-auto py-2">
<Button className="min-w-6">
<a href="/api/login">Login</a>
</Button>
<span>You have to login</span>
</div>
)
}

const Component = () => {
const { user } = Route.useRouteContext()
if (!user) {
return <Login />
}

return <Outlet />
}

// src/routes/_authenticated.tsx
export const Route = createFileRoute("/_authenticated")({
beforeLoad: async ({ context }) => {
const queryClient = context.queryClient

try {
const data = await queryClient.fetchQuery(userQueryOptions)
return data
} catch (e) {
console.error(e)
return { user: null }
}
// userQueryOptions
// check if the user is authenticated
return { user: { name: "John Doe" } }
// return { user: null }
},
component: Component,
})
Loading

0 comments on commit 76db1dd

Please sign in to comment.