import { useTranslation } from 'react-i18next'; import { Link, useLocation, useNavigate, useParams } from 'react-router-dom'; import { useAccountComment, useSubscribe } from '@plebbit/plebbit-react-hooks'; import useSubplebbitsPagesStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits-pages'; import { isAllView, isCatalogView, isModView, isModQueueView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils'; import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits'; import { getBoardPath, isDirectoryBoard } from '../../lib/utils/route-utils'; import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address'; import useCatalogFiltersStore from '../../stores/use-catalog-filters-store'; import useCatalogStyleStore from '../../stores/use-catalog-style-store'; import useFeedResetStore from '../../stores/use-feed-reset-store'; import useSortingStore from '../../stores/use-sorting-store'; import useAllFeedFilterStore from '../../stores/use-all-feed-filter-store'; import useCountLinksInReplies from '../../hooks/use-count-links-in-replies'; import useIsMobile from '../../hooks/use-is-mobile'; import useTimeFilter from '../../hooks/use-time-filter'; import CatalogFilters from '../catalog-filters'; import CatalogSearch from '../catalog-search'; import Tooltip from '../tooltip'; import styles from './board-buttons.module.css'; import _ from 'lodash'; interface BoardButtonsProps { address?: string | undefined; isInAllView?: boolean; isInCatalogView?: boolean; isInSubscriptionsView?: boolean; isInModView?: boolean; isInModQueueView?: boolean; isTopbar?: boolean; } const CatalogButton = ({ address, isInAllView, isInSubscriptionsView, isInModView }: BoardButtonsProps) => { const { t } = useTranslation(); const params = useParams(); const defaultSubplebbits = useDefaultSubplebbits(); const createCatalogLink = () => { if (isInAllView) { if (params?.timeFilterName) return `/all/catalog/${params.timeFilterName}`; return `/all/catalog`; } else if (isInSubscriptionsView) { if (params?.timeFilterName) return `/subs/catalog/${params.timeFilterName}`; return `/subs/catalog`; } else if (isInModView) { if (params?.timeFilterName) return `/mod/catalog/${params.timeFilterName}`; return `/mod/catalog`; } let boardPath = ''; if (address) { boardPath = getBoardPath(address, defaultSubplebbits); } else if (Array.isArray(defaultSubplebbits) && defaultSubplebbits.length > 0 && defaultSubplebbits[0]?.address) { boardPath = getBoardPath(defaultSubplebbits[0].address, defaultSubplebbits); } return `/${boardPath}/catalog`; }; return ( ); }; const SubscribeButton = ({ address }: BoardButtonsProps) => { const { t } = useTranslation(); const { subscribed, subscribe, unsubscribe } = useSubscribe({ subplebbitAddress: address }); return ( ); }; const ReturnButton = ({ address, isInAllView, isInSubscriptionsView, isInModView, isInModQueueView }: BoardButtonsProps) => { const { t } = useTranslation(); const params = useParams(); const defaultSubplebbits = useDefaultSubplebbits(); const createReturnLink = () => { if (isInAllView) { if (params?.timeFilterName) return `/all/${params.timeFilterName}`; return `/all`; } else if (isInSubscriptionsView) { if (params?.timeFilterName) return `/subs/${params.timeFilterName}`; return `/subs`; } else if (isInModQueueView) { // If in mod queue view, return to /mod or /:boardIdentifier if (params?.boardIdentifier) { return `/${params.boardIdentifier}`; } return `/mod`; } else if (isInModView) { if (params?.timeFilterName) return `/mod/${params.timeFilterName}`; return `/mod`; } let boardPath = ''; if (address) { boardPath = getBoardPath(address, defaultSubplebbits); } else if (Array.isArray(defaultSubplebbits) && defaultSubplebbits.length > 0 && defaultSubplebbits[0]?.address) { boardPath = getBoardPath(defaultSubplebbits[0].address, defaultSubplebbits); } return `/${boardPath}`; }; return ( ); }; const VoteButton = () => { const { t } = useTranslation(); const params = useParams(); const defaultSubplebbits = useDefaultSubplebbits(); // Get the boardIdentifier from params (try boardIdentifier first, then subplebbitAddress for backward compatibility) const boardIdentifier = params.boardIdentifier || params.subplebbitAddress; // Only render the vote button if we're on a directory board route if (!boardIdentifier || !isDirectoryBoard(boardIdentifier, defaultSubplebbits)) { return null; } const message = `Not available yet. Users will be able to submit and vote for boards competing for directory slots (like /${boardIdentifier}). The highest-voted board becomes the directory board.`; return ( ); }; const RefreshButton = () => { const { t } = useTranslation(); const reset = useFeedResetStore((state) => state.reset); return ( ); }; const UpdateButton = () => { const { t } = useTranslation(); const isMobile = useIsMobile(); const handleManualUpdate = () => { window.alert('Manual updates are not available yet. Posts update automatically every ~2 minutes.'); }; return ( <> {/* TODO: Implement update button once available in API */} {isMobile ? ( ) : ( )} ); }; const AutoButton = () => { const { t } = useTranslation(); const isMobile = useIsMobile(); const handleManualUpdate = () => { window.alert('Manual updates are not available yet. Posts update automatically every ~2 minutes.'); }; return ( <> {isMobile ? ( ) : ( )} ); }; const SortOptions = () => { const { t } = useTranslation(); const { sortType, setSortType } = useSortingStore(); const handleSortChange = (event: React.ChangeEvent) => { const type = event.target.value as 'active' | 'new'; setSortType(type); }; return ( <> {t('sort_by')} ); }; const ImageSizeOptions = () => { const { t } = useTranslation(); const { imageSize, setImageSize } = useCatalogStyleStore(); return ( <> {t('image_size')}:  ); }; const ShowOPCommentOption = () => { const { t } = useTranslation(); const { showOPComment, setShowOPComment } = useCatalogStyleStore(); return ( <> {t('show_op_comment')}:  ); }; export const TimeFilter = ({ isInAllView, isInCatalogView, isInSubscriptionsView, isInModView, isTopbar = false }: BoardButtonsProps) => { const { t } = useTranslation(); const navigate = useNavigate(); const { timeFilterName, timeFilterNames } = useTimeFilter(); const changeTimeFilter = (event: React.ChangeEvent) => { const timeFilterName = event.target.value; const link = isInAllView ? isInCatalogView ? `/all/catalog/${timeFilterName}` : `/all/${timeFilterName}` : isInSubscriptionsView ? isInCatalogView ? `/subs/catalog/${timeFilterName}` : `/subs/${timeFilterName}` : isInModView ? isInCatalogView ? `/mod/catalog/${timeFilterName}` : `/mod/${timeFilterName}` : null; link && navigate(link); }; const { sortType } = useSortingStore(); const allTimeFilterNames = timeFilterName ? Array.from(new Set([timeFilterName, ...timeFilterNames])) : timeFilterNames; return ( <> {!isTopbar ? ( <> {isInCatalogView ? (sortType === 'active' ? t('last_bumped') : t('newer_than')) : t('last_bumped')}:  ) : ( <> )} ); }; const AllFeedFilter = () => { const { t } = useTranslation(); const { filter, setFilter } = useAllFeedFilterStore(); return ( <> {t('show')} ); }; export const MobileBoardButtons = () => { const { t } = useTranslation(); const params = useParams(); const location = useLocation(); const isInAllView = isAllView(location.pathname); const isInCatalogView = isCatalogView(location.pathname, params); const isInPendingPostPage = isPendingPostView(location.pathname, params); const isInPostView = isPostPageView(location.pathname, params); const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams()); const isInModView = isModView(location.pathname); const isInModQueueView = isModQueueView(location.pathname); const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any }); const resolvedAddress = useResolvedSubplebbitAddress(); const subplebbitAddress = resolvedAddress || accountComment?.subplebbitAddress; const { filteredCount, searchText } = useCatalogFiltersStore(); // Check if we should show the vote button (only for directory boards) const defaultSubplebbits = useDefaultSubplebbits(); const boardIdentifier = params.boardIdentifier || params.subplebbitAddress; const showVoteButton = boardIdentifier && isDirectoryBoard(boardIdentifier, defaultSubplebbits); return (
{isInPostView || isInPendingPostPage ? ( <> {showVoteButton && }
) : isInModQueueView ? ( <> ) : ( <> {isInCatalogView ? ( ) : ( )} {showVoteButton && } {!(isInAllView || isInSubscriptionsView || isInModView) && } {isInCatalogView && searchText ? ( {' '} — {t('search_results_for')}: {searchText} ) : ( isInCatalogView && filteredCount > 0 && ( {' '} — {t('filtered_threads')}: {filteredCount} ) )} {isInAllView && ( <>
)} {isInCatalogView && ( <>
)} )}
); }; const PostPageStats = () => { const { t } = useTranslation(); const params = useParams(); const comment = useSubplebbitsPagesStore((state) => state.comments[params?.commentCid as string]); const { closed, pinned, replyCount } = comment || {}; const linkCount = useCountLinksInReplies(comment); const displayReplyCount = replyCount !== undefined ? replyCount.toString() : '?'; const replyCountTooltip = replyCount !== undefined ? _.capitalize(t('replies')) : t('loading'); return ( {pinned && `${_.capitalize(t('sticky'))} / `} {closed && `${_.capitalize(t('closed'))} / `} / ); }; export const DesktopBoardButtons = () => { const { t } = useTranslation(); const params = useParams(); const location = useLocation(); const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any }); const resolvedAddress = useResolvedSubplebbitAddress(); const subplebbitAddress = resolvedAddress || accountComment?.subplebbitAddress; const isInCatalogView = isCatalogView(location.pathname, params); const isInAllView = isAllView(location.pathname); const isInPendingPostPage = isPendingPostView(location.pathname, params); const isInPostView = isPostPageView(location.pathname, params); const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams()); const isInModView = isModView(location.pathname); const isInModQueueView = isModQueueView(location.pathname); const { filteredCount, searchText } = useCatalogFiltersStore(); // Check if we should show the vote button (only for directory boards) const defaultSubplebbits = useDefaultSubplebbits(); const boardIdentifier = params.boardIdentifier || params.subplebbitAddress; const showVoteButton = boardIdentifier && isDirectoryBoard(boardIdentifier, defaultSubplebbits); return ( <>
{isInPostView || isInPendingPostPage ? ( <> [ ] [ ] [ ] [ ] ) : isInModQueueView ? ( <> [ ] [ ] ) : ( <> {isInCatalogView ? ( <> [ ]{' '} ) : ( <> [ ]{' '} )} [] {showVoteButton && ( <> {' '} [] )} {isInCatalogView && searchText ? ( {' '} — {t('search_results_for')}: {searchText} ) : ( isInCatalogView && filteredCount > 0 && ( {' '} — {t('filtered_threads')}: {filteredCount} ) )} {isInCatalogView && ( <> )} {isInAllView && } {(isInAllView || isInSubscriptionsView || isInModView) && ( )} {!(isInAllView || isInSubscriptionsView || isInModView) && ( <> [ ] )}{' '} {isInCatalogView && ( <> [] )} )}
); }; const SearchOPsBar = () => { const { t } = useTranslation(); const navigate = useNavigate(); const params = useParams(); const location = useLocation(); const isInAllView = isAllView(location.pathname); const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams()); const isInModView = isModView(location.pathname); const defaultSubplebbits = useDefaultSubplebbits(); const resolvedAddress = useResolvedSubplebbitAddress(); const boardPath = resolvedAddress ? getBoardPath(resolvedAddress, defaultSubplebbits) : params?.boardIdentifier || params?.subplebbitAddress; const handleSearch = (event: React.KeyboardEvent) => { if (event.key === 'Enter') { const searchQuery = (event.target as HTMLInputElement).value.trim(); if (searchQuery) { let catalogUrl = ''; if (isInAllView) { catalogUrl = params?.timeFilterName ? `/all/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}` : `/all/catalog?q=${encodeURIComponent(searchQuery)}`; } else if (isInSubscriptionsView) { catalogUrl = params?.timeFilterName ? `/subs/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}` : `/subs/catalog?q=${encodeURIComponent(searchQuery)}`; } else if (isInModView) { catalogUrl = params?.timeFilterName ? `/mod/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}` : `/mod/catalog?q=${encodeURIComponent(searchQuery)}`; } else { catalogUrl = `/${boardPath}/catalog?q=${encodeURIComponent(searchQuery)}`; } navigate(catalogUrl); } } }; return ; };