feat: support editing comment content

This commit is contained in:
DIYgod 2023-04-06 20:39:10 +01:00
parent 8f4adbd2bc
commit 556c20ba68
No known key found for this signature in database
5 changed files with 110 additions and 14 deletions

View File

@ -28,6 +28,9 @@
"Submit": "提交",
"Reply": "回复",
"Cancel Reply": "取消回复",
"Edit": "编辑",
"Cancel Edit": "取消编辑",
"Confirm Modification": "确认修改",
"ago": "{{time}}前",
"joined ago": "{{time}}前加入",
"obtained ago": "{{time}}前获得",

View File

@ -6,20 +6,25 @@ import { Button } from "~/components/ui/Button"
import { useForm } from "react-hook-form"
import { useAccountState } from "@crossbell/connect-kit"
import { useState, useEffect } from "react"
import { useCommentPage } from "~/queries/page"
import { useCommentPage, useUpdateComment } from "~/queries/page"
import { useRouter } from "next/router"
import { EmojiPicker } from "./EmojiPicker"
import { Popover } from "@headlessui/react"
import { useTranslation } from "next-i18next"
import { NoteEntity, CharacterEntity } from "crossbell.js"
export const CommentInput: React.FC<{
pageId?: string
originalId?: string
onSubmitted?: () => void
}> = ({ pageId, originalId, onSubmitted }) => {
comment?: NoteEntity & {
character?: CharacterEntity | null
}
}> = ({ pageId, originalId, onSubmitted, comment }) => {
const account = useAccountState((s) => s.computed.account)
const userSites = useAccountSites()
const commentPage = useCommentPage()
const updateComment = useUpdateComment()
const router = useRouter()
const [viewer, setViewer] = useState<Profile | null>(null)
const { t } = useTranslation(["common", "site"])
@ -32,27 +37,38 @@ export const CommentInput: React.FC<{
const form = useForm({
defaultValues: {
content: "",
content: comment?.metadata?.content?.content || "",
},
})
const handleSubmit = form.handleSubmit(async (values) => {
if (pageId) {
commentPage.mutate({
pageId: pageId,
content: values.content,
externalUrl: window.location.href,
originalId: originalId,
})
if (pageId && values.content) {
if (comment) {
updateComment.mutate({
pageId,
content: values.content,
externalUrl: window.location.href,
originalId,
characterId: comment.characterId,
noteId: comment.noteId,
})
} else {
commentPage.mutate({
pageId,
content: values.content,
externalUrl: window.location.href,
originalId,
})
}
}
})
useEffect(() => {
if (commentPage.isSuccess) {
if (commentPage.isSuccess || updateComment.isSuccess) {
form.reset()
onSubmitted?.()
}
}, [commentPage.isSuccess, form, onSubmitted])
}, [commentPage.isSuccess, updateComment.isSuccess, form, onSubmitted])
return (
<div className="xlog-comment-input flex">
@ -104,12 +120,18 @@ export const CommentInput: React.FC<{
</Popover>
<Button
type="submit"
isLoading={userSites.isLoading || commentPage.isLoading}
isLoading={
userSites.isLoading ||
commentPage.isLoading ||
updateComment.isLoading
}
>
{t(
account
? userSites.isSuccess && !userSites.data?.length
? "Create Character"
: comment
? "Confirm Modification"
: "Submit"
: "Connect",
)}

View File

@ -12,6 +12,7 @@ import { CommentInput } from "~/components/common/CommentInput"
import { CharacterFloatCard } from "~/components/common/CharacterFloatCard"
import { useTranslation } from "next-i18next"
import { useDate } from "~/hooks/useDate"
import { useAccountState } from "@crossbell/connect-kit"
export const CommentItem: React.FC<{
comment: NoteEntity & {
@ -21,9 +22,13 @@ export const CommentItem: React.FC<{
depth: number
}> = ({ comment, originalId, depth }) => {
const [replyOpen, setReplyOpen] = useState(false)
const [editOpen, setEditOpen] = useState(false)
const { t } = useTranslation("common")
const date = useDate()
const account = useAccountState(({ computed }) => computed.account)
if (!comment.metadata?.content?.content) {
return null
}
@ -95,7 +100,7 @@ export const CommentItem: React.FC<{
/>
{depth < 2 && (
<Button
className="text-gray-500 text-[13px] ml-2 mt-[-1px]"
className="text-gray-500 text-[13px] ml-1 mt-[-1px]"
variant="text"
onClick={() => setReplyOpen(!replyOpen)}
>
@ -105,6 +110,16 @@ export const CommentItem: React.FC<{
</span>
</Button>
)}
{comment.characterId === account?.characterId && (
<Button
className="text-gray-500 text-[13px] mt-[-1px]"
variant="text"
onClick={() => setEditOpen(!editOpen)}
>
<i className="i-mingcute:edit-line mx-1" />{" "}
{t(`${editOpen ? "Cancel " : ""}Edit`)}
</Button>
)}
</div>
{replyOpen && (
<div className="pt-6">
@ -115,6 +130,16 @@ export const CommentItem: React.FC<{
/>
</div>
)}
{editOpen && (
<div className="pt-6">
<CommentInput
originalId={originalId}
pageId={`${comment.characterId}-${comment.noteId}`}
onSubmitted={() => setEditOpen(false)}
comment={comment}
/>
</div>
)}
</div>
</div>
{(comment as any)?.fromNotes?.list?.length > 0 && (

View File

@ -567,6 +567,32 @@ export async function getComments({
return res
}
export async function updateComment(
{
pageId,
content,
externalUrl,
originalId,
characterId,
noteId,
}: {
pageId: string
content: string
externalUrl: string
originalId?: string
characterId: number
noteId: number
},
contract: Contract,
) {
return contract.setNoteMetadata(characterId, noteId, {
content,
external_urls: [externalUrl],
tags: ["comment"],
sources: ["xlog"],
})
}
export function parsePageId(pageId: string) {
const [characterId, noteId] = pageId.split("-").map(Number)

View File

@ -15,6 +15,7 @@ import {
} from "@crossbell/connect-kit"
import { useRefCallback } from "@crossbell/util-hooks"
import { useContract } from "@crossbell/contract"
import { NoteEntity } from "crossbell.js"
import * as pageModel from "~/models/page.model"
@ -233,6 +234,25 @@ export function useCommentPage() {
}
}
export function useUpdateComment() {
const queryClient = useQueryClient()
const contract = useContract()
return useMutation(
async (payload: Parameters<typeof pageModel.updateComment>[0]) => {
return pageModel.updateComment(payload, contract)
},
{
onSuccess: (data, variables) => {
queryClient.invalidateQueries([
"getComments",
variables.originalId || variables.pageId,
])
},
},
)
}
export function useGetComments(input: { pageId?: string }) {
return useInfiniteQuery({
queryKey: ["getComments", input.pageId],