/ src / hooks / use-catalog-feed-rows.ts
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;