diff --git a/.changeset/khaki-dogs-reflect.md b/.changeset/khaki-dogs-reflect.md
new file mode 100644
index 0000000..bbb778b
--- /dev/null
+++ b/.changeset/khaki-dogs-reflect.md
@@ -0,0 +1,5 @@
+---
+"namesake": patch
+---
+
+Improve auth redirect logic
diff --git a/package.json b/package.json
index 7cbcb70..228a0c8 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
},
"dependencies": {
"@auth/core": "^0.34.2",
- "@convex-dev/auth": "^0.0.67",
+ "@convex-dev/auth": "^0.0.69",
"@faker-js/faker": "^9.0.1",
"@mdxeditor/editor": "^3.11.4",
"@pdfme/common": "^4.5.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6de4052..1f259fb 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -16,8 +16,8 @@ importers:
specifier: ^0.34.2
version: 0.34.2
'@convex-dev/auth':
- specifier: ^0.0.67
- version: 0.0.67(convex@1.16.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
+ specifier: ^0.0.69
+ version: 0.0.69(convex@1.16.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
'@faker-js/faker':
specifier: ^9.0.1
version: 9.0.1
@@ -639,8 +639,8 @@ packages:
react: ^16.8.0 || ^17 || ^18
react-dom: ^16.8.0 || ^17 || ^18
- '@convex-dev/auth@0.0.67':
- resolution: {integrity: sha512-XUNTe3X7qxzAkpgP/qekuQ7Fc3qE1i2BrbBjyKO5jyFJ0qrvoNr0PRSKofnLYnjTrjG12wkm9KJx56og4pyJUw==}
+ '@convex-dev/auth@0.0.69':
+ resolution: {integrity: sha512-qM7Q1ntNTuOCtUILBzZhSANY/zDpntjtg31ME1bV43+RnM/JfiWpduvs/qTQXWUiil60DawuZ0tdpGse8uNxvg==}
hasBin: true
peerDependencies:
convex: ^1.14.4
@@ -7648,7 +7648,7 @@ snapshots:
transitivePeerDependencies:
- '@lezer/common'
- '@convex-dev/auth@0.0.67(convex@1.16.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)':
+ '@convex-dev/auth@0.0.69(convex@1.16.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)':
dependencies:
'@auth/core': 0.31.0
arctic: 1.9.2
diff --git a/src/components/AppHeader/AppHeader.tsx b/src/components/AppHeader/AppHeader.tsx
index 6a4425d..e59d3be 100644
--- a/src/components/AppHeader/AppHeader.tsx
+++ b/src/components/AppHeader/AppHeader.tsx
@@ -1,7 +1,8 @@
import { useAuthActions } from "@convex-dev/auth/react";
+import { api } from "@convex/_generated/api";
import { RiAccountCircleFill } from "@remixicon/react";
-import { useQuery } from "convex/react";
-import { api } from "../../../convex/_generated/api";
+import { redirect } from "@tanstack/react-router";
+import { Authenticated, useQuery } from "convex/react";
import { Button } from "../Button";
import { Link } from "../Link";
import { Logo } from "../Logo";
@@ -12,32 +13,39 @@ export const AppHeader = () => {
const role = useQuery(api.users.getCurrentUserRole);
const isAdmin = role === "admin";
+ const handleSignOut = () => {
+ signOut();
+ redirect({ to: "/", throw: true });
+ };
+
return (
-
+
- {isAdmin &&
Admin}
-
-
-
-
-
-
+
+ {isAdmin && Admin}
+
+
+
+
+
+
+
);
};
diff --git a/src/main.tsx b/src/main.tsx
index e8b6a30..7bb4706 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,13 +1,18 @@
import "./styles/index.css";
import { ConvexAuthProvider } from "@convex-dev/auth/react";
+import { api } from "@convex/_generated/api";
import { RiErrorWarningLine } from "@remixicon/react";
import { RouterProvider, createRouter } from "@tanstack/react-router";
-import { ConvexReactClient, useConvexAuth, useQuery } from "convex/react";
+import {
+ type ConvexAuthState,
+ ConvexReactClient,
+ useConvexAuth,
+ useQuery,
+} from "convex/react";
import { ThemeProvider } from "next-themes";
-import { StrictMode } from "react";
+import { StrictMode, useEffect } from "react";
import { createRoot } from "react-dom/client";
import { HelmetProvider } from "react-helmet-async";
-import { api } from "../convex/_generated/api";
import { Empty } from "./components";
import { routeTree } from "./routeTree.gen";
@@ -20,6 +25,7 @@ const router = createRouter({
auth: undefined!,
role: undefined!,
},
+ defaultPreload: "intent",
defaultNotFoundComponent: () => (
void;
+const authClient: Promise = new Promise((resolve) => {
+ resolveAuth = resolve;
+});
+
const InnerApp = () => {
const title = "Namesake";
const auth = useConvexAuth();
const role = useQuery(api.users.getCurrentUserRole) ?? undefined;
- return ;
+ useEffect(() => {
+ if (auth.isLoading) return;
+
+ resolveAuth(auth);
+ }, [auth, auth.isLoading]);
+
+ return (
+
+ );
};
const rootElement = document.getElementById("root")!;
diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts
index f19d6ff..ba13332 100644
--- a/src/routeTree.gen.ts
+++ b/src/routeTree.gen.ts
@@ -11,225 +11,315 @@
// Import Routes
import { Route as rootRoute } from './routes/__root'
-import { Route as QuestsRouteImport } from './routes/quests/route'
-import { Route as AdminRouteImport } from './routes/admin/route'
-import { Route as IndexImport } from './routes/index'
-import { Route as SettingsIndexImport } from './routes/settings/index'
-import { Route as AdminIndexImport } from './routes/admin/index'
-import { Route as QuestsQuestIdImport } from './routes/quests/$questId'
-import { Route as AdminQuestsIndexImport } from './routes/admin/quests/index'
-import { Route as AdminFormsIndexImport } from './routes/admin/forms/index'
-import { Route as AdminQuestsQuestIdImport } from './routes/admin/quests/$questId'
-import { Route as AdminFormsFormIdImport } from './routes/admin/forms/$formId'
+import { Route as UnauthenticatedImport } from './routes/_unauthenticated'
+import { Route as AuthenticatedImport } from './routes/_authenticated'
+import { Route as AuthenticatedIndexImport } from './routes/_authenticated/index'
+import { Route as UnauthenticatedLoginImport } from './routes/_unauthenticated/login'
+import { Route as AuthenticatedQuestsRouteImport } from './routes/_authenticated/quests/route'
+import { Route as AuthenticatedAdminRouteImport } from './routes/_authenticated/admin/route'
+import { Route as AuthenticatedSettingsIndexImport } from './routes/_authenticated/settings/index'
+import { Route as AuthenticatedAdminIndexImport } from './routes/_authenticated/admin/index'
+import { Route as AuthenticatedQuestsQuestIdImport } from './routes/_authenticated/quests/$questId'
+import { Route as AuthenticatedAdminQuestsIndexImport } from './routes/_authenticated/admin/quests/index'
+import { Route as AuthenticatedAdminFormsIndexImport } from './routes/_authenticated/admin/forms/index'
+import { Route as AuthenticatedAdminQuestsQuestIdImport } from './routes/_authenticated/admin/quests/$questId'
+import { Route as AuthenticatedAdminFormsFormIdImport } from './routes/_authenticated/admin/forms/$formId'
// Create/Update Routes
-const QuestsRouteRoute = QuestsRouteImport.update({
- path: '/quests',
+const UnauthenticatedRoute = UnauthenticatedImport.update({
+ id: '/_unauthenticated',
getParentRoute: () => rootRoute,
} as any)
-const AdminRouteRoute = AdminRouteImport.update({
- path: '/admin',
+const AuthenticatedRoute = AuthenticatedImport.update({
+ id: '/_authenticated',
getParentRoute: () => rootRoute,
} as any)
-const IndexRoute = IndexImport.update({
+const AuthenticatedIndexRoute = AuthenticatedIndexImport.update({
path: '/',
- getParentRoute: () => rootRoute,
+ getParentRoute: () => AuthenticatedRoute,
} as any)
-const SettingsIndexRoute = SettingsIndexImport.update({
- path: '/settings/',
- getParentRoute: () => rootRoute,
+const UnauthenticatedLoginRoute = UnauthenticatedLoginImport.update({
+ path: '/login',
+ getParentRoute: () => UnauthenticatedRoute,
} as any)
-const AdminIndexRoute = AdminIndexImport.update({
- path: '/',
- getParentRoute: () => AdminRouteRoute,
+const AuthenticatedQuestsRouteRoute = AuthenticatedQuestsRouteImport.update({
+ path: '/quests',
+ getParentRoute: () => AuthenticatedRoute,
} as any)
-const QuestsQuestIdRoute = QuestsQuestIdImport.update({
- path: '/$questId',
- getParentRoute: () => QuestsRouteRoute,
+const AuthenticatedAdminRouteRoute = AuthenticatedAdminRouteImport.update({
+ path: '/admin',
+ getParentRoute: () => AuthenticatedRoute,
} as any)
-const AdminQuestsIndexRoute = AdminQuestsIndexImport.update({
- path: '/quests/',
- getParentRoute: () => AdminRouteRoute,
-} as any)
+const AuthenticatedSettingsIndexRoute = AuthenticatedSettingsIndexImport.update(
+ {
+ path: '/settings/',
+ getParentRoute: () => AuthenticatedRoute,
+ } as any,
+)
-const AdminFormsIndexRoute = AdminFormsIndexImport.update({
- path: '/forms/',
- getParentRoute: () => AdminRouteRoute,
+const AuthenticatedAdminIndexRoute = AuthenticatedAdminIndexImport.update({
+ path: '/',
+ getParentRoute: () => AuthenticatedAdminRouteRoute,
} as any)
-const AdminQuestsQuestIdRoute = AdminQuestsQuestIdImport.update({
- path: '/quests/$questId',
- getParentRoute: () => AdminRouteRoute,
-} as any)
+const AuthenticatedQuestsQuestIdRoute = AuthenticatedQuestsQuestIdImport.update(
+ {
+ path: '/$questId',
+ getParentRoute: () => AuthenticatedQuestsRouteRoute,
+ } as any,
+)
-const AdminFormsFormIdRoute = AdminFormsFormIdImport.update({
- path: '/forms/$formId',
- getParentRoute: () => AdminRouteRoute,
-} as any)
+const AuthenticatedAdminQuestsIndexRoute =
+ AuthenticatedAdminQuestsIndexImport.update({
+ path: '/quests/',
+ getParentRoute: () => AuthenticatedAdminRouteRoute,
+ } as any)
+
+const AuthenticatedAdminFormsIndexRoute =
+ AuthenticatedAdminFormsIndexImport.update({
+ path: '/forms/',
+ getParentRoute: () => AuthenticatedAdminRouteRoute,
+ } as any)
+
+const AuthenticatedAdminQuestsQuestIdRoute =
+ AuthenticatedAdminQuestsQuestIdImport.update({
+ path: '/quests/$questId',
+ getParentRoute: () => AuthenticatedAdminRouteRoute,
+ } as any)
+
+const AuthenticatedAdminFormsFormIdRoute =
+ AuthenticatedAdminFormsFormIdImport.update({
+ path: '/forms/$formId',
+ getParentRoute: () => AuthenticatedAdminRouteRoute,
+ } 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
+ }
+ '/_unauthenticated': {
+ id: '/_unauthenticated'
+ path: ''
+ fullPath: ''
+ preLoaderRoute: typeof UnauthenticatedImport
parentRoute: typeof rootRoute
}
- '/admin': {
- id: '/admin'
+ '/_authenticated/admin': {
+ id: '/_authenticated/admin'
path: '/admin'
fullPath: '/admin'
- preLoaderRoute: typeof AdminRouteImport
- parentRoute: typeof rootRoute
+ preLoaderRoute: typeof AuthenticatedAdminRouteImport
+ parentRoute: typeof AuthenticatedImport
}
- '/quests': {
- id: '/quests'
+ '/_authenticated/quests': {
+ id: '/_authenticated/quests'
path: '/quests'
fullPath: '/quests'
- preLoaderRoute: typeof QuestsRouteImport
- parentRoute: typeof rootRoute
+ preLoaderRoute: typeof AuthenticatedQuestsRouteImport
+ parentRoute: typeof AuthenticatedImport
+ }
+ '/_unauthenticated/login': {
+ id: '/_unauthenticated/login'
+ path: '/login'
+ fullPath: '/login'
+ preLoaderRoute: typeof UnauthenticatedLoginImport
+ parentRoute: typeof UnauthenticatedImport
}
- '/quests/$questId': {
- id: '/quests/$questId'
+ '/_authenticated/': {
+ id: '/_authenticated/'
+ path: '/'
+ fullPath: '/'
+ preLoaderRoute: typeof AuthenticatedIndexImport
+ parentRoute: typeof AuthenticatedImport
+ }
+ '/_authenticated/quests/$questId': {
+ id: '/_authenticated/quests/$questId'
path: '/$questId'
fullPath: '/quests/$questId'
- preLoaderRoute: typeof QuestsQuestIdImport
- parentRoute: typeof QuestsRouteImport
+ preLoaderRoute: typeof AuthenticatedQuestsQuestIdImport
+ parentRoute: typeof AuthenticatedQuestsRouteImport
}
- '/admin/': {
- id: '/admin/'
+ '/_authenticated/admin/': {
+ id: '/_authenticated/admin/'
path: '/'
fullPath: '/admin/'
- preLoaderRoute: typeof AdminIndexImport
- parentRoute: typeof AdminRouteImport
+ preLoaderRoute: typeof AuthenticatedAdminIndexImport
+ parentRoute: typeof AuthenticatedAdminRouteImport
}
- '/settings/': {
- id: '/settings/'
+ '/_authenticated/settings/': {
+ id: '/_authenticated/settings/'
path: '/settings'
fullPath: '/settings'
- preLoaderRoute: typeof SettingsIndexImport
- parentRoute: typeof rootRoute
+ preLoaderRoute: typeof AuthenticatedSettingsIndexImport
+ parentRoute: typeof AuthenticatedImport
}
- '/admin/forms/$formId': {
- id: '/admin/forms/$formId'
+ '/_authenticated/admin/forms/$formId': {
+ id: '/_authenticated/admin/forms/$formId'
path: '/forms/$formId'
fullPath: '/admin/forms/$formId'
- preLoaderRoute: typeof AdminFormsFormIdImport
- parentRoute: typeof AdminRouteImport
+ preLoaderRoute: typeof AuthenticatedAdminFormsFormIdImport
+ parentRoute: typeof AuthenticatedAdminRouteImport
}
- '/admin/quests/$questId': {
- id: '/admin/quests/$questId'
+ '/_authenticated/admin/quests/$questId': {
+ id: '/_authenticated/admin/quests/$questId'
path: '/quests/$questId'
fullPath: '/admin/quests/$questId'
- preLoaderRoute: typeof AdminQuestsQuestIdImport
- parentRoute: typeof AdminRouteImport
+ preLoaderRoute: typeof AuthenticatedAdminQuestsQuestIdImport
+ parentRoute: typeof AuthenticatedAdminRouteImport
}
- '/admin/forms/': {
- id: '/admin/forms/'
+ '/_authenticated/admin/forms/': {
+ id: '/_authenticated/admin/forms/'
path: '/forms'
fullPath: '/admin/forms'
- preLoaderRoute: typeof AdminFormsIndexImport
- parentRoute: typeof AdminRouteImport
+ preLoaderRoute: typeof AuthenticatedAdminFormsIndexImport
+ parentRoute: typeof AuthenticatedAdminRouteImport
}
- '/admin/quests/': {
- id: '/admin/quests/'
+ '/_authenticated/admin/quests/': {
+ id: '/_authenticated/admin/quests/'
path: '/quests'
fullPath: '/admin/quests'
- preLoaderRoute: typeof AdminQuestsIndexImport
- parentRoute: typeof AdminRouteImport
+ preLoaderRoute: typeof AuthenticatedAdminQuestsIndexImport
+ parentRoute: typeof AuthenticatedAdminRouteImport
}
}
}
// Create and export the route tree
-interface AdminRouteRouteChildren {
- AdminIndexRoute: typeof AdminIndexRoute
- AdminFormsFormIdRoute: typeof AdminFormsFormIdRoute
- AdminQuestsQuestIdRoute: typeof AdminQuestsQuestIdRoute
- AdminFormsIndexRoute: typeof AdminFormsIndexRoute
- AdminQuestsIndexRoute: typeof AdminQuestsIndexRoute
+interface AuthenticatedAdminRouteRouteChildren {
+ AuthenticatedAdminIndexRoute: typeof AuthenticatedAdminIndexRoute
+ AuthenticatedAdminFormsFormIdRoute: typeof AuthenticatedAdminFormsFormIdRoute
+ AuthenticatedAdminQuestsQuestIdRoute: typeof AuthenticatedAdminQuestsQuestIdRoute
+ AuthenticatedAdminFormsIndexRoute: typeof AuthenticatedAdminFormsIndexRoute
+ AuthenticatedAdminQuestsIndexRoute: typeof AuthenticatedAdminQuestsIndexRoute
+}
+
+const AuthenticatedAdminRouteRouteChildren: AuthenticatedAdminRouteRouteChildren =
+ {
+ AuthenticatedAdminIndexRoute: AuthenticatedAdminIndexRoute,
+ AuthenticatedAdminFormsFormIdRoute: AuthenticatedAdminFormsFormIdRoute,
+ AuthenticatedAdminQuestsQuestIdRoute: AuthenticatedAdminQuestsQuestIdRoute,
+ AuthenticatedAdminFormsIndexRoute: AuthenticatedAdminFormsIndexRoute,
+ AuthenticatedAdminQuestsIndexRoute: AuthenticatedAdminQuestsIndexRoute,
+ }
+
+const AuthenticatedAdminRouteRouteWithChildren =
+ AuthenticatedAdminRouteRoute._addFileChildren(
+ AuthenticatedAdminRouteRouteChildren,
+ )
+
+interface AuthenticatedQuestsRouteRouteChildren {
+ AuthenticatedQuestsQuestIdRoute: typeof AuthenticatedQuestsQuestIdRoute
}
-const AdminRouteRouteChildren: AdminRouteRouteChildren = {
- AdminIndexRoute: AdminIndexRoute,
- AdminFormsFormIdRoute: AdminFormsFormIdRoute,
- AdminQuestsQuestIdRoute: AdminQuestsQuestIdRoute,
- AdminFormsIndexRoute: AdminFormsIndexRoute,
- AdminQuestsIndexRoute: AdminQuestsIndexRoute,
+const AuthenticatedQuestsRouteRouteChildren: AuthenticatedQuestsRouteRouteChildren =
+ {
+ AuthenticatedQuestsQuestIdRoute: AuthenticatedQuestsQuestIdRoute,
+ }
+
+const AuthenticatedQuestsRouteRouteWithChildren =
+ AuthenticatedQuestsRouteRoute._addFileChildren(
+ AuthenticatedQuestsRouteRouteChildren,
+ )
+
+interface AuthenticatedRouteChildren {
+ AuthenticatedAdminRouteRoute: typeof AuthenticatedAdminRouteRouteWithChildren
+ AuthenticatedQuestsRouteRoute: typeof AuthenticatedQuestsRouteRouteWithChildren
+ AuthenticatedIndexRoute: typeof AuthenticatedIndexRoute
+ AuthenticatedSettingsIndexRoute: typeof AuthenticatedSettingsIndexRoute
}
-const AdminRouteRouteWithChildren = AdminRouteRoute._addFileChildren(
- AdminRouteRouteChildren,
+const AuthenticatedRouteChildren: AuthenticatedRouteChildren = {
+ AuthenticatedAdminRouteRoute: AuthenticatedAdminRouteRouteWithChildren,
+ AuthenticatedQuestsRouteRoute: AuthenticatedQuestsRouteRouteWithChildren,
+ AuthenticatedIndexRoute: AuthenticatedIndexRoute,
+ AuthenticatedSettingsIndexRoute: AuthenticatedSettingsIndexRoute,
+}
+
+const AuthenticatedRouteWithChildren = AuthenticatedRoute._addFileChildren(
+ AuthenticatedRouteChildren,
)
-interface QuestsRouteRouteChildren {
- QuestsQuestIdRoute: typeof QuestsQuestIdRoute
+interface UnauthenticatedRouteChildren {
+ UnauthenticatedLoginRoute: typeof UnauthenticatedLoginRoute
}
-const QuestsRouteRouteChildren: QuestsRouteRouteChildren = {
- QuestsQuestIdRoute: QuestsQuestIdRoute,
+const UnauthenticatedRouteChildren: UnauthenticatedRouteChildren = {
+ UnauthenticatedLoginRoute: UnauthenticatedLoginRoute,
}
-const QuestsRouteRouteWithChildren = QuestsRouteRoute._addFileChildren(
- QuestsRouteRouteChildren,
+const UnauthenticatedRouteWithChildren = UnauthenticatedRoute._addFileChildren(
+ UnauthenticatedRouteChildren,
)
export interface FileRoutesByFullPath {
- '/': typeof IndexRoute
- '/admin': typeof AdminRouteRouteWithChildren
- '/quests': typeof QuestsRouteRouteWithChildren
- '/quests/$questId': typeof QuestsQuestIdRoute
- '/admin/': typeof AdminIndexRoute
- '/settings': typeof SettingsIndexRoute
- '/admin/forms/$formId': typeof AdminFormsFormIdRoute
- '/admin/quests/$questId': typeof AdminQuestsQuestIdRoute
- '/admin/forms': typeof AdminFormsIndexRoute
- '/admin/quests': typeof AdminQuestsIndexRoute
+ '': typeof UnauthenticatedRouteWithChildren
+ '/admin': typeof AuthenticatedAdminRouteRouteWithChildren
+ '/quests': typeof AuthenticatedQuestsRouteRouteWithChildren
+ '/login': typeof UnauthenticatedLoginRoute
+ '/': typeof AuthenticatedIndexRoute
+ '/quests/$questId': typeof AuthenticatedQuestsQuestIdRoute
+ '/admin/': typeof AuthenticatedAdminIndexRoute
+ '/settings': typeof AuthenticatedSettingsIndexRoute
+ '/admin/forms/$formId': typeof AuthenticatedAdminFormsFormIdRoute
+ '/admin/quests/$questId': typeof AuthenticatedAdminQuestsQuestIdRoute
+ '/admin/forms': typeof AuthenticatedAdminFormsIndexRoute
+ '/admin/quests': typeof AuthenticatedAdminQuestsIndexRoute
}
export interface FileRoutesByTo {
- '/': typeof IndexRoute
- '/quests': typeof QuestsRouteRouteWithChildren
- '/quests/$questId': typeof QuestsQuestIdRoute
- '/admin': typeof AdminIndexRoute
- '/settings': typeof SettingsIndexRoute
- '/admin/forms/$formId': typeof AdminFormsFormIdRoute
- '/admin/quests/$questId': typeof AdminQuestsQuestIdRoute
- '/admin/forms': typeof AdminFormsIndexRoute
- '/admin/quests': typeof AdminQuestsIndexRoute
+ '': typeof UnauthenticatedRouteWithChildren
+ '/quests': typeof AuthenticatedQuestsRouteRouteWithChildren
+ '/login': typeof UnauthenticatedLoginRoute
+ '/': typeof AuthenticatedIndexRoute
+ '/quests/$questId': typeof AuthenticatedQuestsQuestIdRoute
+ '/admin': typeof AuthenticatedAdminIndexRoute
+ '/settings': typeof AuthenticatedSettingsIndexRoute
+ '/admin/forms/$formId': typeof AuthenticatedAdminFormsFormIdRoute
+ '/admin/quests/$questId': typeof AuthenticatedAdminQuestsQuestIdRoute
+ '/admin/forms': typeof AuthenticatedAdminFormsIndexRoute
+ '/admin/quests': typeof AuthenticatedAdminQuestsIndexRoute
}
export interface FileRoutesById {
__root__: typeof rootRoute
- '/': typeof IndexRoute
- '/admin': typeof AdminRouteRouteWithChildren
- '/quests': typeof QuestsRouteRouteWithChildren
- '/quests/$questId': typeof QuestsQuestIdRoute
- '/admin/': typeof AdminIndexRoute
- '/settings/': typeof SettingsIndexRoute
- '/admin/forms/$formId': typeof AdminFormsFormIdRoute
- '/admin/quests/$questId': typeof AdminQuestsQuestIdRoute
- '/admin/forms/': typeof AdminFormsIndexRoute
- '/admin/quests/': typeof AdminQuestsIndexRoute
+ '/_authenticated': typeof AuthenticatedRouteWithChildren
+ '/_unauthenticated': typeof UnauthenticatedRouteWithChildren
+ '/_authenticated/admin': typeof AuthenticatedAdminRouteRouteWithChildren
+ '/_authenticated/quests': typeof AuthenticatedQuestsRouteRouteWithChildren
+ '/_unauthenticated/login': typeof UnauthenticatedLoginRoute
+ '/_authenticated/': typeof AuthenticatedIndexRoute
+ '/_authenticated/quests/$questId': typeof AuthenticatedQuestsQuestIdRoute
+ '/_authenticated/admin/': typeof AuthenticatedAdminIndexRoute
+ '/_authenticated/settings/': typeof AuthenticatedSettingsIndexRoute
+ '/_authenticated/admin/forms/$formId': typeof AuthenticatedAdminFormsFormIdRoute
+ '/_authenticated/admin/quests/$questId': typeof AuthenticatedAdminQuestsQuestIdRoute
+ '/_authenticated/admin/forms/': typeof AuthenticatedAdminFormsIndexRoute
+ '/_authenticated/admin/quests/': typeof AuthenticatedAdminQuestsIndexRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
- | '/'
+ | ''
| '/admin'
| '/quests'
+ | '/login'
+ | '/'
| '/quests/$questId'
| '/admin/'
| '/settings'
@@ -239,8 +329,10 @@ export interface FileRouteTypes {
| '/admin/quests'
fileRoutesByTo: FileRoutesByTo
to:
- | '/'
+ | ''
| '/quests'
+ | '/login'
+ | '/'
| '/quests/$questId'
| '/admin'
| '/settings'
@@ -250,31 +342,30 @@ export interface FileRouteTypes {
| '/admin/quests'
id:
| '__root__'
- | '/'
- | '/admin'
- | '/quests'
- | '/quests/$questId'
- | '/admin/'
- | '/settings/'
- | '/admin/forms/$formId'
- | '/admin/quests/$questId'
- | '/admin/forms/'
- | '/admin/quests/'
+ | '/_authenticated'
+ | '/_unauthenticated'
+ | '/_authenticated/admin'
+ | '/_authenticated/quests'
+ | '/_unauthenticated/login'
+ | '/_authenticated/'
+ | '/_authenticated/quests/$questId'
+ | '/_authenticated/admin/'
+ | '/_authenticated/settings/'
+ | '/_authenticated/admin/forms/$formId'
+ | '/_authenticated/admin/quests/$questId'
+ | '/_authenticated/admin/forms/'
+ | '/_authenticated/admin/quests/'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
- IndexRoute: typeof IndexRoute
- AdminRouteRoute: typeof AdminRouteRouteWithChildren
- QuestsRouteRoute: typeof QuestsRouteRouteWithChildren
- SettingsIndexRoute: typeof SettingsIndexRoute
+ AuthenticatedRoute: typeof AuthenticatedRouteWithChildren
+ UnauthenticatedRoute: typeof UnauthenticatedRouteWithChildren
}
const rootRouteChildren: RootRouteChildren = {
- IndexRoute: IndexRoute,
- AdminRouteRoute: AdminRouteRouteWithChildren,
- QuestsRouteRoute: QuestsRouteRouteWithChildren,
- SettingsIndexRoute: SettingsIndexRoute,
+ AuthenticatedRoute: AuthenticatedRouteWithChildren,
+ UnauthenticatedRoute: UnauthenticatedRouteWithChildren,
}
export const routeTree = rootRoute
@@ -289,57 +380,78 @@ export const routeTree = rootRoute
"__root__": {
"filePath": "__root.tsx",
"children": [
- "/",
- "/admin",
- "/quests",
- "/settings/"
+ "/_authenticated",
+ "/_unauthenticated"
]
},
- "/": {
- "filePath": "index.tsx"
+ "/_authenticated": {
+ "filePath": "_authenticated.tsx",
+ "children": [
+ "/_authenticated/admin",
+ "/_authenticated/quests",
+ "/_authenticated/",
+ "/_authenticated/settings/"
+ ]
+ },
+ "/_unauthenticated": {
+ "filePath": "_unauthenticated.tsx",
+ "children": [
+ "/_unauthenticated/login"
+ ]
},
- "/admin": {
- "filePath": "admin/route.tsx",
+ "/_authenticated/admin": {
+ "filePath": "_authenticated/admin/route.tsx",
+ "parent": "/_authenticated",
"children": [
- "/admin/",
- "/admin/forms/$formId",
- "/admin/quests/$questId",
- "/admin/forms/",
- "/admin/quests/"
+ "/_authenticated/admin/",
+ "/_authenticated/admin/forms/$formId",
+ "/_authenticated/admin/quests/$questId",
+ "/_authenticated/admin/forms/",
+ "/_authenticated/admin/quests/"
]
},
- "/quests": {
- "filePath": "quests/route.tsx",
+ "/_authenticated/quests": {
+ "filePath": "_authenticated/quests/route.tsx",
+ "parent": "/_authenticated",
"children": [
- "/quests/$questId"
+ "/_authenticated/quests/$questId"
]
},
- "/quests/$questId": {
- "filePath": "quests/$questId.tsx",
- "parent": "/quests"
+ "/_unauthenticated/login": {
+ "filePath": "_unauthenticated/login.tsx",
+ "parent": "/_unauthenticated"
+ },
+ "/_authenticated/": {
+ "filePath": "_authenticated/index.tsx",
+ "parent": "/_authenticated"
+ },
+ "/_authenticated/quests/$questId": {
+ "filePath": "_authenticated/quests/$questId.tsx",
+ "parent": "/_authenticated/quests"
},
- "/admin/": {
- "filePath": "admin/index.tsx",
- "parent": "/admin"
+ "/_authenticated/admin/": {
+ "filePath": "_authenticated/admin/index.tsx",
+ "parent": "/_authenticated/admin"
},
- "/settings/": {
- "filePath": "settings/index.tsx"
+ "/_authenticated/settings/": {
+ "filePath": "_authenticated/settings/index.tsx",
+ "parent": "/_authenticated"
},
- "/admin/forms/$formId": {
- "filePath": "admin/forms/$formId.tsx",
- "parent": "/admin"
+ "/_authenticated/admin/forms/$formId": {
+ "filePath": "_authenticated/admin/forms/$formId.tsx",
+ "parent": "/_authenticated/admin"
},
- "/admin/quests/$questId": {
- "filePath": "admin/quests/$questId.tsx",
- "parent": "/admin"
+ "/_authenticated/admin/quests/$questId": {
+ "filePath": "_authenticated/admin/quests/$questId.tsx",
+ "parent": "/_authenticated/admin"
},
- "/admin/forms/": {
- "filePath": "admin/forms/index.tsx",
- "parent": "/admin"
+ "/_authenticated/admin/forms/": {
+ "filePath": "_authenticated/admin/forms/index.tsx",
+ "parent": "/_authenticated/admin"
},
- "/admin/quests/": {
- "filePath": "admin/quests/index.tsx",
- "parent": "/admin"
+ "/_authenticated/admin/quests/": {
+ "filePath": "_authenticated/admin/quests/index.tsx",
+ "parent": "/_authenticated/admin"
}
}
}
diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx
index 7f6938b..8dad0b1 100644
--- a/src/routes/__root.tsx
+++ b/src/routes/__root.tsx
@@ -1,13 +1,4 @@
-import {
- AppHeader,
- Button,
- Card,
- Form,
- Link,
- Logo,
- TextField,
-} from "@/components";
-import { useAuthActions } from "@convex-dev/auth/react";
+import type { Role } from "@convex/types";
import {
type NavigateOptions,
Outlet,
@@ -15,10 +6,9 @@ import {
createRootRouteWithContext,
useRouter,
} from "@tanstack/react-router";
-import { type ConvexAuthState, useConvexAuth } from "convex/react";
-import { useState } from "react";
+import type { ConvexAuthState } from "convex/react";
+import React, { Suspense } from "react";
import { RouterProvider } from "react-aria-components";
-import type { Role } from "../../convex/types";
declare module "react-aria-components" {
interface RouterConfig {
@@ -29,7 +19,7 @@ declare module "react-aria-components" {
interface RouterContext {
title: string;
- auth: ConvexAuthState;
+ auth: Promise;
role: Role;
}
@@ -39,105 +29,16 @@ export const Route = createRootRouteWithContext()({
function RootRoute() {
const router = useRouter();
- const { isAuthenticated } = useConvexAuth();
- const isProd = process.env.NODE_ENV === "production";
-
- const SignInWithMagicLink = ({
- handleLinkSent,
- }: {
- handleLinkSent: () => void;
- }) => {
- const { signIn } = useAuthActions();
- const [isSubmitting, setIsSubmitting] = useState(false);
- const [error, setError] = useState(null);
-
- return (
-
- );
- };
-
- const SignIn = () => {
- const [step, setStep] = useState<"signIn" | "linkSent">("signIn");
-
- return (
-
- {step === "signIn" ? (
- setStep("linkSent")} />
- ) : (
-
-
Check your email.
-
A sign-in link has been sent to your email address.
-
-
- )}
-
- );
- };
-
- const ClosedSignups = () => (
-
-
- Namesake is in active development and currently closed to signups. For
- name change support, join us on{" "}
- Discord.
-
-
- );
-
- type AppProps = {
- isAuthenticated: boolean;
- isClosed: boolean;
- };
-
- const App = ({ isAuthenticated, isClosed }: AppProps) => {
- if (isClosed || !isAuthenticated) {
- return (
-
-
- {isClosed ?
:
}
-
- Namesake
- Support
- System Status
-
-
- );
- }
- return (
-
-
-
-
- );
- };
+ const TanStackRouterDevtools =
+ process.env.NODE_ENV === "production"
+ ? () => null // Render nothing in production
+ : React.lazy(() =>
+ // Lazy load in development
+ import("@tanstack/router-devtools").then((res) => ({
+ default: res.TanStackRouterDevtools,
+ })),
+ );
return (
// TODO: Improve this API
@@ -152,7 +53,10 @@ function RootRoute() {
typeof path === "string" ? path : router.buildLocation(path).href
}
>
-
+
+
+
+
);
}
diff --git a/src/routes/_authenticated.tsx b/src/routes/_authenticated.tsx
new file mode 100644
index 0000000..b2ed590
--- /dev/null
+++ b/src/routes/_authenticated.tsx
@@ -0,0 +1,19 @@
+import { AppHeader } from "@/components";
+import { Outlet, createFileRoute, redirect } from "@tanstack/react-router";
+
+export const Route = createFileRoute("/_authenticated")({
+ beforeLoad: async ({ context }) => {
+ const auth = await context.auth;
+ if (!auth.isAuthenticated) throw redirect({ to: "/login" });
+ },
+ component: AuthenticatedRoute,
+});
+
+function AuthenticatedRoute() {
+ return (
+
+
+
+
+ );
+}
diff --git a/src/routes/admin/forms/$formId.tsx b/src/routes/_authenticated/admin/forms/$formId.tsx
similarity index 85%
rename from src/routes/admin/forms/$formId.tsx
rename to src/routes/_authenticated/admin/forms/$formId.tsx
index 40c3cb7..fbb2296 100644
--- a/src/routes/admin/forms/$formId.tsx
+++ b/src/routes/_authenticated/admin/forms/$formId.tsx
@@ -1,10 +1,10 @@
import { Badge, PageHeader } from "@/components";
+import { api } from "@convex/_generated/api";
+import type { Id } from "@convex/_generated/dataModel";
import { createFileRoute } from "@tanstack/react-router";
import { useQuery } from "convex/react";
-import { api } from "../../../../convex/_generated/api";
-import type { Id } from "../../../../convex/_generated/dataModel";
-export const Route = createFileRoute("/admin/forms/$formId")({
+export const Route = createFileRoute("/_authenticated/admin/forms/$formId")({
component: AdminFormDetailRoute,
});
diff --git a/src/routes/admin/forms/index.tsx b/src/routes/_authenticated/admin/forms/index.tsx
similarity index 96%
rename from src/routes/admin/forms/index.tsx
rename to src/routes/_authenticated/admin/forms/index.tsx
index b6b5b26..99772b5 100644
--- a/src/routes/admin/forms/index.tsx
+++ b/src/routes/_authenticated/admin/forms/index.tsx
@@ -19,15 +19,15 @@ import {
TableRow,
TextField,
} from "@/components";
+import { api } from "@convex/_generated/api";
+import type { DataModel } from "@convex/_generated/dataModel";
+import { JURISDICTIONS } from "@convex/constants";
import { RiAddLine, RiFileTextLine, RiMoreFill } from "@remixicon/react";
import { createFileRoute } from "@tanstack/react-router";
import { useMutation, useQuery } from "convex/react";
import { useState } from "react";
-import { api } from "../../../../convex/_generated/api";
-import type { DataModel } from "../../../../convex/_generated/dataModel";
-import { JURISDICTIONS } from "../../../../convex/constants";
-export const Route = createFileRoute("/admin/forms/")({
+export const Route = createFileRoute("/_authenticated/admin/forms/")({
component: FormsRoute,
});
diff --git a/src/routes/admin/index.tsx b/src/routes/_authenticated/admin/index.tsx
similarity index 70%
rename from src/routes/admin/index.tsx
rename to src/routes/_authenticated/admin/index.tsx
index 914904a..ac8afa6 100644
--- a/src/routes/admin/index.tsx
+++ b/src/routes/_authenticated/admin/index.tsx
@@ -1,6 +1,6 @@
import { createFileRoute, redirect } from "@tanstack/react-router";
-export const Route = createFileRoute("/admin/")({
+export const Route = createFileRoute("/_authenticated/admin/")({
beforeLoad: () => {
throw redirect({
to: "/admin/quests",
diff --git a/src/routes/admin/quests/$questId.tsx b/src/routes/_authenticated/admin/quests/$questId.tsx
similarity index 93%
rename from src/routes/admin/quests/$questId.tsx
rename to src/routes/_authenticated/admin/quests/$questId.tsx
index e328528..d820fe3 100644
--- a/src/routes/admin/quests/$questId.tsx
+++ b/src/routes/_authenticated/admin/quests/$questId.tsx
@@ -7,14 +7,14 @@ import {
RichTextEditor,
TextField,
} from "@/components";
+import { api } from "@convex/_generated/api";
+import type { Id } from "@convex/_generated/dataModel";
import { createFileRoute } from "@tanstack/react-router";
import { useMutation, useQuery } from "convex/react";
import { useState } from "react";
import Markdown from "react-markdown";
-import { api } from "../../../../convex/_generated/api";
-import type { Id } from "../../../../convex/_generated/dataModel";
-export const Route = createFileRoute("/admin/quests/$questId")({
+export const Route = createFileRoute("/_authenticated/admin/quests/$questId")({
component: AdminQuestDetailRoute,
});
diff --git a/src/routes/admin/quests/index.tsx b/src/routes/_authenticated/admin/quests/index.tsx
similarity index 94%
rename from src/routes/admin/quests/index.tsx
rename to src/routes/_authenticated/admin/quests/index.tsx
index af7c72a..414f921 100644
--- a/src/routes/admin/quests/index.tsx
+++ b/src/routes/_authenticated/admin/quests/index.tsx
@@ -18,15 +18,15 @@ import {
TableRow,
TextField,
} from "@/components";
+import { api } from "@convex/_generated/api";
+import type { DataModel } from "@convex/_generated/dataModel";
+import { JURISDICTIONS } from "@convex/constants";
import { RiAddLine, RiMoreFill, RiSignpostLine } from "@remixicon/react";
import { createFileRoute } from "@tanstack/react-router";
import { useMutation, useQuery } from "convex/react";
import { useState } from "react";
-import { api } from "../../../../convex/_generated/api";
-import type { DataModel } from "../../../../convex/_generated/dataModel";
-import { JURISDICTIONS } from "../../../../convex/constants";
-export const Route = createFileRoute("/admin/quests/")({
+export const Route = createFileRoute("/_authenticated/admin/quests/")({
component: QuestsRoute,
});
@@ -95,7 +95,9 @@ const NewQuestModal = ({
const QuestTableRow = ({
quest,
-}: { quest: DataModel["quests"]["document"] }) => {
+}: {
+ quest: DataModel["quests"]["document"];
+}) => {
const questCount = useQuery(api.usersQuests.getQuestCount, {
questId: quest._id,
});
diff --git a/src/routes/admin/route.tsx b/src/routes/_authenticated/admin/route.tsx
similarity index 94%
rename from src/routes/admin/route.tsx
rename to src/routes/_authenticated/admin/route.tsx
index 0d36784..8753f8e 100644
--- a/src/routes/admin/route.tsx
+++ b/src/routes/_authenticated/admin/route.tsx
@@ -7,7 +7,7 @@ import {
} from "@remixicon/react";
import { Outlet, createFileRoute, redirect } from "@tanstack/react-router";
-export const Route = createFileRoute("/admin")({
+export const Route = createFileRoute("/_authenticated/admin")({
beforeLoad: ({ context }) => {
const isAdmin = context.role === "admin";
diff --git a/src/routes/_authenticated/index.tsx b/src/routes/_authenticated/index.tsx
new file mode 100644
index 0000000..d30f68f
--- /dev/null
+++ b/src/routes/_authenticated/index.tsx
@@ -0,0 +1,7 @@
+import { createFileRoute, redirect } from "@tanstack/react-router";
+
+export const Route = createFileRoute("/_authenticated/")({
+ beforeLoad: () => {
+ throw redirect({ to: "/quests" });
+ },
+});
diff --git a/src/routes/quests/$questId.tsx b/src/routes/_authenticated/quests/$questId.tsx
similarity index 93%
rename from src/routes/quests/$questId.tsx
rename to src/routes/_authenticated/quests/$questId.tsx
index fdcc943..492663a 100644
--- a/src/routes/quests/$questId.tsx
+++ b/src/routes/_authenticated/quests/$questId.tsx
@@ -6,14 +6,14 @@ import {
MenuTrigger,
PageHeader,
} from "@/components";
+import { api } from "@convex/_generated/api";
+import type { Id } from "@convex/_generated/dataModel";
import { RiMoreLine } from "@remixicon/react";
import { createFileRoute } from "@tanstack/react-router";
import { useMutation, useQuery } from "convex/react";
import Markdown from "react-markdown";
-import { api } from "../../../convex/_generated/api";
-import type { Id } from "../../../convex/_generated/dataModel";
-export const Route = createFileRoute("/quests/$questId")({
+export const Route = createFileRoute("/_authenticated/quests/$questId")({
component: QuestDetailRoute,
});
diff --git a/src/routes/quests/route.tsx b/src/routes/_authenticated/quests/route.tsx
similarity index 96%
rename from src/routes/quests/route.tsx
rename to src/routes/_authenticated/quests/route.tsx
index 8ad432b..c8326b6 100644
--- a/src/routes/quests/route.tsx
+++ b/src/routes/_authenticated/quests/route.tsx
@@ -8,6 +8,8 @@ import {
GridListItem,
Modal,
} from "@/components";
+import { api } from "@convex/_generated/api";
+import type { Id } from "@convex/_generated/dataModel";
import { RiAddLine, RiSignpostLine } from "@remixicon/react";
import { Outlet, createFileRoute } from "@tanstack/react-router";
import {
@@ -18,10 +20,8 @@ import {
} from "convex/react";
import { useState } from "react";
import type { Selection } from "react-aria-components";
-import { api } from "../../../convex/_generated/api";
-import type { Id } from "../../../convex/_generated/dataModel";
-export const Route = createFileRoute("/quests")({
+export const Route = createFileRoute("/_authenticated/quests")({
component: IndexRoute,
});
diff --git a/src/routes/settings/index.tsx b/src/routes/_authenticated/settings/index.tsx
similarity index 96%
rename from src/routes/settings/index.tsx
rename to src/routes/_authenticated/settings/index.tsx
index eb5477d..85ea9a9 100644
--- a/src/routes/settings/index.tsx
+++ b/src/routes/_authenticated/settings/index.tsx
@@ -10,16 +10,16 @@ import {
TextField,
} from "@/components";
import { useAuthActions } from "@convex-dev/auth/react";
+import { api } from "@convex/_generated/api";
+import type { Theme } from "@convex/types";
import { RiCheckLine, RiLoader4Line } from "@remixicon/react";
import { createFileRoute } from "@tanstack/react-router";
import { useMutation, useQuery } from "convex/react";
import { useTheme } from "next-themes";
import { useEffect, useState } from "react";
import { useDebouncedCallback } from "use-debounce";
-import { api } from "../../../convex/_generated/api";
-import type { Theme } from "../../../convex/types";
-export const Route = createFileRoute("/settings/")({
+export const Route = createFileRoute("/_authenticated/settings/")({
component: SettingsRoute,
});
diff --git a/src/routes/_unauthenticated.tsx b/src/routes/_unauthenticated.tsx
new file mode 100644
index 0000000..9b568d8
--- /dev/null
+++ b/src/routes/_unauthenticated.tsx
@@ -0,0 +1,14 @@
+import { Outlet, createFileRoute, redirect } from "@tanstack/react-router";
+
+export const Route = createFileRoute("/_unauthenticated")({
+ beforeLoad: async ({ context }) => {
+ const auth = await context.auth;
+ // If already authenticated, redirect to dashboard
+ if (auth.isAuthenticated) throw redirect({ to: "/" });
+ },
+ component: UnauthenticatedRoute,
+});
+
+function UnauthenticatedRoute() {
+ return ;
+}
diff --git a/src/routes/_unauthenticated/login.tsx b/src/routes/_unauthenticated/login.tsx
new file mode 100644
index 0000000..ee15a70
--- /dev/null
+++ b/src/routes/_unauthenticated/login.tsx
@@ -0,0 +1,88 @@
+import { Button, Card, Form, Link, Logo, TextField } from "@/components";
+import { useAuthActions } from "@convex-dev/auth/react";
+import { createFileRoute } from "@tanstack/react-router";
+import { useState } from "react";
+
+export const Route = createFileRoute("/_unauthenticated/login")({
+ component: LoginRoute,
+});
+
+const SignInWithMagicLink = ({
+ handleLinkSent,
+}: {
+ handleLinkSent: () => void;
+}) => {
+ const { signIn } = useAuthActions();
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [error, setError] = useState(null);
+
+ return (
+
+ );
+};
+
+const SignIn = () => {
+ const [step, setStep] = useState<"signIn" | "linkSent">("signIn");
+
+ return (
+
+ {step === "signIn" ? (
+ setStep("linkSent")} />
+ ) : (
+
+
Check your email.
+
A sign-in link has been sent to your email address.
+
+
+ )}
+
+ );
+};
+
+const ClosedSignups = () => (
+
+
+ Namesake is in active development and currently closed to signups. For
+ name change support, join us on{" "}
+ Discord.
+
+
+);
+
+function LoginRoute() {
+ const isClosed = process.env.NODE_ENV === "production";
+
+ return (
+
+
+ {isClosed ?
:
}
+
+ Namesake
+ Support
+ System Status
+
+
+ );
+}
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
deleted file mode 100644
index 8758562..0000000
--- a/src/routes/index.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import { createFileRoute, redirect } from "@tanstack/react-router";
-
-export const Route = createFileRoute("/")({
- beforeLoad: ({ context }) => {
- if (context.auth.isAuthenticated) throw redirect({ to: "/quests" });
- },
-});
diff --git a/tsconfig.app.json b/tsconfig.app.json
index 4bfd345..b27e830 100644
--- a/tsconfig.app.json
+++ b/tsconfig.app.json
@@ -17,7 +17,8 @@
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": {
- "@/*": ["src/*"]
+ "@/*": ["src/*"],
+ "@convex/*": ["convex/*"]
}
}
}
diff --git a/tsconfig.node.json b/tsconfig.node.json
index a3fd855..065a310 100644
--- a/tsconfig.node.json
+++ b/tsconfig.node.json
@@ -15,7 +15,8 @@
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": {
- "@/*": ["src/*"]
+ "@/*": ["src/*"],
+ "@convex/*": ["convex/*"]
}
},
"include": ["vite.config.ts"]
diff --git a/vite.config.ts b/vite.config.ts
index a295c87..c5327a8 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -20,7 +20,10 @@ export default defineConfig({
},
},
resolve: {
- alias: [{ find: "@", replacement: "/src" }],
+ alias: [
+ { find: "@", replacement: "/src" },
+ { find: "@convex", replacement: "/convex" },
+ ],
},
test: {
environment: "edge-runtime",