use-catalog-feed-rows.ts
1 import { useMemo } from 'react'; 2 import { useTranslation } from 'react-i18next'; 3 import { useParams, useLocation } from 'react-router-dom'; 4 import { useAccountComments, Subplebbit } from '@plebbit/plebbit-react-hooks'; 5 import useInterfaceSettingsStore from '../stores/use-interface-settings-store'; 6 import { getCommentMediaInfo, getHasThumbnail } from '../lib/utils/media-utils'; 7 import { isAllView } from '../lib/utils/view-utils'; 8 import { useMultisubMetadata } from './use-default-subplebbits'; 9 import _ from 'lodash'; 10 11 const useCatalogFeedRows = (columnCount: number, feed: any, isFeedLoaded: boolean, subplebbit: Subplebbit) => { 12 const { t } = useTranslation(); 13 const { address, createdAt, description, rules, shortAddress, suggested, title } = subplebbit || {}; 14 const { avatarUrl } = suggested || {}; 15 const { hideThreadsWithoutImages } = useInterfaceSettingsStore(); 16 17 const location = useLocation(); 18 const isInAllView = isAllView(location.pathname, useParams()); 19 const multisub = useMultisubMetadata(); 20 21 const { accountComments } = useAccountComments(); 22 23 const feedWithFakePostsOnTop = useMemo(() => { 24 if (!isFeedLoaded) { 25 return []; // prevent rules and description from appearing while feed is loading 26 } 27 28 if (!description && !rules && !isInAllView) { 29 return feed; 30 } 31 32 const _feed = [...feed]; 33 34 // show account comments instantly in the feed once published (cid defined), instead of waiting for the feed to update 35 const filteredComments = accountComments.filter((comment) => { 36 const { cid, deleted, link, postCid, removed, state, subplebbitAddress, timestamp } = comment || {}; 37 const commentMediaInfo = getCommentMediaInfo(comment); 38 const isMediaShowed = getHasThumbnail(commentMediaInfo, link); 39 40 return ( 41 !deleted && 42 !removed && 43 timestamp > Date.now() - 60 * 60 * 1000 && 44 state === 'succeeded' && 45 (!hideThreadsWithoutImages || (hideThreadsWithoutImages && isMediaShowed)) && 46 cid && 47 cid === postCid && 48 subplebbitAddress === address && 49 !_feed.some((feedItem) => feedItem.cid === cid) 50 ); 51 }); 52 53 // show newest account comment at the top of the feed but after pinned posts 54 const lastPinnedIndex = _feed.map((post) => post.pinned).lastIndexOf(true); 55 if (filteredComments.length > 0) { 56 _feed.splice( 57 lastPinnedIndex + 1, 58 0, 59 ...filteredComments.map((comment) => ({ 60 ...comment, 61 isAccountComment: true, 62 })), 63 ); 64 } 65 66 // add subplebbit description and rules as fake posts at the top of the feed 67 if (description && description.length > 0) { 68 _feed.unshift({ 69 isDescription: true, 70 subplebbitAddress: address, 71 timestamp: createdAt, 72 author: { displayName: `## ${t('board_mods')}` }, 73 content: isInAllView ? multisub?.description : description, 74 link: avatarUrl, 75 title: t('welcome_to_board', { board: isInAllView ? multisub?.title : title || `p/${shortAddress}`, interpolation: { escapeValue: false } }), 76 pinned: true, 77 locked: true, 78 }); 79 } 80 81 // rules are shown in description thread if both are set 82 if (rules && rules.length > 0 && !description) { 83 _feed.unshift({ 84 isRules: true, 85 subplebbitAddress: address, 86 timestamp: createdAt, 87 author: { displayName: `## ${t('board_mods')}` }, 88 content: rules.map((rule: string, index: number) => `${index + 1}. ${rule}`).join('\n'), 89 title: _.capitalize(t('rules')), 90 pinned: true, 91 locked: true, 92 }); 93 } 94 95 return _feed; 96 }, [accountComments, feed, description, rules, address, isFeedLoaded, createdAt, title, shortAddress, avatarUrl, t, isInAllView, multisub, hideThreadsWithoutImages]); 97 98 const rows = useMemo(() => { 99 const rows = []; 100 for (let i = 0; i < feedWithFakePostsOnTop.length; i += columnCount) { 101 rows.push(feedWithFakePostsOnTop.slice(i, i + columnCount)); 102 } 103 return rows; 104 }, [feedWithFakePostsOnTop, columnCount]); 105 106 return rows; 107 }; 108 109 export default useCatalogFeedRows;