import { useEffect, useState, useCallback } from 'react'; import { useLocation, useParams } from 'react-router-dom'; import Comment from './Comment'; import Message from './Message'; import MessageInput from './MessageInput'; import Spinner from './Spinner'; import { getMessages, comment, update } from '../api'; import { useVisitor } from './VisitorContext'; import { Helmet } from 'react-helmet'; /** * @type { import('../api').Message } */ const emptyMessage = {}; /** * @param {{ connection: EventSource? }} props */ export default function Thread(props) { const location = useLocation(); const params = useParams(); const [message, setMessage] = useState((location.state || {}).data || {}); const [replies, setReplies] = useState([]); const [loading, setLoading] = useState(false); const [active, setActive] = useState(0); const [editing, setEditing] = useState(emptyMessage); const [visitor] = useVisitor(); const [hash] = useState(visitor.hash); const { mid } = params; let loadReplies = useCallback(() => { document.body.scrollTop = 0; document.documentElement.scrollTop = 0; setReplies([]); setLoading(true); let params = { mid: mid }; params.hash = hash; getMessages('/api/thread', params) .then(response => { let updatedMessage = response.data.shift(); if (!message.mid) { setMessage(updatedMessage); } setReplies(response.data); setLoading(false); setActive(0); } ).catch(ex => { console.log(ex); }); }, [hash, message.mid, mid]); let onReply = useCallback((json) => { const msg = JSON.parse(json.data); if (msg.mid == message.mid) { setReplies(oldReplies => { return [...oldReplies, msg]; }); } }, [message]); let postComment = useCallback((template) => { const { mid, rid, body, attach } = template; let commentAction = editing.rid ? update(mid, editing.rid, body) : comment(mid, rid, body, attach); commentAction.then(() => { setEditing(emptyMessage); loadReplies(); }) .catch(console.log); }, [editing.rid, loadReplies]); let startEditing = (reply) => { setActive(reply.replyto); setEditing(reply); }; useEffect(() => { setActive(0); loadReplies(); }, [loadReplies]); useEffect(() => { if (props.connection.addEventListener && message.mid) { props.connection.addEventListener('msg', onReply); } return () => { if (props.connection.removeEventListener && message.mid) { props.connection.removeEventListener('msg', onReply); } }; }, [props.connection, message.mid, onReply]); const loaders = Math.min(message.replies || 0, 10); const pageTitle = `${params.user} ${message && message.tags || 'thread'}`; return ( <> {pageTitle} { message.mid ? ( {active === (message.rid || 0) && Write a comment...} ) : ( ) } { message.replies && } ); }