refactor: migrate 5chan to the community hooks API (#1073)

* refactor(community-api): migrate 5chan to community hooks

* fix(review): address PR feedback

* fix(review): preserve legacy board context fallbacks

* fix(review): address latest bot feedback

* fix(review): use communityAddress in edit menu privileges
This commit is contained in:
Tommaso Casaburi
2026-03-13 13:25:10 +08:00
committed by GitHub
parent 9dc4d96d27
commit d7703953fb
105 changed files with 2659 additions and 1491 deletions
@@ -9,8 +9,8 @@ import BoardsBar from '../boards-bar';
const act = (React as { act?: (cb: () => void | Promise<void>) => void | Promise<void> }).act as (cb: () => void | Promise<void>) => void | Promise<void>;
const testState = vi.hoisted(() => ({
accountComment: undefined as { subplebbitAddress?: string } | undefined,
accountSubplebbitAddresses: ['music-posting.eth'] as string[],
accountComment: undefined as { communityAddress?: string; subplebbitAddress?: string } | undefined,
accountCommunityAddresses: ['music-posting.eth'] as string[],
directories: [
{ address: 'music-posting.eth', title: '/mu/ - Music' },
{ address: 'tech-posting.eth', title: '/g/ - Technology' },
@@ -21,7 +21,7 @@ const testState = vi.hoisted(() => ({
openBoardsBarEditModalMock: vi.fn(),
openCreateBoardModalMock: vi.fn(),
openDirectoryModalMock: vi.fn(),
resolvedSubplebbitAddress: 'music-posting.eth' as string | undefined,
resolvedCommunityAddress: 'music-posting.eth' as string | undefined,
showSubscriptionsInBoardsBar: true,
subscriptions: ['custom.eth'] as string[],
visibleDirectories: new Set<string>(['mu']),
@@ -68,8 +68,8 @@ vi.mock('@bitsocialnet/bitsocial-react-hooks/dist/stores/accounts', () => ({
}),
}));
vi.mock('../../../hooks/use-account-subplebbit-addresses', () => ({
useAccountSubplebbitAddresses: () => testState.accountSubplebbitAddresses,
vi.mock('../../../hooks/use-account-community-addresses', () => ({
useAccountCommunityAddresses: () => testState.accountCommunityAddresses,
}));
vi.mock('../../../hooks/use-directories', async () => {
@@ -81,13 +81,13 @@ vi.mock('../../../hooks/use-directories', async () => {
};
});
vi.mock('../../../hooks/use-resolved-subplebbit-address', () => ({
useBoardPath: (subplebbitAddress: string | undefined) => {
if (subplebbitAddress === 'music-posting.eth') return 'mu';
if (subplebbitAddress === 'tech-posting.eth') return 'g';
return subplebbitAddress;
vi.mock('../../../hooks/use-resolved-community-address', () => ({
useBoardPath: (communityAddress: string | undefined) => {
if (communityAddress === 'music-posting.eth') return 'mu';
if (communityAddress === 'tech-posting.eth') return 'g';
return communityAddress;
},
useResolvedSubplebbitAddress: () => testState.resolvedSubplebbitAddress,
useResolvedCommunityAddress: () => testState.resolvedCommunityAddress,
}));
vi.mock('../../../stores/use-create-board-modal-store', () => ({
@@ -150,7 +150,7 @@ describe('BoardsBar', () => {
beforeEach(() => {
vi.clearAllMocks();
testState.accountComment = undefined;
testState.accountSubplebbitAddresses = ['music-posting.eth'];
testState.accountCommunityAddresses = ['music-posting.eth'];
testState.directories = [
{ address: 'music-posting.eth', title: '/mu/ - Music' },
{ address: 'tech-posting.eth', title: '/g/ - Technology' },
@@ -161,7 +161,7 @@ describe('BoardsBar', () => {
testState.openCreateBoardModalMock.mockReset();
testState.openDirectoryModalMock.mockReset();
testState.initializeVisibilityMock.mockReset();
testState.resolvedSubplebbitAddress = 'music-posting.eth';
testState.resolvedCommunityAddress = 'music-posting.eth';
testState.showSubscriptionsInBoardsBar = true;
testState.subscriptions = ['custom.eth'];
testState.visibleDirectories = new Set(['mu']);
@@ -258,4 +258,15 @@ describe('BoardsBar', () => {
expect(mobileNav?.style.transform).toBe('translateY(-23px)');
});
it('keeps the mobile board context for legacy account comments', async () => {
testState.resolvedCommunityAddress = undefined;
testState.accountComment = { subplebbitAddress: 'music-posting.eth' };
await renderBoardsBar('/pending/7');
const select = container.querySelector('select');
expect(select).toBeTruthy();
expect(Array.from(select?.querySelectorAll('option') ?? []).some((option) => option.value === 'mu')).toBe(true);
});
});
+21 -20
View File
@@ -5,10 +5,11 @@ import getShortAddress from '../../lib/get-short-address';
import { useAccountComment } from '@bitsocialnet/bitsocial-react-hooks';
import useAccountsStore from '@bitsocialnet/bitsocial-react-hooks/dist/stores/accounts';
import { isAllView, isCatalogView, isModView, isSubscriptionsView } from '../../lib/utils/view-utils';
import { useAccountSubplebbitAddresses } from '../../hooks/use-account-subplebbit-addresses';
import { useAccountCommunityAddresses } from '../../hooks/use-account-community-addresses';
import { useDirectories, useDirectoriesMetadata, DirectoryCommunity } from '../../hooks/use-directories';
import { useBoardPath, useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
import { useBoardPath, useResolvedCommunityAddress } from '../../hooks/use-resolved-community-address';
import { getBoardPath, extractDirectoryFromTitle } from '../../lib/utils/route-utils';
import { getCommentCommunityAddress } from '../../lib/utils/comment-utils';
import useCreateBoardModalStore from '../../stores/use-create-board-modal-store';
import useBoardsBarEditModalStore from '../../stores/use-boards-bar-edit-modal-store';
import useBoardsBarVisibilityStore from '../../stores/use-boards-bar-visibility-store';
@@ -81,9 +82,9 @@ const SearchBar = ({ setShowSearchBar }: { setShowSearchBar: (show: boolean) =>
// Helper function to find board address by directory code
const findBoardAddressByCode = (code: string, directories: DirectoryCommunity[]): string | null => {
const entry = directories.find((subplebbit) => {
if (!subplebbit.title) return false;
const directory = extractDirectoryFromTitle(subplebbit.title);
const entry = directories.find((community) => {
if (!community.title) return false;
const directory = extractDirectoryFromTitle(community.title);
return directory === code;
});
return entry?.address || null;
@@ -117,7 +118,7 @@ const BoardsBarDesktop = () => {
},
);
const accountSubplebbitAddresses = useAccountSubplebbitAddresses();
const accountCommunityAddresses = useAccountCommunityAddresses();
// Show all subscriptions when enabled; no separate per-address tracking (avoids drift when subscribing from board-buttons)
const visibleSubscriptionAddresses = showSubscriptionsInBoardsBar ? subscriptions : [];
@@ -205,7 +206,7 @@ const BoardsBarDesktop = () => {
<div className={styles.boardNavDesktop}>
<span className={styles.boardList}>
[<Link to='/all'>all</Link> / <Link to='/subs'>subs</Link>
{accountSubplebbitAddresses.length > 0 && (
{accountCommunityAddresses.length > 0 && (
<>
{' '}
/ <Link to='/mod'>mod</Link>
@@ -300,12 +301,12 @@ const BoardsBarDesktop = () => {
);
};
const BoardsBarMobile = ({ subplebbitAddress }: { subplebbitAddress?: string }) => {
const BoardsBarMobile = ({ communityAddress }: { communityAddress?: string }) => {
const { t } = useTranslation();
const navigate = useNavigate();
const directories = useDirectories();
const directoriesMetadata = useDirectoriesMetadata();
const displaySubplebbitAddress = subplebbitAddress && subplebbitAddress.length > 30 ? subplebbitAddress.slice(0, 30).concat('...') : subplebbitAddress;
const displayCommunityAddress = communityAddress && communityAddress.length > 30 ? communityAddress.slice(0, 30).concat('...') : communityAddress;
const [showSearchBar, setShowSearchBar] = useState(false);
// Filter to only show directory boards (those with titles)
@@ -317,13 +318,13 @@ const BoardsBarMobile = ({ subplebbitAddress }: { subplebbitAddress?: string })
const isInCatalogView = isCatalogView(location.pathname, params);
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
const isInModView = isModView(location.pathname);
const boardPath = useBoardPath(subplebbitAddress);
const selectValue = isInAllView ? 'all' : isInSubscriptionsView ? 'subs' : isInModView ? 'mod' : boardPath || subplebbitAddress;
const boardPath = useBoardPath(communityAddress);
const selectValue = isInAllView ? 'all' : isInSubscriptionsView ? 'subs' : isInModView ? 'mod' : boardPath || communityAddress;
const accountSubplebbitAddresses = useAccountSubplebbitAddresses();
const accountCommunityAddresses = useAccountCommunityAddresses();
// Check if current subplebbit is a directory board
const currentIsDirectoryBoard = directoryBoards.some((board) => board.address === subplebbitAddress);
// Check if current community is a directory board
const currentIsDirectoryBoard = directoryBoards.some((board) => board.address === communityAddress);
// Build multiboards with full titles, then combine with directory boards and sort alphabetically
const sortedBoardOptions = useMemo(() => {
@@ -334,7 +335,7 @@ const BoardsBarMobile = ({ subplebbitAddress }: { subplebbitAddress?: string })
const multiboards: Array<{ value: string; label: string }> = [
{ value: 'all', label: allTitle },
{ value: 'subs', label: subsTitle },
...(accountSubplebbitAddresses.length > 0 ? [{ value: 'mod', label: modTitle }] : []),
...(accountCommunityAddresses.length > 0 ? [{ value: 'mod', label: modTitle }] : []),
];
const directoryOptions = directoryBoards.map((board) => {
@@ -343,7 +344,7 @@ const BoardsBarMobile = ({ subplebbitAddress }: { subplebbitAddress?: string })
});
return [...multiboards, ...directoryOptions].sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: 'base' }));
}, [directoriesMetadata?.title, t, accountSubplebbitAddresses.length, directoryBoards]);
}, [directoriesMetadata?.title, t, accountCommunityAddresses.length, directoryBoards]);
const boardSelect = (
<select
@@ -353,7 +354,7 @@ const BoardsBarMobile = ({ subplebbitAddress }: { subplebbitAddress?: string })
navigate(`/${value}${isInCatalogView ? '/catalog' : ''}`);
}}
>
{!currentIsDirectoryBoard && subplebbitAddress && <option value={subplebbitAddress}>{displaySubplebbitAddress}</option>}
{!currentIsDirectoryBoard && communityAddress && <option value={communityAddress}>{displayCommunityAddress}</option>}
{sortedBoardOptions.map((opt) => (
<option key={opt.value} value={opt.value}>
{opt.label}
@@ -415,13 +416,13 @@ const BoardsBar = () => {
const params = useParams();
const commentIndex = params?.accountCommentIndex ? parseInt(params.accountCommentIndex) : undefined;
const accountComment = useAccountComment({ commentIndex });
const resolvedSubplebbitAddress = useResolvedSubplebbitAddress();
const subplebbitAddress = resolvedSubplebbitAddress || accountComment?.subplebbitAddress;
const resolvedCommunityAddress = useResolvedCommunityAddress();
const communityAddress = resolvedCommunityAddress || getCommentCommunityAddress(accountComment);
return (
<>
<BoardsBarDesktop />
<BoardsBarMobile subplebbitAddress={subplebbitAddress} />
<BoardsBarMobile communityAddress={communityAddress} />
</>
);
};