import React, { useState, useEffect, useRef } from 'react'; import { Link, useNavigate, useParams } from 'react-router-dom'; import { Tooltip } from 'react-tooltip'; import { useComment, usePublishComment } from '@plebbit/plebbit-react-hooks'; import { debounce } from 'lodash'; import useAppStore from '../../useAppStore'; import { Container, NavBar, Header, Break, PostForm, PostFormTable, BoardForm } from './styles/Board.styled'; import { ReplyFormLink, TopBar, BottomBar } from './styles/Thread.styled'; import CaptchaModal from '../CaptchaModal'; import ImageBanner from '../ImageBanner'; import Post from '../Post'; import PostLoader from '../PostLoader'; import ReplyModal from '../ReplyModal'; import SettingsModal from '../SettingsModal'; import getCommentMediaInfo from '../../utils/getCommentMediaInfo'; import getDate from '../../utils/getDate'; import handleStyleChange from '../../utils/handleStyleChange'; import onError from '../../utils/onError'; import onSuccess from '../../utils/onSuccess'; import renderThreadComments from '../../utils/renderThreadComments'; import useClickForm from '../../hooks/useClickForm'; const Thread = () => { const { captchaResponse, setCaptchaResponse, defaultSubplebbits, isSettingsOpen, setIsSettingsOpen, selectedAddress, setSelectedAddress, selectedStyle, selectedThread, setSelectedThread, selectedTitle, setSelectedTitle, showPostForm, showPostFormLink } = useAppStore(state => state); const nameRef = useRef(); const commentRef = useRef(); const linkRef = useRef(); const [commentContent, setCommentContent] = useState(''); const [isCaptchaOpen, setIsCaptchaOpen] = useState(false); const [isReplyOpen, setIsReplyOpen] = useState(false); const [captchaImage, setCaptchaImage] = useState(''); const navigate = useNavigate(); const [prevScrollPos, setPrevScrollPos] = useState(0); const [visible, setVisible] = useState(true); const comment = useComment({commentCid: selectedThread}); const { subplebbitAddress, threadCid } = useParams(); const handleClickForm = useClickForm(); const commentMediaInfo = getCommentMediaInfo(comment); const fallbackImgUrl = "/assets/filedeleted-res.gif"; // useEffect(() => { // console.log(comment); // }, [comment]); // temporary title from JSON, gets subplebbitAddress and threadCid from URL useEffect(() => { setSelectedAddress(subplebbitAddress); setSelectedThread(threadCid); const selectedSubplebbit = defaultSubplebbits.find((subplebbit) => subplebbit.address === subplebbitAddress); if (selectedSubplebbit) { setSelectedTitle(selectedSubplebbit.title); } }, [subplebbitAddress, setSelectedAddress, setSelectedTitle, defaultSubplebbits]); // mobile navbar scroll effect useEffect(() => { const debouncedHandleScroll = debounce(() => { const currentScrollPos = window.pageYOffset; setVisible(prevScrollPos > currentScrollPos || currentScrollPos < 10); setPrevScrollPos(currentScrollPos); }, 50); window.addEventListener('scroll', debouncedHandleScroll); return () => window.removeEventListener('scroll', debouncedHandleScroll); }, [prevScrollPos, visible]); const onChallengeVerification = (challengeVerification) => { if (challengeVerification.challengeSuccess === true) { onSuccess('challenge success', {publishedCid: challengeVerification.publication.cid}) } else if (challengeVerification.challengeSuccess === false) { onError('challenge failed', {reason: challengeVerification.reason, errors: challengeVerification.errors}); onError("Error: You seem to have mistyped the CAPTCHA. Please try again."); } }; const onChallenge = async (challenges, comment) => { // console.log("onChallenge:", challenges, comment); let challengeAnswers = []; try { challengeAnswers = await getChallengeAnswersFromUser(challenges) } catch (error) { onError(error); } if (challengeAnswers) { await comment.publishChallengeAnswers(challengeAnswers) } }; const publishCommentOptions = { displayName: nameRef.current ? nameRef.current.value : undefined, content: commentRef.current ? commentRef.current.value : undefined, link: linkRef.current ? linkRef.current.value : undefined, parentCid: selectedThread, subplebbitAddress: selectedAddress, onChallenge, onChallengeVerification, onError }; const resetFields = () => { nameRef.current.value = ''; commentRef.current.value = ''; linkRef.current.value = ''; }; const { publishComment } = usePublishComment(publishCommentOptions); const getChallengeAnswersFromUser = async (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); setCaptchaImage(imageSource); const handleKeyDown = (event) => { if (event.key === 'Enter') { setCaptchaImage(''); resolve(captchaResponse); setIsCaptchaOpen(false); document.removeEventListener('keydown', handleKeyDown); event.preventDefault(); } }; setCaptchaResponse(''); document.addEventListener('keydown', handleKeyDown); }; challengeImg.onerror = () => { reject(onError('Could not load challenge image')); }; }); }; // mobile navbar board select functionality const handleSelectChange = (event) => { const selected = event.target.value; const selectedTitle = defaultSubplebbits.find((subplebbit) => subplebbit.address === selected).title; setSelectedTitle(selectedTitle); setSelectedAddress(selected); navigate(`/${selected}`); }; // scroll to post when quote is clicked function handleQuoteClick(reply, event) { event.preventDefault(); const cid = reply.shortCid; const targetElement = [...document.querySelectorAll('.post-reply')] .find(el => el.innerHTML.includes(cid)); if (targetElement) { targetElement.scrollIntoView({ behavior: "instant" }); } }; return ( setIsCaptchaOpen(false)} captchaImage={captchaImage} /> setIsReplyOpen(false)} /> setIsSettingsOpen(false)} /> <> {defaultSubplebbits.map(subplebbit => ( [ { setSelectedTitle(subplebbit.title); setSelectedAddress(subplebbit.address); }} >{subplebbit.title ? subplebbit.title : subplebbit.address} ]  ))} [ setIsSettingsOpen(true)}>Settings ] [ handleStyleChange({target: {value: "Yotsuba"}} )}>Home ]
Board  
setIsSettingsOpen(true)}>Settings   handleStyleChange({target: {value: "Yotsuba"}} )}>Home
 
 
<>
<>
{selectedTitle}
p/{selectedAddress}
Return
Catalog
[ event.target.style.cursor='pointer'}>Post a Reply ]
event.target.style.cursor='pointer'}>Post a Reply
Name {await publishComment(); resetFields();}} /> Comment