diff --git a/src/app/api/anonymous/comment/route.ts b/src/app/api/anonymous/comment/route.ts index 4e3f9df5..f3157dcd 100644 --- a/src/app/api/anonymous/comment/route.ts +++ b/src/app/api/anonymous/comment/route.ts @@ -2,36 +2,39 @@ import { createContract } from "crossbell" import { NextResponse } from "next/server" import { ANONYMOUS_ACCOUNT_PRIVATEKEY } from "~/lib/env.server" -import { NextServerResponse, getQuery } from "~/lib/server-helper" +import { NextServerResponse } from "~/lib/server-helper" const contract = createContract(ANONYMOUS_ACCOUNT_PRIVATEKEY) -// /api/anonymous/comment?target=1-1&content=hello&name=Me -export async function GET(req: Request): Promise { - const { target, content, name } = getQuery(req) +// /api/anonymous/comment +export async function POST(req: Request): Promise { + const { targetCharacterId, targetNoteId, content, name, email } = + await req.json() - if (!target || !content) { - return NextResponse.json({ error: "Missing target or content" }) + if (!targetCharacterId || !targetNoteId || !content || !name || !email) { + return NextResponse.json({ error: "Missing required fields" }) } const res = new NextServerResponse() const { data } = await contract.note.postForNote({ - targetCharacterId: target.split("-")[0], - targetNoteId: target.split("-")[1], + targetCharacterId, + targetNoteId, characterId: 56592, metadataOrUri: { tags: ["comment"], sources: ["xlog"], - content: content, - }, - ...(name && { + content, attributes: [ { - trait_type: "xlog_display_name", + trait_type: "xlog_sender_name", value: name, }, + { + trait_type: "xlog_sender_email", + value: email, + }, ], - }), + }, }) return res.status(200).json({ diff --git a/src/components/common/CommentInput.tsx b/src/components/common/CommentInput.tsx index 1441f5bd..8fbceab6 100644 --- a/src/components/common/CommentInput.tsx +++ b/src/components/common/CommentInput.tsx @@ -1,5 +1,5 @@ import type { CharacterEntity, NoteEntity } from "crossbell" -import { useCallback, useEffect, useRef } from "react" +import { useCallback, useEffect, useRef, useState } from "react" import { useForm } from "react-hook-form" import { EditorView } from "@codemirror/view" @@ -11,7 +11,11 @@ import { Button } from "~/components/ui/Button" import { editorUpload } from "~/editor/Multimedia" import { useUploadFile } from "~/hooks/useUploadFile" import { useTranslation } from "~/lib/i18n/client" -import { useCommentPage, useUpdateComment } from "~/queries/page" +import { + useAnonymousComment, + useCommentPage, + useUpdateComment, +} from "~/queries/page" import { CodeMirrorEditor } from "../ui/CodeMirror" import { Input } from "../ui/Input" @@ -38,6 +42,8 @@ export const CommentInput = ({ const commentPage = useCommentPage() const updateComment = useUpdateComment() const { t } = useTranslation("site") + const anonymousComment = useAnonymousComment() + const [anonymous, setAnonymous] = useState(false) const form = useForm({ defaultValues: { @@ -45,6 +51,16 @@ export const CommentInput = ({ }, }) + const anonymousForm = useForm({ + defaultValues: { + name: "", + email: "", + } as { + name: string + email: string + }, + }) + const inputContent = form.watch("content").trim() const handleSubmit = form.handleSubmit(async (values) => { @@ -61,24 +77,52 @@ export const CommentInput = ({ }) } } else { - commentPage.mutate({ - characterId, - noteId, - content: values.content, - externalUrl: window.location.href, - originalCharacterId, - originalNoteId, - }) + if (anonymous) { + if ( + values.content && + anonymousForm.getValues("name") && + anonymousForm.getValues("email") + ) { + anonymousComment.mutate({ + targetCharacterId: characterId, + targetNoteId: noteId, + content: values.content, + name: anonymousForm.getValues("name"), + email: anonymousForm.getValues("email"), + originalCharacterId, + originalNoteId, + }) + } + } else { + commentPage.mutate({ + characterId, + noteId, + content: values.content, + externalUrl: window.location.href, + originalCharacterId, + originalNoteId, + }) + } } } }) useEffect(() => { - if (commentPage.isSuccess || updateComment.isSuccess) { + if ( + commentPage.isSuccess || + updateComment.isSuccess || + anonymousComment.isSuccess + ) { form.reset() onSubmitted?.() } - }, [commentPage.isSuccess, updateComment.isSuccess, form, onSubmitted]) + }, [ + commentPage.isSuccess, + updateComment.isSuccess, + anonymousComment.isSuccess, + form, + onSubmitted, + ]) const cmViewRef = useRef() const onCreateEditor = useCallback((view: EditorView) => { @@ -112,6 +156,33 @@ export const CommentInput = ({ ), [account?.character, t, form], ) + + let submitText = "Connect" + if (anonymous) { + submitText = "Submit" + } else if (account) { + if (!account.character) { + submitText = "Create Character" + } else if (comment) { + submitText = "Confirm Modification" + } else { + submitText = "Submit" + } + } + + let submitDisabled = false + const name = anonymousForm.watch("name").trim() + const email = anonymousForm.watch("email").trim() + if (account?.character) { + if (!inputContent || inputContent === comment?.metadata?.content?.content) { + submitDisabled = true + } + } else if (anonymous) { + if (!name || !email || !inputContent) { + submitDisabled = true + } + } + return (
)} - + +
diff --git a/src/lib/i18n/locales/zh/common.json b/src/lib/i18n/locales/zh/common.json index 42f6b54f..5dbf67fb 100644 --- a/src/lib/i18n/locales/zh/common.json +++ b/src/lib/i18n/locales/zh/common.json @@ -84,5 +84,8 @@ "Search for your interest": "搜索你感兴趣的内容", "results": "条结果", "My xLog": "我的 xLog", - "Click to select files": "点击选择文件" + "Click to select files": "点击选择文件", + "Comment Without Login": "免登录评论", + "Name": "名称", + "Email": "邮箱" } diff --git a/src/models/page.model.ts b/src/models/page.model.ts index 941cc909..9ecfaa12 100644 --- a/src/models/page.model.ts +++ b/src/models/page.model.ts @@ -754,6 +754,28 @@ export async function getComments({ return res } +export async function anonymousComment(input: { + targetCharacterId: number + targetNoteId: number + content: string + name: string + email: string +}) { + return await fetch("/api/anonymous/comment", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + targetCharacterId: input.targetCharacterId, + targetNoteId: input.targetNoteId, + content: input.content, + name: input.name, + email: input.email, + }), + }) +} + export async function updateComment( { content, diff --git a/src/queries/page.ts b/src/queries/page.ts index 647d0f1b..4da9487a 100644 --- a/src/queries/page.ts +++ b/src/queries/page.ts @@ -340,6 +340,30 @@ export function useCommentPage() { } } +export function useAnonymousComment() { + const queryClient = useQueryClient() + + return useMutation( + async ( + payload: Parameters[0] & { + originalNoteId?: number + originalCharacterId?: number + }, + ) => { + return pageModel.anonymousComment(payload) + }, + { + onSuccess: (data, variables) => { + queryClient.invalidateQueries([ + "getComments", + variables.originalCharacterId || variables.targetCharacterId, + variables.originalNoteId || variables.targetNoteId, + ]) + }, + }, + ) +} + export function useUpdateComment() { const queryClient = useQueryClient() const contract = useContract()