From 322a7d3d23cdc7e7fb1e4d0bfc1d664ea67fe991 Mon Sep 17 00:00:00 2001 From: plebbitor Date: Wed, 12 Apr 2023 21:00:51 +0200 Subject: [PATCH] implemented replying in modal --- src/components/ReplyModal.jsx | 168 ++++++++++++++++++++++++++-- src/components/views/Board.jsx | 19 +++- src/components/views/Thread.jsx | 1 - src/hooks/stores/useGeneralStore.js | 3 + 4 files changed, 175 insertions(+), 16 deletions(-) diff --git a/src/components/ReplyModal.jsx b/src/components/ReplyModal.jsx index 7bde1723..d6fcfcc8 100644 --- a/src/components/ReplyModal.jsx +++ b/src/components/ReplyModal.jsx @@ -1,18 +1,164 @@ -import React from 'react'; +import React, { useRef, useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { usePublishComment } from '@plebbit/plebbit-react-hooks'; import { StyledModal } from './styled/ReplyModal.styled'; import useGeneralStore from '../hooks/stores/useGeneralStore'; import Modal from 'react-modal'; import Draggable from 'react-draggable'; +import useError from '../hooks/useError'; +import useSuccess from '../hooks/useSuccess'; const ReplyModal = ({ isOpen, closeModal }) => { - const selectedStyle = useGeneralStore(state => state.selectedStyle); + const { + captchaResponse, setCaptchaResponse, + setChallengesArray, + setIsCaptchaOpen, + setPendingComment, + selectedAddress, + selectedReply, + selectedStyle, + selectedThread, + } = useGeneralStore(state => state); - const handleCloseModal = () => { - closeModal(); + const navigate = useNavigate(); + + const nodeRef = useRef(null); + + const nameRef = useRef(); + const commentRef = useRef(); + const linkRef = useRef(); + + const onChallengeVerificationRef = useRef(); + + const [errorMessage, setErrorMessage] = useState(null); + const [successMessage, setSuccessMessage] = useState(null); + useError(errorMessage, [errorMessage]); + useSuccess(successMessage, [successMessage]); + + + const onChallengeVerification = (challengeVerification) => { + if (challengeVerification.challengeSuccess === true) { + setSuccessMessage('challenge success', {publishedCid: challengeVerification.publication?.cid}); + navigate(`/p/${selectedAddress}/c/${selectedThread}`); + } + else if (challengeVerification.challengeSuccess === false) { + setErrorMessage('challenge failed', {reason: challengeVerification.reason, errors: challengeVerification.errors}); + setErrorMessage("Error: You seem to have mistyped the CAPTCHA. Please try again."); + } + }; + + + const onChallenge = async (challenges, comment) => { + setPendingComment(comment); + let challengeAnswers = []; + + try { + challengeAnswers = await getChallengeAnswersFromUser(challenges) + } + catch (error) { + setErrorMessage(error); + } + if (challengeAnswers) { + await comment.publishChallengeAnswers(challengeAnswers) + } + }; + + + const [publishCommentOptions, setPublishCommentOptions] = useState({ + subplebbitAddress: selectedAddress, + onChallenge, + onChallengeVerification: onChallengeVerificationRef.current, + onError: (error) => { + setErrorMessage(error); + }, + }); + + + const { publishComment, index } = usePublishComment(publishCommentOptions); + + + useEffect(() => { + if (index !== undefined) { + navigate(`/profile/c/${index}`); + setSuccessMessage('Comment pending with index ' + index + '.'); + } + }, [index]); + + + onChallengeVerificationRef.current = onChallengeVerification; + + + const resetFields = () => { + nameRef.current.value = ''; + commentRef.current.value = ''; + linkRef.current.value = ''; + }; + + + useEffect(() => { + setPublishCommentOptions((prevPublishCommentOptions) => ({ + ...prevPublishCommentOptions, + subplebbitAddress: selectedAddress, + onChallengeVerification: onChallengeVerificationRef.current, + })); + }, [selectedAddress]); + + + const handleSubmit = async (event) => { + event.preventDefault(); + + setPublishCommentOptions((prevPublishCommentOptions) => ({ + ...prevPublishCommentOptions, + displayName: nameRef.current.value || undefined, + content: commentRef.current.value || undefined, + link: linkRef.current.value || undefined, + parentCid: selectedReply, + })); + }; + + + useEffect(() => { + if (publishCommentOptions.content) { + (async () => { + await publishComment(); + resetFields(); + })(); + } + }, [publishCommentOptions]); + + + 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 = (event) => { + if (event.key === 'Enter') { + resolve(captchaResponse); + setIsCaptchaOpen(false); + document.removeEventListener('keydown', handleKeyDown); + event.preventDefault(); + } + }; + + setCaptchaResponse(''); + document.addEventListener('keydown', handleKeyDown); + }; + + challengeImg.onerror = () => { + reject(setErrorMessage('Could not load challenges')); + }; + }); }; - const nodeRef = React.useRef(null); return ( {
- Reply to Thread -
- +
- +
- +