import React, { useEffect, useState, useRef, useCallback } from 'react';
import PropTypes from 'prop-types';
import ReactRouterPropTypes from 'react-router-prop-types';
import { UserType, MessageType } from './Types';
import Message from './Message';
import MessageInput from './MessageInput';
import Spinner from './Spinner';
import Avatar from './Avatar';
import { UserLink } from './UserInfo';
import Button from './Button';
import { format, embedUrls } from '../utils/embed';
import { getMessages, comment, update, markReadTracker, fetchUserUri, updateAvatar } from '../api';
import { bubbleStyle, chatItemStyle } from './helpers/BubbleStyle';
import './Thread.css';
let isMounted;
function Comment({ msg, draft, visitor, active, setActive, onStartEditing, postComment }) {
const embedRef = useRef();
const msgRef = useRef();
const [author, setAuthor] = useState(msg.user);
useEffect(() => {
if (msgRef.current) {
embedUrls(msgRef.current.querySelectorAll('a'), embedRef.current);
if (!embedRef.current.hasChildNodes()) {
embedRef.current.style.display = 'none';
}
}
}, []);
useEffect(() => {
isMounted = true;
if (author.uri) {
fetchUserUri(author.uri).then(response => {
if (isMounted) {
setAuthor(response.data);
}
});
}
return () => {
isMounted = false;
};
}, [author.uri]);
return (
{msg.replyto > 0 &&
(
)}
{
visitor.uid > 0 ? (
<>
{active === msg.rid || setActive(msg.rid)}>Reply}
{
visitor.uid == msg.user.uid &&
<>
·
onStartEditing(msg)}>Edit
>
}
>
) : (
<>
· {active === msg.rid || }
>
)
}
{
msg.photo &&
}
{
active === msg.rid && Write a comment...
}
);
}
Comment.propTypes = {
msg: MessageType.isRequired,
draft: PropTypes.string.isRequired,
visitor: UserType.isRequired,
active: PropTypes.number.isRequired,
setActive: PropTypes.func.isRequired,
onStartEditing: PropTypes.func.isRequired,
postComment: PropTypes.func.isRequired
};
export default function Thread(props) {
const [message, setMessage] = useState((props.location.state || {}).msg || {});
const [replies, setReplies] = useState([]);
const [loading, setLoading] = useState(false);
const [active, setActive] = useState(0);
const [editing, setEditing] = useState({});
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]);
let loadReplies = useCallback(() => {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
setReplies([]);
setLoading(true);
const { mid } = props.match.params;
let params = {
mid: mid
};
if (props.visitor && props.visitor.hash) {
params.hash = props.visitor.hash;
}
getMessages('/api/thread', params)
.then(response => {
setMessage(response.data.shift());
setReplies(response.data);
setLoading(false);
setActive(0);
}
).catch(ex => {
console.log(ex);
});
}, [props.visitor, props.match.params]);
let onReply = useCallback((json) => {
const msg = JSON.parse(json.data);
if (msg.mid == message.mid) {
setReplies(oldReplies => {
return [...oldReplies, msg];
});
}
}, [message]);
let postComment = (template) => {
const { mid, rid, body, attach } = template;
let commentAction = editing.rid ? update(mid, editing.rid, body) : comment(mid, rid, body, attach);
commentAction.then(res => {
setEditing({});
loadReplies();
})
.catch(console.log);
};
let startEditing = (reply) => {
setActive(reply.replyto);
setEditing(reply);
};
const loaders = Math.min(message.replies || 0, 10);
return (
<>
{
message.mid ? (
{active === (message.rid || 0) && Write a comment...}
) : (
)
}
{
!loading ? replies.map((msg) => (
-
)) : (
<>
{Array(loaders).fill().map((it, i) => )}
>
)
}
>
);
}
const linkStyle = {
cursor: 'pointer'
};
Thread.propTypes = {
location: ReactRouterPropTypes.location,
history: ReactRouterPropTypes.history,
match: ReactRouterPropTypes.match,
visitor: UserType.isRequired,
connection: PropTypes.object.isRequired,
};