diff --git a/template-tanstack-start-clerk/convex/_generated/api.d.ts b/template-tanstack-start-clerk/convex/_generated/api.d.ts index 43da140..075cb4e 100644 --- a/template-tanstack-start-clerk/convex/_generated/api.d.ts +++ b/template-tanstack-start-clerk/convex/_generated/api.d.ts @@ -14,7 +14,6 @@ import type { FunctionReference, } from "convex/server"; import type * as posts from "../posts.js"; -import type * as tasks from "../tasks.js"; import type * as user from "../user.js"; /** @@ -27,7 +26,6 @@ import type * as user from "../user.js"; */ declare const fullApi: ApiFromModules<{ posts: typeof posts; - tasks: typeof tasks; user: typeof user; }>; export declare const api: FilterApi< diff --git a/template-tanstack-start-clerk/convex/posts.ts b/template-tanstack-start-clerk/convex/posts.ts index 087d1f0..3c2efc5 100644 --- a/template-tanstack-start-clerk/convex/posts.ts +++ b/template-tanstack-start-clerk/convex/posts.ts @@ -1,21 +1,8 @@ import { action, internalMutation, query } from './_generated/server' import { api, internal } from './_generated/api.js' -import { v } from 'convex/values' import type { Doc } from './_generated/dataModel' import type { WithoutSystemFields } from 'convex/server' -export const get = query({ - args: { - postId: v.string(), - }, - handler: async (ctx, { postId }) => { - return await ctx.db - .query('posts') - .withIndex('id', (q) => q.eq('id', postId)) - .unique() - }, -}) - export const list = query(async (ctx) => { return await ctx.db.query('posts').collect() }) @@ -25,10 +12,6 @@ export const insert = internalMutation( ctx.db.insert('posts', post), ) -export const count = query( - async (ctx) => (await ctx.db.query('posts').collect()).length, -) - export const populate = action(async (ctx) => { const existing = await ctx.runQuery(api.posts.list) if (existing.length) { diff --git a/template-tanstack-start-clerk/convex/schema.ts b/template-tanstack-start-clerk/convex/schema.ts index 6726fbc..5f7cfea 100644 --- a/template-tanstack-start-clerk/convex/schema.ts +++ b/template-tanstack-start-clerk/convex/schema.ts @@ -7,9 +7,4 @@ export default defineSchema({ title: v.string(), body: v.string(), }).index('id', ['id']), - - tasks: defineTable({ - text: v.string(), - isCompleted: v.boolean(), - }), }) diff --git a/template-tanstack-start-clerk/convex/tasks.ts b/template-tanstack-start-clerk/convex/tasks.ts deleted file mode 100644 index 50172f9..0000000 --- a/template-tanstack-start-clerk/convex/tasks.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { query } from './_generated/server' - -export const get = query({ - args: {}, - handler: async (ctx) => { - return await ctx.db.query('tasks').collect() - }, -}) diff --git a/template-tanstack-start-clerk/convex/user.ts b/template-tanstack-start-clerk/convex/user.ts index b5505fd..32cec94 100644 --- a/template-tanstack-start-clerk/convex/user.ts +++ b/template-tanstack-start-clerk/convex/user.ts @@ -1,10 +1,8 @@ import { query } from './_generated/server' -export const profile = query((ctx) => ctx.auth.getUserIdentity()) - -export const name = query( - async (ctx) => (await ctx.auth.getUserIdentity())?.name, -) -export const email = query( - async (ctx) => (await ctx.auth.getUserIdentity())?.email, -) +export const profile = query({ + args: {}, + handler: async (ctx) => { + return ctx.auth.getUserIdentity() + }, +}) diff --git a/template-tanstack-start-clerk/package.json b/template-tanstack-start-clerk/package.json index ec3537b..b03dadc 100644 --- a/template-tanstack-start-clerk/package.json +++ b/template-tanstack-start-clerk/package.json @@ -9,8 +9,7 @@ "dev:convex": "npx convex dev", "build": "vite build && tsc --noEmit", "start": "node .output/server/index.mjs", - "format": "prettier --write .", - "seed": "npx convex import --table tasks sampleData.jsonl" + "format": "prettier --write ." }, "dependencies": { "@clerk/tanstack-react-start": "0.24.0", diff --git a/template-tanstack-start-clerk/sampleData.jsonl b/template-tanstack-start-clerk/sampleData.jsonl deleted file mode 100644 index a15cbf0..0000000 --- a/template-tanstack-start-clerk/sampleData.jsonl +++ /dev/null @@ -1,3 +0,0 @@ -{"text": "Buy groceries", "isCompleted": true} -{"text": "Go for a swim", "isCompleted": true} -{"text": "Integrate Convex", "isCompleted": false} diff --git a/template-tanstack-start-clerk/src/routeTree.gen.ts b/template-tanstack-start-clerk/src/routeTree.gen.ts index 45f06da..70cd08a 100644 --- a/template-tanstack-start-clerk/src/routeTree.gen.ts +++ b/template-tanstack-start-clerk/src/routeTree.gen.ts @@ -9,23 +9,14 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { Route as rootRouteImport } from './routes/__root' -import { Route as TasksRouteImport } from './routes/tasks' -import { Route as ConvexpostsRouteImport } from './routes/convexposts' +import { Route as PostsRouteImport } from './routes/posts' import { Route as AuthedRouteImport } from './routes/_authed' import { Route as IndexRouteImport } from './routes/index' import { Route as AuthedUserRouteImport } from './routes/_authed/user' -import { Route as AuthedPostsRouteImport } from './routes/_authed/posts' -import { Route as AuthedPostsIndexRouteImport } from './routes/_authed/posts.index' -import { Route as AuthedPostsPostIdRouteImport } from './routes/_authed/posts.$postId' -const TasksRoute = TasksRouteImport.update({ - id: '/tasks', - path: '/tasks', - getParentRoute: () => rootRouteImport, -} as any) -const ConvexpostsRoute = ConvexpostsRouteImport.update({ - id: '/convexposts', - path: '/convexposts', +const PostsRoute = PostsRouteImport.update({ + id: '/posts', + path: '/posts', getParentRoute: () => rootRouteImport, } as any) const AuthedRoute = AuthedRouteImport.update({ @@ -42,95 +33,45 @@ const AuthedUserRoute = AuthedUserRouteImport.update({ path: '/user', getParentRoute: () => AuthedRoute, } as any) -const AuthedPostsRoute = AuthedPostsRouteImport.update({ - id: '/posts', - path: '/posts', - getParentRoute: () => AuthedRoute, -} as any) -const AuthedPostsIndexRoute = AuthedPostsIndexRouteImport.update({ - id: '/', - path: '/', - getParentRoute: () => AuthedPostsRoute, -} as any) -const AuthedPostsPostIdRoute = AuthedPostsPostIdRouteImport.update({ - id: '/$postId', - path: '/$postId', - getParentRoute: () => AuthedPostsRoute, -} as any) export interface FileRoutesByFullPath { '/': typeof IndexRoute - '/convexposts': typeof ConvexpostsRoute - '/tasks': typeof TasksRoute - '/posts': typeof AuthedPostsRouteWithChildren + '/posts': typeof PostsRoute '/user': typeof AuthedUserRoute - '/posts/$postId': typeof AuthedPostsPostIdRoute - '/posts/': typeof AuthedPostsIndexRoute } export interface FileRoutesByTo { '/': typeof IndexRoute - '/convexposts': typeof ConvexpostsRoute - '/tasks': typeof TasksRoute + '/posts': typeof PostsRoute '/user': typeof AuthedUserRoute - '/posts/$postId': typeof AuthedPostsPostIdRoute - '/posts': typeof AuthedPostsIndexRoute } export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute '/_authed': typeof AuthedRouteWithChildren - '/convexposts': typeof ConvexpostsRoute - '/tasks': typeof TasksRoute - '/_authed/posts': typeof AuthedPostsRouteWithChildren + '/posts': typeof PostsRoute '/_authed/user': typeof AuthedUserRoute - '/_authed/posts/$postId': typeof AuthedPostsPostIdRoute - '/_authed/posts/': typeof AuthedPostsIndexRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: - | '/' - | '/convexposts' - | '/tasks' - | '/posts' - | '/user' - | '/posts/$postId' - | '/posts/' + fullPaths: '/' | '/posts' | '/user' fileRoutesByTo: FileRoutesByTo - to: '/' | '/convexposts' | '/tasks' | '/user' | '/posts/$postId' | '/posts' - id: - | '__root__' - | '/' - | '/_authed' - | '/convexposts' - | '/tasks' - | '/_authed/posts' - | '/_authed/user' - | '/_authed/posts/$postId' - | '/_authed/posts/' + to: '/' | '/posts' | '/user' + id: '__root__' | '/' | '/_authed' | '/posts' | '/_authed/user' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute AuthedRoute: typeof AuthedRouteWithChildren - ConvexpostsRoute: typeof ConvexpostsRoute - TasksRoute: typeof TasksRoute + PostsRoute: typeof PostsRoute } declare module '@tanstack/react-router' { interface FileRoutesByPath { - '/tasks': { - id: '/tasks' - path: '/tasks' - fullPath: '/tasks' - preLoaderRoute: typeof TasksRouteImport - parentRoute: typeof rootRouteImport - } - '/convexposts': { - id: '/convexposts' - path: '/convexposts' - fullPath: '/convexposts' - preLoaderRoute: typeof ConvexpostsRouteImport + '/posts': { + id: '/posts' + path: '/posts' + fullPath: '/posts' + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRouteImport } '/_authed': { @@ -154,51 +95,14 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthedUserRouteImport parentRoute: typeof AuthedRoute } - '/_authed/posts': { - id: '/_authed/posts' - path: '/posts' - fullPath: '/posts' - preLoaderRoute: typeof AuthedPostsRouteImport - parentRoute: typeof AuthedRoute - } - '/_authed/posts/': { - id: '/_authed/posts/' - path: '/' - fullPath: '/posts/' - preLoaderRoute: typeof AuthedPostsIndexRouteImport - parentRoute: typeof AuthedPostsRoute - } - '/_authed/posts/$postId': { - id: '/_authed/posts/$postId' - path: '/$postId' - fullPath: '/posts/$postId' - preLoaderRoute: typeof AuthedPostsPostIdRouteImport - parentRoute: typeof AuthedPostsRoute - } } } -interface AuthedPostsRouteChildren { - AuthedPostsPostIdRoute: typeof AuthedPostsPostIdRoute - AuthedPostsIndexRoute: typeof AuthedPostsIndexRoute -} - -const AuthedPostsRouteChildren: AuthedPostsRouteChildren = { - AuthedPostsPostIdRoute: AuthedPostsPostIdRoute, - AuthedPostsIndexRoute: AuthedPostsIndexRoute, -} - -const AuthedPostsRouteWithChildren = AuthedPostsRoute._addFileChildren( - AuthedPostsRouteChildren, -) - interface AuthedRouteChildren { - AuthedPostsRoute: typeof AuthedPostsRouteWithChildren AuthedUserRoute: typeof AuthedUserRoute } const AuthedRouteChildren: AuthedRouteChildren = { - AuthedPostsRoute: AuthedPostsRouteWithChildren, AuthedUserRoute: AuthedUserRoute, } @@ -208,8 +112,7 @@ const AuthedRouteWithChildren = const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, AuthedRoute: AuthedRouteWithChildren, - ConvexpostsRoute: ConvexpostsRoute, - TasksRoute: TasksRoute, + PostsRoute: PostsRoute, } export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) diff --git a/template-tanstack-start-clerk/src/routes/__root.tsx b/template-tanstack-start-clerk/src/routes/__root.tsx index 8186a04..24298cf 100644 --- a/template-tanstack-start-clerk/src/routes/__root.tsx +++ b/template-tanstack-start-clerk/src/routes/__root.tsx @@ -126,14 +126,6 @@ function RootDocument({ children }: { children: React.ReactNode }) { activeOptions={{ exact: true }} > Home - {' '} - - Tasks Posts - - Convex Posts - fetchPost({ data: postId }), - errorComponent: PostErrorComponent, - component: PostComponent, -}) - -function PostErrorComponent({ error }: ErrorComponentProps) { - return -} - -function PostComponent() { - const post = Route.useLoaderData() - - return ( -
-

{post.title}

-
{post.body}
-
- ) -} diff --git a/template-tanstack-start-clerk/src/routes/_authed/posts.index.tsx b/template-tanstack-start-clerk/src/routes/_authed/posts.index.tsx deleted file mode 100644 index ea9e667..0000000 --- a/template-tanstack-start-clerk/src/routes/_authed/posts.index.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/_authed/posts/')({ - component: PostsIndexComponent, -}) - -function PostsIndexComponent() { - return
Select a post.
-} diff --git a/template-tanstack-start-clerk/src/routes/_authed/posts.tsx b/template-tanstack-start-clerk/src/routes/_authed/posts.tsx deleted file mode 100644 index 1ada9a1..0000000 --- a/template-tanstack-start-clerk/src/routes/_authed/posts.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' -import { fetchPosts } from '~/utils/posts' - -export const Route = createFileRoute('/_authed/posts')({ - loader: () => fetchPosts(), - component: PostsComponent, -}) - -function PostsComponent() { - const posts = Route.useLoaderData() - - return ( -
- -
- -
- ) -} diff --git a/template-tanstack-start-clerk/src/routes/_authed/user.tsx b/template-tanstack-start-clerk/src/routes/_authed/user.tsx index 0399209..8a2c281 100644 --- a/template-tanstack-start-clerk/src/routes/_authed/user.tsx +++ b/template-tanstack-start-clerk/src/routes/_authed/user.tsx @@ -1,27 +1,25 @@ import { createFileRoute } from '@tanstack/react-router' import { api } from 'convex/_generated/api' import { convexQuery } from '@convex-dev/react-query' -import { useQuery, useSuspenseQuery } from '@tanstack/react-query' +import { useSuspenseQuery } from '@tanstack/react-query' export const Route = createFileRoute('/_authed/user')({ component: RouteComponent, + loader: async ({ context }) => { + await context.queryClient.ensureQueryData(convexQuery(api.user.profile, {})) + }, }) function RouteComponent() { - // Not server-rendered and null until authed - const { data: profile } = useQuery(convexQuery(api.user.profile, {})) - // Server-rendered - const { data: email } = useSuspenseQuery(convexQuery(api.user.email, {})) + const { data: profile } = useSuspenseQuery(convexQuery(api.user.profile, {})) return (
-
server-rendered email: {email}
-
- { - 'client-rendered and requires auth (could be momentarily null if not protected by ): ' - } - {profile?.email} - {profile?.name} -
+ {profile === null ? ( +

You are not logged in.

+ ) : ( +

Welcome! Your email address is {profile.email}.

+ )}
) } diff --git a/template-tanstack-start-clerk/src/routes/convexposts.tsx b/template-tanstack-start-clerk/src/routes/convexposts.tsx deleted file mode 100644 index a480b0a..0000000 --- a/template-tanstack-start-clerk/src/routes/convexposts.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { api } from 'convex/_generated/api' -import { convexQuery } from '@convex-dev/react-query' -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' -import { useAction } from 'convex/react' -import { useQuery } from '@tanstack/react-query' - -export const Route = createFileRoute('/convexposts')({ - loader: async ({ context }) => { - await context.queryClient.ensureQueryData({ - ...convexQuery(api.posts.list, {}), - gcTime: 10000, - }) - }, - component: PostsComponent, -}) - -function PostsComponent() { - const { - data: posts, - isPending, - error, - } = useQuery({ - ...convexQuery(api.posts.list, {}), - }) - - // Not server-rendered - const { data: count } = useQuery(convexQuery(api.posts.count, {})) - - if (isPending) return <>loading.. - if (error) return <>error.. - - const populatePosts = useAction(api.posts.populate) - - return ( -
-
client-rendered but no auth required (pops in): {count}
- - {(!count || count === 0) && ( - - )} - - -
- -
- ) -} diff --git a/template-tanstack-start-clerk/src/routes/posts.tsx b/template-tanstack-start-clerk/src/routes/posts.tsx new file mode 100644 index 0000000..6782055 --- /dev/null +++ b/template-tanstack-start-clerk/src/routes/posts.tsx @@ -0,0 +1,46 @@ +import { api } from 'convex/_generated/api' +import { convexQuery } from '@convex-dev/react-query' +import { Outlet, createFileRoute } from '@tanstack/react-router' +import { useAction } from 'convex/react' +import { useSuspenseQuery } from '@tanstack/react-query' + +export const Route = createFileRoute('/posts')({ + loader: async ({ context }) => { + await context.queryClient.ensureQueryData({ + ...convexQuery(api.posts.list, {}), + gcTime: 10000, + }) + }, + component: PostsComponent, +}) + +function PostsComponent() { + const { data: posts } = useSuspenseQuery(convexQuery(api.posts.list, {})) + + const populatePosts = useAction(api.posts.populate) + + return ( +
+ {posts.length === 0 && ( + + )} + + +
+ +
+ ) +} diff --git a/template-tanstack-start-clerk/src/routes/tasks.tsx b/template-tanstack-start-clerk/src/routes/tasks.tsx deleted file mode 100644 index 014a423..0000000 --- a/template-tanstack-start-clerk/src/routes/tasks.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { api } from '../../convex/_generated/api' -import { convexQuery } from '@convex-dev/react-query' -import { createFileRoute } from '@tanstack/react-router' -import { useSuspenseQuery } from '@tanstack/react-query' - -export const Route = createFileRoute('/tasks')({ - component: RouteComponent, -}) - -function RouteComponent() { - const { data } = useSuspenseQuery(convexQuery(api.tasks.get, {})) - - return ( -
-

Tasks from Convex

- {data.map(({ _id, text }) => ( -
{text}
- ))} -
- ) -} diff --git a/template-tanstack-start-clerk/src/utils/posts.ts b/template-tanstack-start-clerk/src/utils/posts.ts deleted file mode 100644 index e0d7133..0000000 --- a/template-tanstack-start-clerk/src/utils/posts.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { notFound } from '@tanstack/react-router' -import { createServerFn } from '@tanstack/react-start' -import axios from 'redaxios' - -export type PostType = { - id: string - title: string - body: string -} - -export const fetchPost = createServerFn({ method: 'GET' }) - .validator((postId: string) => postId) - .handler(async ({ data }) => { - console.info(`Fetching post with id ${data}...`) - const post = await axios - .get(`https://jsonplaceholder.typicode.com/posts/${data}`) - .then((r) => r.data) - .catch((err) => { - console.error(err) - if (err.status === 404) { - throw notFound() - } - throw err - }) - - return post - }) - -export const fetchPosts = createServerFn({ method: 'GET' }).handler( - async () => { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) - }, -)