2025-10-16 23:16:38 +02:00
|
|
|
import { useEffect } from 'react';
|
2024-04-29 12:35:37 +02:00
|
|
|
import { useTranslation } from 'react-i18next';
|
2025-03-07 11:29:04 +01:00
|
|
|
import { Comment, Role, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
2025-03-05 17:10:26 +01:00
|
|
|
import useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits';
|
2024-04-08 17:32:12 +02:00
|
|
|
import { useLocation, useParams } from 'react-router-dom';
|
2025-12-23 19:14:25 +01:00
|
|
|
import { isAllView } from '../../lib/utils/view-utils';
|
2025-11-07 12:50:58 +01:00
|
|
|
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
2024-06-11 15:49:26 +02:00
|
|
|
import useIsMobile from '../../hooks/use-is-mobile';
|
2025-06-03 22:02:54 +02:00
|
|
|
import ErrorDisplay from '../../components/error-display/error-display';
|
2024-06-11 15:49:26 +02:00
|
|
|
import PostDesktop from '../../components/post-desktop';
|
|
|
|
|
import PostMobile from '../../components/post-mobile';
|
|
|
|
|
import styles from './post.module.css';
|
2025-03-05 21:38:01 +01:00
|
|
|
|
2024-06-11 15:49:26 +02:00
|
|
|
export interface PostProps {
|
|
|
|
|
index?: number;
|
|
|
|
|
isHidden?: boolean;
|
2024-12-24 17:13:12 +01:00
|
|
|
hasThumbnail?: boolean;
|
2024-06-11 15:49:26 +02:00
|
|
|
post?: any;
|
2024-07-01 10:26:38 +02:00
|
|
|
postReplyCount?: number;
|
2024-06-11 15:49:26 +02:00
|
|
|
reply?: any;
|
|
|
|
|
roles?: Role[];
|
|
|
|
|
showAllReplies?: boolean;
|
|
|
|
|
showReplies?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-05 21:38:01 +01:00
|
|
|
export const Post = ({ post, showAllReplies = false, showReplies = true }: PostProps) => {
|
2025-03-05 17:10:26 +01:00
|
|
|
const subplebbit = useSubplebbitsStore((state) => state.subplebbits[post?.subplebbitAddress]);
|
2024-06-11 15:49:26 +02:00
|
|
|
const isMobile = useIsMobile();
|
|
|
|
|
|
2024-06-21 22:02:56 +02:00
|
|
|
let comment = post;
|
|
|
|
|
|
|
|
|
|
// handle pending mod or author edit
|
|
|
|
|
const { editedComment } = useEditedComment({ comment });
|
|
|
|
|
if (editedComment) {
|
|
|
|
|
comment = editedComment;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-11 15:49:26 +02:00
|
|
|
return (
|
|
|
|
|
<div className={styles.thread}>
|
|
|
|
|
<div className={styles.postContainer}>
|
|
|
|
|
{isMobile ? (
|
2025-03-05 21:38:01 +01:00
|
|
|
<PostMobile post={comment} roles={subplebbit?.roles} showAllReplies={showAllReplies} showReplies={showReplies} />
|
2024-06-11 15:49:26 +02:00
|
|
|
) : (
|
2025-03-05 21:38:01 +01:00
|
|
|
<PostDesktop post={comment} roles={subplebbit?.roles} showAllReplies={showAllReplies} showReplies={showReplies} />
|
2024-06-11 15:49:26 +02:00
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
2024-04-02 17:00:36 +02:00
|
|
|
|
|
|
|
|
const PostPage = () => {
|
2024-04-29 12:35:37 +02:00
|
|
|
const { t } = useTranslation();
|
2024-04-02 17:00:36 +02:00
|
|
|
const params = useParams();
|
2024-05-09 16:04:24 +02:00
|
|
|
const location = useLocation();
|
2025-11-07 12:50:58 +01:00
|
|
|
const { commentCid } = params;
|
|
|
|
|
const subplebbitAddress = useResolvedSubplebbitAddress();
|
2024-10-29 17:40:09 +01:00
|
|
|
const isInAllView = isAllView(location.pathname);
|
2024-04-08 17:32:12 +02:00
|
|
|
|
2024-06-15 12:37:45 +02:00
|
|
|
const comment = useComment({ commentCid });
|
2025-03-07 11:29:04 +01:00
|
|
|
const subplebbit = useSubplebbit({ subplebbitAddress });
|
|
|
|
|
const { createdAt, description, rules, shortAddress, suggested, title } = subplebbit || {};
|
2024-06-15 12:37:45 +02:00
|
|
|
|
|
|
|
|
// if the comment is a reply, return the post comment instead, then the reply will be highlighted in the thread
|
2024-06-04 21:35:22 +02:00
|
|
|
const postComment = useComment({ commentCid: comment?.postCid });
|
2024-07-02 15:39:20 +02:00
|
|
|
let post: Comment;
|
2024-06-04 21:35:22 +02:00
|
|
|
if (comment.parentCid) {
|
|
|
|
|
post = postComment;
|
|
|
|
|
} else {
|
|
|
|
|
post = comment;
|
|
|
|
|
}
|
2024-06-15 12:37:45 +02:00
|
|
|
|
2025-03-02 12:10:16 +01:00
|
|
|
const { error, replyCount } = post || {};
|
2024-04-02 17:00:36 +02:00
|
|
|
|
2024-04-04 11:41:17 +02:00
|
|
|
useEffect(() => {
|
|
|
|
|
window.scrollTo(0, 0);
|
|
|
|
|
}, []);
|
|
|
|
|
|
2024-07-02 15:39:20 +02:00
|
|
|
useEffect(() => {
|
|
|
|
|
const boardTitle = title ? title : shortAddress || subplebbitAddress;
|
|
|
|
|
const postTitle = post?.title?.slice(0, 30) || post?.content?.slice(0, 30);
|
2025-10-17 23:30:35 +02:00
|
|
|
const postDucumentTitle = (postTitle ? postTitle.trim() + '... - ' : '') + boardTitle + ' - 5chan';
|
|
|
|
|
document.title = isInAllView ? `${t('all')} - 5chan` : postDucumentTitle;
|
2024-09-18 14:23:07 +02:00
|
|
|
}, [title, shortAddress, subplebbitAddress, post?.title, post?.content, isInAllView, t]);
|
2024-07-02 15:39:20 +02:00
|
|
|
|
2025-06-03 22:02:54 +02:00
|
|
|
// probably not necessary to show the error to the user if the post loaded successfully
|
2025-10-16 23:13:18 +02:00
|
|
|
const shouldShowErrorToUser = post?.error && ((post?.replyCount > 0 && post?.replies?.length === 0) || (post?.state === 'failed' && post?.error));
|
2025-06-03 22:02:54 +02:00
|
|
|
|
2024-04-02 17:00:36 +02:00
|
|
|
return (
|
|
|
|
|
<div className={styles.content}>
|
2024-07-07 19:12:12 +02:00
|
|
|
{/* TODO: remove this replyCount error once api supports scrolling replies pages */}
|
|
|
|
|
{replyCount > 60 && <span className={styles.error}>Error: this thread has too many replies, some of them cannot be displayed right now.</span>}
|
2025-06-03 22:02:54 +02:00
|
|
|
{shouldShowErrorToUser && (
|
|
|
|
|
<div className={styles.error}>
|
|
|
|
|
<ErrorDisplay error={error} />
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2025-12-23 19:14:25 +01:00
|
|
|
<Post post={post} showAllReplies={true} />
|
2024-04-02 17:00:36 +02:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default PostPage;
|