import type { CharacterEntity, NoteEntity } from "crossbell" import { nanoid } from "nanoid" import { useCallback, useEffect, useRef, useState } from "react" import { useForm } from "react-hook-form" import { EditorView } from "@codemirror/view" import { useAccountState } from "@crossbell/connect-kit" import { Popover } from "@headlessui/react" import { editorUpload } from "~/components/dashboard/toolbars/Multimedia" import { Avatar } from "~/components/ui/Avatar" import { Button } from "~/components/ui/Button" import CodeMirrorEditor from "~/components/ui/CodeMirror" import { useUploadFile } from "~/hooks/useUploadFile" import { useTranslation } from "~/lib/i18n/client" import { useAnonymousComment, useCommentPage, useUpdateComment, } from "~/queries/page" import filter from "../../../data/filter.json" import { Input } from "../ui/Input" import { Tooltip } from "../ui/Tooltip" import { EmojiPicker } from "./EmojiPicker" export const CommentInput = ({ characterId, noteId, originalCharacterId, originalNoteId, onSubmitted, comment, }: { characterId?: number noteId?: number originalCharacterId?: number originalNoteId?: number onSubmitted?: () => void comment?: NoteEntity & { character?: CharacterEntity | null } }) => { const account = useAccountState((s) => s.computed.account) const commentPage = useCommentPage() const updateComment = useUpdateComment() const { t } = useTranslation("site") const anonymousComment = useAnonymousComment() const [anonymous, setAnonymous] = useState(false) const [randomId] = useState(nanoid()) const form = useForm({ defaultValues: { content: comment?.metadata?.content?.content || "", }, }) const anonymousForm = useForm({ defaultValues: { name: "", email: "", url: "", } as { name: string email: string url: string }, }) const inputContent = form.watch("content").trim() const handleSubmit = form.handleSubmit(async (values) => { if (characterId && noteId) { if (comment) { if (values.content) { updateComment.mutate({ content: values.content, characterId: comment.characterId, noteId: comment.noteId, originalCharacterId, originalNoteId, }) } } else { 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"), url: anonymousForm.getValues("url"), originalCharacterId, originalNoteId, }) } } else { commentPage.mutate({ characterId, noteId, content: values.content, originalCharacterId, originalNoteId, }) } } } }) useEffect(() => { if ( commentPage.isSuccess || updateComment.isSuccess || anonymousComment.isSuccess ) { form.reset() onSubmitted?.() } }, [ commentPage.isSuccess, updateComment.isSuccess, anonymousComment.isSuccess, form, onSubmitted, ]) const cmViewRef = useRef() const onCreateEditor = useCallback((view: EditorView) => { cmViewRef.current = view }, []) const uploadFile = useUploadFile() const handleDropFile = useCallback( async (file: File) => { const view = cmViewRef.current if (view) { editorUpload(file, view) } }, [uploadFile], ) const InputHolder = useCallback( () => ( ), [account?.character, t, form], ) if (account?.characterId && filter.comment.includes(account.characterId)) { return null } 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() const url = anonymousForm.watch("url").trim() if (account?.character) { if (!inputContent || inputContent === comment?.metadata?.content?.content) { submitDisabled = true } } else if (anonymous) { if (!name || !email || !inputContent) { submitDisabled = true } } const id = `anonymous-${characterId}-${noteId}` return (
{ form.setValue("content", val) }} handleDropFile={handleDropFile} className="mb-2 p-3 h-[74px] border focus-within:border-accent border-[var(--border-color)] rounded-lg outline-2 outline-transparent cursor-text transition-colors" placeholder={t("Write a comment on the blockchain") || ""} maxLength={600} onCreateEditor={onCreateEditor} LoadingComponent={InputHolder} />
{({ open }: { open: boolean }) => ( <> { const emojiValue = e.native const view = cmViewRef.current if (!view) return const state = view.state const range = state.selection.ranges[0] view.dispatch({ changes: { from: range.from, to: range.to, insert: `${emojiValue}`, }, selection: { anchor: range.from }, }) requestAnimationFrame(() => { form.setValue("content", view.state.doc.toString()) }) }} /> )}
{!account && (
setAnonymous(e.target.checked)} />
{anonymous && (
)}
)}
) }