import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useAccount, usePublishComment } from '@plebbit/plebbit-react-hooks'; import Modal from 'react-modal'; import Draggable from 'react-draggable'; import { StyledModal } from '../styled/modals/ReplyModal.styled'; import useAnonMode from '../../hooks/useAnonMode'; import useError from '../../hooks/useError'; import useAnonModeStore from '../../hooks/stores/useAnonModeStore'; import useGeneralStore from '../../hooks/stores/useGeneralStore'; const ReplyModal = ({ isOpen, closeModal }) => { const { captchaResponse, setCaptchaResponse, setChallengesArray, setIsCaptchaOpen, setPendingComment, setPendingCommentIndex, replyQuoteCid, setResolveCaptchaPromise, selectedAddress, selectedParentCid, selectedShortCid, selectedStyle, selectedText, setSelectedText, triggerInsertion, } = useGeneralStore(state => state); const { anonymousMode } = useAnonModeStore(); const account = useAccount(); const [, setNewErrorMessage] = useError(); const nodeRef = useRef(null); const nameRef = useRef(); const commentRef = useRef(); const linkRef = useRef(); const [triggerPublishComment, setTriggerPublishComment] = useState(false); const [isMobile, setIsMobile] = useState(window.innerWidth <= 480); const [executeAnonMode, setExecuteAnonMode] = useState(false); useAnonMode(selectedParentCid, anonymousMode && executeAnonMode); useEffect(() => { const handleResize = () => setIsMobile(window.innerWidth <= 480); window.addEventListener('resize', handleResize); // Cleanup function return () => { window.removeEventListener('resize', handleResize); }; }, [setIsMobile]); const onModalOpen = () => { if (commentRef.current) { if (selectedText) { commentRef.current.value += '\n'; } commentRef.current.focus(); const len = commentRef.current.value.length; commentRef.current.setSelectionRange(len, len); } }; const insertAtCursor = (inputElement, valueToInsert) => { const startPos = inputElement.selectionStart || inputElement.value.length; const endPos = startPos + valueToInsert.length; inputElement.setRangeText(valueToInsert, startPos, startPos, 'end'); inputElement.setSelectionRange(endPos, endPos); } useEffect(() => { if (replyQuoteCid && commentRef.current) { const prefixedReplyQuoteCid = `c/${replyQuoteCid}\n`; insertAtCursor(commentRef.current, prefixedReplyQuoteCid); } }, [triggerInsertion, replyQuoteCid]); const getSelectedText = useCallback(() => { const text = document.getSelection().toString(); setSelectedText(text ? `>${text}\n` : ''); }, [setSelectedText]); useEffect(() => { if (isOpen) { setTimeout(getSelectedText, 0); } else { setSelectedText(''); } }, [isOpen, getSelectedText, setSelectedText]); const onChallengeVerification = (challengeVerification) => { if (challengeVerification.challengeSuccess === true) { return; } else if (challengeVerification.challengeSuccess === false) { setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`); console.log('challenge failed', challengeVerification); } }; const onChallenge = async (challenges, comment) => { setPendingComment(comment); let challengeAnswers = []; try { challengeAnswers = await getChallengeAnswersFromUser(challenges) } catch (error) { setNewErrorMessage(error.message); console.log(error); } if (challengeAnswers) { await comment.publishChallengeAnswers(challengeAnswers) } }; useEffect(() => { setPublishCommentOptions((prevPublishCommentOptions) => ({ ...prevPublishCommentOptions, subplebbitAddress: selectedAddress, })); }, [selectedAddress]); const [publishCommentOptions, setPublishCommentOptions] = useState({ subplebbitAddress: selectedAddress, onChallenge, onChallengeVerification, onError: (error) => { setNewErrorMessage(error.message); console.log(error); }, }); const { publishComment, index } = usePublishComment(publishCommentOptions); useEffect(() => { if (index !== undefined) { setPendingCommentIndex(index); } }, [index, setPendingCommentIndex]); const resetFields = useCallback(() => { if (nameRef.current) { nameRef.current.value = ''; } if (commentRef.current) { commentRef.current.value = ''; } if (linkRef.current) { linkRef.current.value = ''; } }, []); const handleSubmit = async (event) => { event.preventDefault(); if ( commentRef.current.value === "" && linkRef.current.value === "" ) { setNewErrorMessage("Please enter a comment or link."); return; } setPublishCommentOptions((prevPublishCommentOptions) => ({ ...prevPublishCommentOptions, author: { displayName: nameRef.current.value || undefined, address: account?.author.address, }, content: commentRef.current.value || undefined, link: linkRef.current.value || undefined, parentCid: selectedParentCid, })); setTriggerPublishComment(true); }; const updateSigner = useCallback(async () => { if (anonymousMode) { setExecuteAnonMode(true); let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {}; let signer; if (!storedSigners[selectedParentCid]) { signer = await account?.plebbit.createSigner(); storedSigners[selectedParentCid] = { privateKey: signer?.privateKey, address: signer?.address }; localStorage.setItem('storedSigners', JSON.stringify(storedSigners)); } else { const signerPrivateKey = storedSigners[selectedParentCid].privateKey; try { signer = await account?.plebbit.createSigner({type: 'ed25519', privateKey: signerPrivateKey}); } catch (error) { console.log(error); } } setPublishCommentOptions(prevPublishCommentOptions => { const newPublishCommentOptions = { ...prevPublishCommentOptions, signer, author: { ...prevPublishCommentOptions.author, address: signer?.address, }, }; if (JSON.stringify(prevPublishCommentOptions) !== JSON.stringify(newPublishCommentOptions)) { return newPublishCommentOptions; } return prevPublishCommentOptions; }); } }, [selectedParentCid, anonymousMode, account]); useEffect(() => { if (anonymousMode) { updateSigner(); } }, [updateSigner, anonymousMode]); useEffect(() => { if (publishCommentOptions && triggerPublishComment) { (async () => { await publishComment(); resetFields(); closeModal(); })(); setTriggerPublishComment(false); setExecuteAnonMode(false); } }, [publishCommentOptions, triggerPublishComment, publishComment, resetFields, closeModal]); const getChallengeAnswersFromUser = async (challenges) => { setChallengesArray(challenges); return new Promise((resolve, reject) => { const imageString = challenges?.challenges[0].challenge; const imageSource = `data:image/png;base64,${imageString}`; const challengeImg = new Image(); challengeImg.src = imageSource; challengeImg.onload = () => { setIsCaptchaOpen(true); const handleKeyDown = async (event) => { if (event.key === 'Enter') { const currentCaptchaResponse = captchaResponse; resolve(currentCaptchaResponse); setIsCaptchaOpen(false); document.removeEventListener('keydown', handleKeyDown); event.preventDefault(); } }; setCaptchaResponse(''); document.addEventListener('keydown', handleKeyDown); setResolveCaptchaPromise(resolve); }; challengeImg.onerror = () => { reject(setNewErrorMessage('Could not load challenges')); }; }); }; return (
Reply to c/{selectedShortCid}
{account && account?.author && account?.author.displayName ? ( ) : ( )}
{`c/${selectedShortCid}`}