From 5f8943492e6519e0ca9d302da6a850f61d5ded91 Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Wed, 19 Feb 2025 20:11:40 -0600 Subject: [PATCH] feat(lst): tan stack routes added with protected routes --- .versionrc.json | 28 +- frontend/index.html | 22 +- frontend/package.json | 3 + frontend/public/lst.ico | Bin 0 -> 22454 bytes frontend/src/App.tsx | 31 -- .../src/components/{ => auth}/LoginForm.tsx | 4 +- frontend/src/lib/hooks/useSession.ts | 6 +- frontend/src/main.tsx | 45 ++- frontend/src/routeTree.gen.ts | 311 ++++++++++++++++++ frontend/src/routes/__root.tsx | 42 +++ frontend/src/routes/_auth.tsx | 12 + frontend/src/routes/_auth/dashboard.tsx | 9 + frontend/src/routes/_auth/profile.tsx | 9 + frontend/src/routes/about.tsx | 13 + frontend/src/routes/index.tsx | 29 ++ frontend/src/routes/login.tsx | 38 +++ frontend/src/routes/ocp/$lineID.tsx | 17 + frontend/src/routes/ocp/index.tsx | 34 ++ frontend/src/routes/ocp/lots.tsx | 9 + frontend/src/utils/auth.ts | 11 + frontend/vite.config.ts | 3 +- package.json | 2 +- server/src/app.ts | 4 +- 23 files changed, 608 insertions(+), 74 deletions(-) create mode 100644 frontend/public/lst.ico delete mode 100644 frontend/src/App.tsx rename frontend/src/components/{ => auth}/LoginForm.tsx (95%) create mode 100644 frontend/src/routeTree.gen.ts create mode 100644 frontend/src/routes/__root.tsx create mode 100644 frontend/src/routes/_auth.tsx create mode 100644 frontend/src/routes/_auth/dashboard.tsx create mode 100644 frontend/src/routes/_auth/profile.tsx create mode 100644 frontend/src/routes/about.tsx create mode 100644 frontend/src/routes/index.tsx create mode 100644 frontend/src/routes/login.tsx create mode 100644 frontend/src/routes/ocp/$lineID.tsx create mode 100644 frontend/src/routes/ocp/index.tsx create mode 100644 frontend/src/routes/ocp/lots.tsx create mode 100644 frontend/src/utils/auth.ts diff --git a/.versionrc.json b/.versionrc.json index 0c69c73..dfae449 100644 --- a/.versionrc.json +++ b/.versionrc.json @@ -1,16 +1,16 @@ { - "types": [ - { "type": "feat", "section": "🌟 Enhancements" }, - { "type": "fix", "section": "🐛 Bug fixes" }, - { "type": "chore", "hidden": false, "section": "📝 Chore" }, - { "type": "docs", "section": "📚 Documentation" }, - { "type": "style", "hidden": true }, - { "type": "refactor", "section": "🛠️ Code Refactor" }, - { "type": "perf", "hidden": false, "section": "🚀 Code Refactor" }, - { "type": "test", "section": "📝 Testing Code" }, - { "type": "ci", "section": "📈 Project changes" } - ], - "commitUrlFormat": "https://git.tuffraid.net/cowch/Lst_Backend/commits{{hash}}", - "compareUrlFormat": "https://git.tuffraid.net/cowch/Lst_Backend/compare/{{previousTag}}...{{currentTag}}", - "header": "# All notable changes to the LST project will be documented in this file.\n`" + "types": [ + {"type": "feat", "section": "🌟 Enhancements"}, + {"type": "fix", "section": "🐛 Bug fixes"}, + {"type": "chore", "hidden": false, "section": "📝 Chore"}, + {"type": "docs", "section": "📚 Documentation"}, + {"type": "style", "hidden": true}, + {"type": "refactor", "section": "🛠️ Code Refactor"}, + {"type": "perf", "hidden": false, "section": "🚀 Code Refactor"}, + {"type": "test", "section": "📝 Testing Code"}, + {"type": "ci", "section": "📈 Project changes"} + ], + "commitUrlFormat": "https://git.tuffraid.net/cowch/lstV2/commits{{hash}}", + "compareUrlFormat": "https://git.tuffraid.net/cowch/lstV2/compare/{{previousTag}}...{{currentTag}}", + "header": "# All CHanges to LST can be found below.\n`" } diff --git a/frontend/index.html b/frontend/index.html index e4b78ea..b94b87b 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1,13 +1,13 @@ - + - - - - - Vite + React + TS - - -
- - + + + + + Logistics Support Tool + + +
+ + diff --git a/frontend/package.json b/frontend/package.json index 41fc443..4da93fe 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,6 +14,7 @@ "@radix-ui/react-slot": "^1.1.2", "@tailwindcss/vite": "^4.0.6", "@tanstack/react-query": "^5.66.5", + "@tanstack/react-router": "^1.106.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.475.0", @@ -27,6 +28,8 @@ }, "devDependencies": { "@eslint/js": "^9.19.0", + "@tanstack/router-devtools": "^1.106.0", + "@tanstack/router-plugin": "^1.106.0", "@types/node": "^22.13.4", "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", diff --git a/frontend/public/lst.ico b/frontend/public/lst.ico new file mode 100644 index 0000000000000000000000000000000000000000..cfd8d4c1abeb1ada4b979ce845703f0f54fb5b89 GIT binary patch literal 22454 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
    Mqcyf2kT8<4K7Gkl`%&juN>lGN&CURqII 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 - no session please login -

    - ); - } - - return ( - <> - {/*

    Logged in user: {session.user.username}

    */} - <>Session: {JSON.stringify(session)} -

    Status: {JSON.stringify(status)}

    -

    - -

    - - ); -} - -export default App; diff --git a/frontend/src/components/LoginForm.tsx b/frontend/src/components/auth/LoginForm.tsx similarity index 95% rename from frontend/src/components/LoginForm.tsx rename to frontend/src/components/auth/LoginForm.tsx index 079168c..51772bd 100644 --- a/frontend/src/components/LoginForm.tsx +++ b/frontend/src/components/auth/LoginForm.tsx @@ -1,5 +1,5 @@ import {useState} from "react"; -import {useSessionStore} from "../lib/store/sessionStore"; +import {useSessionStore} from "../../lib/store/sessionStore"; import {useQueryClient} from "@tanstack/react-query"; const LoginForm = () => { @@ -36,7 +36,7 @@ const LoginForm = () => { setSession(data.data.token); // Refetch the session data to reflect the logged-in state - queryClient.invalidateQueries(["session"]); + queryClient.invalidateQueries(); setUsername(""); setPassword(""); diff --git a/frontend/src/lib/hooks/useSession.ts b/frontend/src/lib/hooks/useSession.ts index 6cd8f8f..d3309b1 100644 --- a/frontend/src/lib/hooks/useSession.ts +++ b/frontend/src/lib/hooks/useSession.ts @@ -15,7 +15,7 @@ const fetchSession = async () => { Authorization: `Bearer ${token}`, }, }); - console.log(res); + // console.log(res); if (!res.ok) { throw new Error("Session not found"); } @@ -31,7 +31,7 @@ export const useSession = () => { queryKey: ["session"], queryFn: fetchSession, enabled: !!token, // Prevents query if token is null - staleTime: 5 * 60 * 1000, // 5 mins + staleTime: 60 * 1000, gcTime: 10 * 60 * 1000, // 10 mins refetchOnWindowFocus: true, }); @@ -47,3 +47,5 @@ export const useSession = () => { return {session: data && token ? {user: data.user, token: data.token} : null, status, error}; }; + +export type SessionType = ReturnType; diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 2bf9b3f..3430fdb 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,13 +1,38 @@ import {StrictMode} from "react"; -import {createRoot} from "react-dom/client"; +import ReactDOM from "react-dom/client"; import "./styles.css"; -import App from "./App.tsx"; -import {SessionProvider} from "./components/providers/Providers.tsx"; -createRoot(document.getElementById("root")!).render( - - - - - -); +import {SessionProvider} from "./components/providers/Providers.tsx"; +import {RouterProvider, createRouter} from "@tanstack/react-router"; + +// Import the generated route tree +import {routeTree} from "./routeTree.gen"; +import {useSession} from "./lib/hooks/useSession.ts"; + +// Create a new router instance +const router = createRouter({routeTree, context: {sessionType: undefined!}}); + +// Register the router instance for type safety +declare module "@tanstack/react-router" { + interface Register { + router: typeof router; + } +} + +function App() { + const sessionType = useSession(); + return ; +} + +// Render the app +const rootElement = document.getElementById("root")!; +if (!rootElement.innerHTML) { + const root = ReactDOM.createRoot(rootElement); + root.render( + + + + + + ); +} diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts new file mode 100644 index 0000000..cfcd7d3 --- /dev/null +++ b/frontend/src/routeTree.gen.ts @@ -0,0 +1,311 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import { Route as rootRoute } from './routes/__root' +import { Route as LoginImport } from './routes/login' +import { Route as AboutImport } from './routes/about' +import { Route as AuthImport } from './routes/_auth' +import { Route as IndexImport } from './routes/index' +import { Route as OcpIndexImport } from './routes/ocp/index' +import { Route as OcpLotsImport } from './routes/ocp/lots' +import { Route as OcpLineIDImport } from './routes/ocp/$lineID' +import { Route as AuthProfileImport } from './routes/_auth/profile' +import { Route as AuthDashboardImport } from './routes/_auth/dashboard' + +// Create/Update Routes + +const LoginRoute = LoginImport.update({ + id: '/login', + path: '/login', + getParentRoute: () => rootRoute, +} as any) + +const AboutRoute = AboutImport.update({ + id: '/about', + path: '/about', + getParentRoute: () => rootRoute, +} as any) + +const AuthRoute = AuthImport.update({ + id: '/_auth', + getParentRoute: () => rootRoute, +} as any) + +const IndexRoute = IndexImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRoute, +} as any) + +const OcpIndexRoute = OcpIndexImport.update({ + id: '/ocp/', + path: '/ocp/', + getParentRoute: () => rootRoute, +} as any) + +const OcpLotsRoute = OcpLotsImport.update({ + id: '/ocp/lots', + path: '/ocp/lots', + getParentRoute: () => rootRoute, +} as any) + +const OcpLineIDRoute = OcpLineIDImport.update({ + id: '/ocp/$lineID', + path: '/ocp/$lineID', + getParentRoute: () => rootRoute, +} as any) + +const AuthProfileRoute = AuthProfileImport.update({ + id: '/profile', + path: '/profile', + getParentRoute: () => AuthRoute, +} as any) + +const AuthDashboardRoute = AuthDashboardImport.update({ + id: '/dashboard', + path: '/dashboard', + getParentRoute: () => AuthRoute, +} as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexImport + parentRoute: typeof rootRoute + } + '/_auth': { + id: '/_auth' + path: '' + fullPath: '' + preLoaderRoute: typeof AuthImport + parentRoute: typeof rootRoute + } + '/about': { + id: '/about' + path: '/about' + fullPath: '/about' + preLoaderRoute: typeof AboutImport + parentRoute: typeof rootRoute + } + '/login': { + id: '/login' + path: '/login' + fullPath: '/login' + preLoaderRoute: typeof LoginImport + parentRoute: typeof rootRoute + } + '/_auth/dashboard': { + id: '/_auth/dashboard' + path: '/dashboard' + fullPath: '/dashboard' + preLoaderRoute: typeof AuthDashboardImport + parentRoute: typeof AuthImport + } + '/_auth/profile': { + id: '/_auth/profile' + path: '/profile' + fullPath: '/profile' + preLoaderRoute: typeof AuthProfileImport + parentRoute: typeof AuthImport + } + '/ocp/$lineID': { + id: '/ocp/$lineID' + path: '/ocp/$lineID' + fullPath: '/ocp/$lineID' + preLoaderRoute: typeof OcpLineIDImport + parentRoute: typeof rootRoute + } + '/ocp/lots': { + id: '/ocp/lots' + path: '/ocp/lots' + fullPath: '/ocp/lots' + preLoaderRoute: typeof OcpLotsImport + parentRoute: typeof rootRoute + } + '/ocp/': { + id: '/ocp/' + path: '/ocp' + fullPath: '/ocp' + preLoaderRoute: typeof OcpIndexImport + parentRoute: typeof rootRoute + } + } +} + +// Create and export the route tree + +interface AuthRouteChildren { + AuthDashboardRoute: typeof AuthDashboardRoute + AuthProfileRoute: typeof AuthProfileRoute +} + +const AuthRouteChildren: AuthRouteChildren = { + AuthDashboardRoute: AuthDashboardRoute, + AuthProfileRoute: AuthProfileRoute, +} + +const AuthRouteWithChildren = AuthRoute._addFileChildren(AuthRouteChildren) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute + '': typeof AuthRouteWithChildren + '/about': typeof AboutRoute + '/login': typeof LoginRoute + '/dashboard': typeof AuthDashboardRoute + '/profile': typeof AuthProfileRoute + '/ocp/$lineID': typeof OcpLineIDRoute + '/ocp/lots': typeof OcpLotsRoute + '/ocp': typeof OcpIndexRoute +} + +export interface FileRoutesByTo { + '/': typeof IndexRoute + '': typeof AuthRouteWithChildren + '/about': typeof AboutRoute + '/login': typeof LoginRoute + '/dashboard': typeof AuthDashboardRoute + '/profile': typeof AuthProfileRoute + '/ocp/$lineID': typeof OcpLineIDRoute + '/ocp/lots': typeof OcpLotsRoute + '/ocp': typeof OcpIndexRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/': typeof IndexRoute + '/_auth': typeof AuthRouteWithChildren + '/about': typeof AboutRoute + '/login': typeof LoginRoute + '/_auth/dashboard': typeof AuthDashboardRoute + '/_auth/profile': typeof AuthProfileRoute + '/ocp/$lineID': typeof OcpLineIDRoute + '/ocp/lots': typeof OcpLotsRoute + '/ocp/': typeof OcpIndexRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '/' + | '' + | '/about' + | '/login' + | '/dashboard' + | '/profile' + | '/ocp/$lineID' + | '/ocp/lots' + | '/ocp' + fileRoutesByTo: FileRoutesByTo + to: + | '/' + | '' + | '/about' + | '/login' + | '/dashboard' + | '/profile' + | '/ocp/$lineID' + | '/ocp/lots' + | '/ocp' + id: + | '__root__' + | '/' + | '/_auth' + | '/about' + | '/login' + | '/_auth/dashboard' + | '/_auth/profile' + | '/ocp/$lineID' + | '/ocp/lots' + | '/ocp/' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute + AuthRoute: typeof AuthRouteWithChildren + AboutRoute: typeof AboutRoute + LoginRoute: typeof LoginRoute + OcpLineIDRoute: typeof OcpLineIDRoute + OcpLotsRoute: typeof OcpLotsRoute + OcpIndexRoute: typeof OcpIndexRoute +} + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, + AuthRoute: AuthRouteWithChildren, + AboutRoute: AboutRoute, + LoginRoute: LoginRoute, + OcpLineIDRoute: OcpLineIDRoute, + OcpLotsRoute: OcpLotsRoute, + OcpIndexRoute: OcpIndexRoute, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/", + "/_auth", + "/about", + "/login", + "/ocp/$lineID", + "/ocp/lots", + "/ocp/" + ] + }, + "/": { + "filePath": "index.tsx" + }, + "/_auth": { + "filePath": "_auth.tsx", + "children": [ + "/_auth/dashboard", + "/_auth/profile" + ] + }, + "/about": { + "filePath": "about.tsx" + }, + "/login": { + "filePath": "login.tsx" + }, + "/_auth/dashboard": { + "filePath": "_auth/dashboard.tsx", + "parent": "/_auth" + }, + "/_auth/profile": { + "filePath": "_auth/profile.tsx", + "parent": "/_auth" + }, + "/ocp/$lineID": { + "filePath": "ocp/$lineID.tsx" + }, + "/ocp/lots": { + "filePath": "ocp/lots.tsx" + }, + "/ocp/": { + "filePath": "ocp/index.tsx" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/frontend/src/routes/__root.tsx b/frontend/src/routes/__root.tsx new file mode 100644 index 0000000..5358d87 --- /dev/null +++ b/frontend/src/routes/__root.tsx @@ -0,0 +1,42 @@ +import {createRootRouteWithContext, Link, Outlet} from "@tanstack/react-router"; +import {TanStackRouterDevtools} from "@tanstack/router-devtools"; +import {SessionType} from "../lib/hooks/useSession"; + +type RouterContext = { + sessionType: SessionType; +}; +// same as the layout +export const Route = createRootRouteWithContext()({ + component: () => { + return ( + <> +
    + + Home + {" "} + + About + + + dashboard + + + {({isActive}) => <>Profile {isActive && "~"}} + + + {({isActive}) => <>OCP {isActive && "~"}} + +
    +
    + + + + + ); + }, +}); diff --git a/frontend/src/routes/_auth.tsx b/frontend/src/routes/_auth.tsx new file mode 100644 index 0000000..43aa3c1 --- /dev/null +++ b/frontend/src/routes/_auth.tsx @@ -0,0 +1,12 @@ +import {createFileRoute, redirect} from "@tanstack/react-router"; + +// src/routes/_authenticated.tsx +export const Route = createFileRoute("/_auth")({ + beforeLoad: async ({context}) => { + if (!context.sessionType.session) { + throw redirect({ + to: "/", + }); + } + }, +}); diff --git a/frontend/src/routes/_auth/dashboard.tsx b/frontend/src/routes/_auth/dashboard.tsx new file mode 100644 index 0000000..09dd879 --- /dev/null +++ b/frontend/src/routes/_auth/dashboard.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/_auth/dashboard')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
    Hello "/_auth/dashboard"!
    +} diff --git a/frontend/src/routes/_auth/profile.tsx b/frontend/src/routes/_auth/profile.tsx new file mode 100644 index 0000000..aeb10b9 --- /dev/null +++ b/frontend/src/routes/_auth/profile.tsx @@ -0,0 +1,9 @@ +import {createFileRoute} from "@tanstack/react-router"; + +export const Route = createFileRoute("/_auth/profile")({ + component: RouteComponent, +}); + +function RouteComponent() { + return
    Hello "/profile"!
    ; +} diff --git a/frontend/src/routes/about.tsx b/frontend/src/routes/about.tsx new file mode 100644 index 0000000..baad8db --- /dev/null +++ b/frontend/src/routes/about.tsx @@ -0,0 +1,13 @@ +import {createFileRoute} from "@tanstack/react-router"; + +export const Route = createFileRoute("/about")({ + component: About, +}); + +function About() { + return ( +
    +

    About page to come.

    +
    + ); +} diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx new file mode 100644 index 0000000..6074078 --- /dev/null +++ b/frontend/src/routes/index.tsx @@ -0,0 +1,29 @@ +import {createFileRoute} from "@tanstack/react-router"; +import LoginForm from "../components/auth/LoginForm"; +import {Button} from "../components/ui/button"; +import {useLogout} from "../lib/hooks/useLogout"; +import {useSession} from "../lib/hooks/useSession"; + +export const Route = createFileRoute("/")({ + component: Index, +}); + +function Index() { + const {session} = useSession(); + const logout = useLogout(); + return ( +
    +

    Welcome Home!

    +

    +

    + {session ? ( + <> + {" "} + + ) : ( + + )} +

    +
    + ); +} diff --git a/frontend/src/routes/login.tsx b/frontend/src/routes/login.tsx new file mode 100644 index 0000000..71be4d8 --- /dev/null +++ b/frontend/src/routes/login.tsx @@ -0,0 +1,38 @@ +import {createFileRoute, useRouter} from "@tanstack/react-router"; +import {isAuthenticated, signIn, signOut} from "../utils/auth"; +import {Button} from "../components/ui/button"; + +export const Route = createFileRoute("/login")({ + component: RouteComponent, +}); + +function RouteComponent() { + const router = useRouter(); + return ( +
    +

    Ligin

    + {isAuthenticated() ? ( + <> +

    Hello User!

    + + + ) : ( + + )} +
    + ); +} diff --git a/frontend/src/routes/ocp/$lineID.tsx b/frontend/src/routes/ocp/$lineID.tsx new file mode 100644 index 0000000..6dcbd5c --- /dev/null +++ b/frontend/src/routes/ocp/$lineID.tsx @@ -0,0 +1,17 @@ +import {createFileRoute} from "@tanstack/react-router"; + +export const Route = createFileRoute("/ocp/$lineID")({ + component: RouteComponent, + loader: async ({params}) => { + await new Promise((r) => setTimeout(r, 1500)); + //throw new Error(); + return {lineID: params.lineID}; + }, + pendingComponent: () =>
    Loading....
    , + errorComponent: () =>
    Error....
    , +}); + +function RouteComponent() { + const {lineID} = Route.useLoaderData(); + return
    Hello "/ocp/{lineID}"!
    ; +} diff --git a/frontend/src/routes/ocp/index.tsx b/frontend/src/routes/ocp/index.tsx new file mode 100644 index 0000000..9af23da --- /dev/null +++ b/frontend/src/routes/ocp/index.tsx @@ -0,0 +1,34 @@ +import {createFileRoute, Link} from "@tanstack/react-router"; + +export const Route = createFileRoute("/ocp/")({ + component: RouteComponent, + validateSearch: (search) => { + return { + q: (search.q as string) || "", + }; + }, + loaderDeps: ({search: {q}}) => ({q}), + loader: async ({deps: {q}}) => { + return {line: q}; + }, +}); + +function RouteComponent() { + const {line} = Route.useLoaderData(); + + const lines = ["l", "2", "3"]; + return ( +
    +

    Hello "/ocp/{line}/something"!

    + {lines.map((line) => { + return ( +
    + + Post + +
    + ); + })} +
    + ); +} diff --git a/frontend/src/routes/ocp/lots.tsx b/frontend/src/routes/ocp/lots.tsx new file mode 100644 index 0000000..4011f02 --- /dev/null +++ b/frontend/src/routes/ocp/lots.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/ocp/lots')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
    Hello "/ocp/lots"!
    +} diff --git a/frontend/src/utils/auth.ts b/frontend/src/utils/auth.ts new file mode 100644 index 0000000..67f6a58 --- /dev/null +++ b/frontend/src/utils/auth.ts @@ -0,0 +1,11 @@ +export function isAuthenticated() { + return localStorage.getItem("isAuthenticated") === "true"; +} + +export function signIn() { + return localStorage.setItem("isAuthenticated", "true"); +} + +export function signOut() { + return localStorage.removeItem("isAuthenticated"); +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 03c513b..383b219 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,11 +1,12 @@ import {defineConfig} from "vite"; import react from "@vitejs/plugin-react-swc"; import tailwindcss from "@tailwindcss/vite"; +import {TanStackRouterVite} from "@tanstack/router-plugin/vite"; import path from "path"; // https://vite.dev/config/ export default defineConfig({ - plugins: [react(), tailwindcss()], + plugins: [react(), tailwindcss(), TanStackRouterVite({autoCodeSplitting: true})], // build: { // outDir: path.resolve(__dirname, "../../dist/frontend/dist"), // emptyOutDir: true, diff --git a/package.json b/package.json index 55ab607..9e446d0 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "build:server": "cd apps/server && bun build index.js --outdir ../../dist/server", "build:ocme": "rimraf dist/ocme && cd apps/ocme && bun build index.js --outdir ../../dist/ocme", "build:front": "cd frontend && rimraf frontend/dist && bun run build", - "start": "bun --env-file .env run ./server/index.js", + "start": "cd server && bun run --env-file ../.env ./index.js", "commit": "cz", "clean": "rimraf dist/server", "deploy": "standard-version --conventional-commits" diff --git a/server/src/app.ts b/server/src/app.ts index 51a49c6..9a0b0eb 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -52,8 +52,8 @@ routes.forEach((route) => { // return c.json({success: true, message: "is authenticated"}); // }); -app.get("*", serveStatic({root: "./frontend/dist"})); -app.get("*", serveStatic({path: "./frontend/dist/index.html"})); +app.get("*", serveStatic({root: "../frontend/dist"})); +app.get("*", serveStatic({path: "../frontend/dist/index.html"})); export default app;