import { useState } from 'react'; import { Link, useLocation, useParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { Role, useSubplebbit } from '@plebbit/plebbit-react-hooks'; import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js'; import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils'; import { getFormattedDate } from '../../lib/utils/time-utils'; import { isPostPageView } from '../../lib/utils/view-utils'; import useCountLinksInReplies from '../../hooks/use-count-links-in-replies'; import useReplies from '../../hooks/use-replies'; import useWindowWidth from '../../hooks/use-window-width'; import styles from './post.module.css'; import Markdown from '../markdown'; import CommentMedia from '../comment-media'; import { canEmbed } from '../embed'; interface PostProps { index?: number; post?: any; reply?: any; roles?: Role[]; showAllReplies?: boolean; } const PostDesktop = ({ post, roles, showAllReplies }: PostProps) => { const { t } = useTranslation(); const { author, cid, content, link, linkHeight, linkWidth, locked, pinned, postCid, replyCount, shortCid, subplebbitAddress, timestamp, title } = post || {}; const { address, displayName, shortAddress } = author || {}; const authorRole = roles?.[address]?.role; const { isDescription, isRules } = post || {}; // custom properties, not from api const isInPostPage = isPostPageView(useLocation().pathname, useParams()); const displayTitle = title && title.length > 75 ? title?.slice(0, 75) + '...' : title; const displayContent = content && !isInPostPage && content.length > 1000 ? content?.slice(0, 1000) + '(...)' : content; const commentMediaInfo = getCommentMediaInfo(post); const { type, url } = commentMediaInfo || {}; const hasThumbnail = getHasThumbnail(commentMediaInfo, link); const [showThumbnail, setShowThumbnail] = useState(true); const replies = useReplies(post); const visibleLinkCount = useCountLinksInReplies(post, 5); const totalLinkCount = useCountLinksInReplies(post); const repliesCount = pinned ? replyCount : replyCount - 5; const linkCount = pinned ? totalLinkCount : totalLinkCount - visibleLinkCount; const [menuBtnRotated, setMenuBtnRotated] = useState(false); return (

{!isInPostPage && ( )} {url && (
{t('link')}:{' '} {url.length > 30 ? url.slice(0, 30) + '...' : url} {' '} ({type}) {!showThumbnail && (type === 'iframe' || type === 'video' || type === 'audio') && ( {' '} [ setShowThumbnail(true)}> {t('close')} ] )} {showThumbnail && !hasThumbnail && ( {' '} [ setShowThumbnail(false)}> {t('open')} ] )}
{(hasThumbnail || (!hasThumbnail && !showThumbnail)) && ( )}
)}
{title && {displayTitle} } {displayName || 'Anonymous'} {authorRole && ` ## Board ${authorRole}`}{' '} {!(isDescription || isRules) && (u/{shortAddress}) } {getFormattedDate(timestamp)} {isDescription || isRules ? '' : ' '} {!(isDescription || isRules) && ( c/ {shortCid} )} {pinned && ( )} {locked && ( )} [{t('reply')}] setMenuBtnRotated(!menuBtnRotated)} style={{ transform: menuBtnRotated ? 'rotate(90deg)' : 'rotate(0deg)' }} > ▶
{!content &&
} {content && (
{content.length > 1000 && !isInPostPage && (
Comment too long. Click here to view the full text.
)}
)} {(replies.length > 5 || (pinned && replies.length > 0)) && !isInPostPage && ( {repliesCount} replies {linkCount > 0 && `and ${linkCount} links`} omitted.{' '} Click here to view. )} {!(pinned && !isInPostPage) && replies && (showAllReplies ? replies : replies.slice(-5)).map((reply, index) => (
))}
); }; const ReplyDesktop = ({ reply, roles }: PostProps) => { const { t } = useTranslation(); const { author, content, link, linkHeight, linkWidth, parentCid, pinned, postCid, shortCid, subplebbitAddress, timestamp } = reply || {}; const { address, displayName, shortAddress } = author || {}; const authorRole = roles?.[address]?.role; const commentMediaInfo = getCommentMediaInfo(reply); const { type, url } = commentMediaInfo || {}; const embedUrl = url && new URL(url); const hasThumbnail = getHasThumbnail(commentMediaInfo, link); const [showThumbnail, setShowThumbnail] = useState(true); const isReplyingToReply = postCid !== parentCid; const [menuBtnRotated, setMenuBtnRotated] = useState(false); return (
{'>>'}
{displayName || 'Anonymous'} {authorRole && ` ## Board ${authorRole}`}{' '} (u/{shortAddress}) {getFormattedDate(timestamp)} c/ {shortCid} {pinned && ( )} setMenuBtnRotated(!menuBtnRotated)} style={{ transform: menuBtnRotated ? 'rotate(90deg)' : 'rotate(0deg)' }} > ▶
{url && (
{t('link')}:{' '} {link.length > 30 ? link?.slice(0, 30) + '...' : link} {!showThumbnail && (type === 'iframe' || type === 'video' || type === 'audio') && ( {' '} [ setShowThumbnail(true)}> {t('close')} ] )} {showThumbnail && !hasThumbnail && embedUrl && canEmbed(embedUrl) && ( {' '} [ setShowThumbnail(false)}> {t('open')} ] )}
{(hasThumbnail || (!hasThumbnail && !showThumbnail)) && ( )}
)} {content && (
{isReplyingToReply && ( <> {`c/${Plebbit.getShortCid(parentCid)}`}
)}
)}
); }; const PostMobile = ({ post, roles, showAllReplies }: PostProps) => { const { t } = useTranslation(); const { author, cid, content, link, linkHeight, linkWidth, locked, pinned, replyCount, shortCid, subplebbitAddress, timestamp, title } = post || {}; const { address, displayName, shortAddress } = author || {}; const authorRole = roles?.[address]?.role; const { isDescription, isRules } = post || {}; // custom properties, not from api const linkCount = useCountLinksInReplies(post); const isInPostPage = isPostPageView(useLocation().pathname, useParams()); const displayTitle = title && title.length > 30 ? title?.slice(0, 30) + '(...)' : title; const displayContent = content && !isInPostPage && content.length > 1000 ? content?.slice(0, 1000) : content; const commentMediaInfo = getCommentMediaInfo(post); const hasThumbnail = getHasThumbnail(commentMediaInfo, link); const [showThumbnail, setShowThumbnail] = useState(true); const replies = useReplies(post); return (

... {displayName || 'Anonymous'} {authorRole && ` ## Board ${authorRole}`}{' '} {!(isDescription || isRules) && (u/{shortAddress || address?.slice(0, 12) + '...'})} {pinned && ( )} {locked && ( )} {title && ( <>
{displayTitle} )}
{getFormattedDate(timestamp)}{' '} {!(isDescription || isRules) && ( <> c/ {shortCid} )}
{(hasThumbnail || link) && ( )} {content && (
{content.length > 1000 && !isInPostPage && (
Comment too long. Click here to view the full text.
)}
)}
{!isInPostPage && (
{replyCount > 0 && `${replyCount} Replies`} {linkCount > 0 && ` / ${linkCount} Links`} {t('view_thread')}
)}
{!(pinned && !isInPostPage) && replies && (showAllReplies ? replies : replies.slice(-5)).map((reply, index) => (
))}
); }; const ReplyMobile = ({ reply, roles }: PostProps) => { const { t } = useTranslation(); const { author, content, link, linkHeight, linkWidth, parentCid, pinned, postCid, shortCid, subplebbitAddress, timestamp } = reply || {}; const { address, displayName, shortAddress } = author || {}; const authorRole = roles?.[address]?.role; const commentMediaInfo = getCommentMediaInfo(reply); const hasThumbnail = getHasThumbnail(commentMediaInfo, link); const [showThumbnail, setShowThumbnail] = useState(true); const isReplyingToReply = postCid !== parentCid; return (
... {displayName || 'Anonymous'} {authorRole && ` ## Board ${authorRole}`}{' '} (u/{shortAddress}) {pinned && ( )} {getFormattedDate(timestamp)} c/ {shortCid}
{(hasThumbnail || link) && ( )} {content && (
{isReplyingToReply && ( <> {`c/${Plebbit.getShortCid(parentCid)}`}
)}
)}
); }; const Post = ({ post, showAllReplies = false }: PostProps) => { const subplebbit = useSubplebbit({ subplebbitAddress: post?.subplebbitAddress }); const isMobile = useWindowWidth() < 640; return (
{isMobile ? ( ) : ( )}
); }; export default Post;