diff --git a/convex/posts.ts b/convex/posts.ts index e4b6368..174ac24 100644 --- a/convex/posts.ts +++ b/convex/posts.ts @@ -46,6 +46,7 @@ export const getUsersPostById = query({ return await ctx.db .query('posts') .withIndex('by_user_id', q => q.eq('userId', args.userId)) + .filter(q => q.eq(q.field('parentPostId'), undefined)) .order('desc') .paginate(args.paginationOpts); }, diff --git a/src/app/posts/[id]/edit/page.tsx b/src/app/posts/[id]/edit/page.tsx index 899f183..8ffdbb8 100644 --- a/src/app/posts/[id]/edit/page.tsx +++ b/src/app/posts/[id]/edit/page.tsx @@ -1,26 +1,70 @@ -import Editor from '@/components/Editor'; -import { getConvexClient } from '@/lib/convex'; +'use client'; + +import Editor, { SubmitActionParams } from '@/components/Editor'; +import SpinningLoader from '@/components/SpinningLoader'; +import { useRouter } from '@/hooks'; +import { useUser } from '@clerk/nextjs'; +import { useMutation, useQuery } from 'convex/react'; import { api } from '../../../../../convex/_generated/api'; import { Id } from '../../../../../convex/_generated/dataModel'; -export default async function EditPostPage({ - params, -}: { - params: { id: string }; -}) { - const client = await getConvexClient(); - const post = await client.query(api.posts.getPostById, { +export default function EditPostPage({ params }: { params: { id: string } }) { + const user = useUser(); + const post = useQuery(api.posts.getPostById, { id: params.id as Id<'posts'>, }); + const createOrUpdatePost = useMutation(api.posts.createOrUpdatePost); + const router = useRouter(); + + if (user.isSignedIn === false) { + router.push('/login'); + return; + } if (post === 'POST_NOT_FOUND' || post === 'USER_FOR_POST_NOT_FOUND') { // TODO: Return actual not found component return

Not Found

; } + async function submitAction({ + clerkUserId, + parentPostId, + post, + currentDoc, + }: SubmitActionParams) { + const result = await createOrUpdatePost({ + parentPostId: parentPostId, + id: post?._id, + clerkUserId: clerkUserId, + content: currentDoc, + }); + + switch (result) { + case 'USER_NOT_FOUND': + case 'USER_NOT_AUTHORIZED': + case 'CANNOT_POST_ON_BEHALF_OF_ANOTHER_USER': + throw Error('Unable to update post'); + default: + 'use server'; + router.push('/'); + return; + } + } + return ( -
- +
+ {user.isLoaded && post !== undefined ? ( + + ) : ( +
+ + Loading... +
+ )}
); } diff --git a/src/app/posts/[id]/page.tsx b/src/app/posts/[id]/page.tsx index 0da092b..8a56fca 100644 --- a/src/app/posts/[id]/page.tsx +++ b/src/app/posts/[id]/page.tsx @@ -1,10 +1,11 @@ 'use client'; -import Editor from '@/components/Editor'; +import Editor, { SubmitActionParams } from '@/components/Editor'; import Post from '@/components/Post'; import SpinningLoader from '@/components/SpinningLoader'; +import { useRouter } from '@/hooks'; import { useUser } from '@clerk/nextjs'; -import { useQuery } from 'convex/react'; +import { useMutation, useQuery } from 'convex/react'; import Image from 'next/image'; import { api } from '../../../../convex/_generated/api'; import { Id } from '../../../../convex/_generated/dataModel'; @@ -17,9 +18,39 @@ export default function PostPage({ searchParams: { reply?: boolean }; }) { const user = useUser(); + const router = useRouter(); const post = useQuery(api.posts.getPostById, { id: params.id as Id<'posts'>, }); + const createOrUpdatePost = useMutation(api.posts.createOrUpdatePost); + + async function submitAction({ + clerkUserId, + parentPostId, + post, + currentDoc, + }: SubmitActionParams) { + const result = await createOrUpdatePost({ + parentPostId: parentPostId, + id: post?._id, + clerkUserId: clerkUserId, + content: currentDoc, + }); + + switch (result) { + case 'USER_NOT_FOUND': + case 'USER_NOT_AUTHORIZED': + case 'CANNOT_POST_ON_BEHALF_OF_ANOTHER_USER': + throw Error('Unable to create post'); + default: + return; + } + } + + if (user.isSignedIn === false) { + router.push('/login'); + return; + } if (post === 'POST_NOT_FOUND' || post === 'USER_FOR_POST_NOT_FOUND') { // TODO: Return actual not found component @@ -29,11 +60,7 @@ export default function PostPage({ return (
- {post === undefined ? ( -
- Loading post... -
- ) : ( + {post !== undefined && user.isLoaded ? ( <>
- {user.isSignedIn !== true ? null : ( -
- user profile image -
- )} +
+ user profile image +
+
- +
+ ) : ( +
+ Loading post... +
)}
diff --git a/src/app/posts/add/page.tsx b/src/app/posts/add/page.tsx index 41d4eb8..636f799 100644 --- a/src/app/posts/add/page.tsx +++ b/src/app/posts/add/page.tsx @@ -1,9 +1,60 @@ -import Editor from '@/components/Editor'; +'use client'; + +import Editor, { SubmitActionParams } from '@/components/Editor'; +import SpinningLoader from '@/components/SpinningLoader'; +import { useRouter } from '@/hooks'; +import { useUser } from '@clerk/nextjs'; +import { useMutation } from 'convex/react'; +import { api } from '../../../../convex/_generated/api'; export default function AddPost() { + const user = useUser(); + const createOrUpdatePost = useMutation(api.posts.createOrUpdatePost); + const router = useRouter(); + + async function submitAction({ + clerkUserId, + parentPostId, + post, + currentDoc, + }: SubmitActionParams) { + const result = await createOrUpdatePost({ + parentPostId: parentPostId, + id: post?._id, + clerkUserId: clerkUserId, + content: currentDoc, + }); + + switch (result) { + case 'USER_NOT_FOUND': + case 'USER_NOT_AUTHORIZED': + case 'CANNOT_POST_ON_BEHALF_OF_ANOTHER_USER': + throw Error('Unable to create post'); + default: + 'use server'; + router.push('/'); + return; + } + } + + if (user.isSignedIn === false) { + router.push('/login'); + return; + } + return ( -
- +
+ {user.isLoaded ? ( + + ) : ( +
+ + Loading... +
+ )}
); } diff --git a/src/components/Editor.tsx b/src/components/Editor.tsx index 40ed0be..9a3878f 100644 --- a/src/components/Editor.tsx +++ b/src/components/Editor.tsx @@ -2,30 +2,41 @@ import { useCodeMirror, useRouter } from '@/hooks'; import { basicDark } from '@/lib/codemirror'; -import { useUser } from '@clerk/nextjs'; import { indentWithTab } from '@codemirror/commands'; import { markdown, markdownLanguage } from '@codemirror/lang-markdown'; import { languages } from '@codemirror/language-data'; import { Compartment, EditorState, Text } from '@codemirror/state'; import { EditorView, keymap } from '@codemirror/view'; import { basicSetup } from 'codemirror'; -import { useMutation } from 'convex/react'; import { FormEvent, useState } from 'react'; -import { api } from '../../convex/_generated/api'; import { Doc, Id } from '../../convex/_generated/dataModel'; import PostContent from './PostContent'; -export default function Editor({ - parentPostId, - post, -}: { +export type SubmitActionParams = { + clerkUserId: string; parentPostId?: Id<'posts'>; post?: Doc<'posts'>; + currentDoc: string[]; +}; + +export default function Editor({ + clerkUserId, + parentPostId, + post, + submitAction, +}: { + clerkUserId: string; + parentPostId?: Id<'posts'>; + post?: Doc<'posts'>; + submitAction: ({ + clerkUserId, + parentPostId, + post, + currentDoc, + }: SubmitActionParams) => Promise; }) { - const { user, isSignedIn } = useUser(); const editorTheme = new Compartment(); const [currentDoc, setCurrentDoc] = useState(post?.content ?? ['']); - const createOrUpdatePost = useMutation(api.posts.createOrUpdatePost); const router = useRouter(); const [creatingOrUpdating, setCreatingOrUpdating] = useState(false); @@ -42,48 +53,38 @@ export default function Editor({ ]; const [mode, setMode] = useState<'write' | 'preview'>('write'); - const { editorRef } = useCodeMirror({ + const { editorRef, editorView } = useCodeMirror({ doc: currentDoc, extensions, }); async function handleSubmit(e: FormEvent) { e.preventDefault(); + try { - if (isSignedIn !== true) { - router.push('/login'); - return; - } - setCreatingOrUpdating(true); - - const result = await createOrUpdatePost({ - parentPostId: parentPostId, - id: post?._id, - clerkUserId: user.id, - content: currentDoc, + await submitAction({ + clerkUserId, + parentPostId, + post, + currentDoc, }); - - switch (result) { - case 'USER_NOT_FOUND': - case 'USER_NOT_AUTHORIZED': - case 'CANNOT_POST_ON_BEHALF_OF_ANOTHER_USER': - throw Error('Unable to create post'); - default: - router.push('/'); - return; - } } catch (error) { console.log(error); } finally { + console.log('here'); setCreatingOrUpdating(false); + setCurrentDoc(['']); + editorView?.dispatch({ + changes: { from: 0, to: editorView.state.doc.length, insert: '' }, + }); } } return (