From 616fea39fbc0de79973489ce66fe8bdac46c2648 Mon Sep 17 00:00:00 2001 From: Tommaso Casaburi Date: Thu, 21 May 2026 00:05:29 +0700 Subject: [PATCH] fix(directory): use resolved board for directory feeds --- src/__tests__/app.test.tsx | 31 ++++++++- src/app.tsx | 8 +-- .../use-resolved-community-address.test.tsx | 64 +++++++++++++++++-- src/hooks/use-directory-list.ts | 43 +++++++++++-- src/hooks/use-resolved-community-address.ts | 48 ++++++++++++-- src/views/archive/archive.tsx | 10 +-- src/views/board/__tests__/board.test.tsx | 24 ++++++- src/views/board/board.tsx | 10 +-- src/views/catalog/catalog.tsx | 10 +-- 9 files changed, 198 insertions(+), 50 deletions(-) diff --git a/src/__tests__/app.test.tsx b/src/__tests__/app.test.tsx index 51b224d2..d25e81e7 100644 --- a/src/__tests__/app.test.tsx +++ b/src/__tests__/app.test.tsx @@ -25,7 +25,7 @@ const testState = vi.hoisted(() => ({ directories: [ { address: 'music-posting.eth', title: '/mu/ - Music', nsfw: false }, { address: 'tech-posting.eth', title: '/g/ - Technology', nsfw: false }, - ] as Array<{ address: string; title?: string; nsfw?: boolean }>, + ] as Array<{ address: string; title?: string; nsfw?: boolean; directoryCode?: string }>, initSnowMock: vi.fn(), isMobile: false, isSpecialEnabled: false, @@ -41,6 +41,8 @@ const testState = vi.hoisted(() => ({ threadNumber: null, } as ReplyModalShape, resolvedCommunityAddress: undefined as string | undefined, + resolvedDirectoryBoardPath: undefined as string | undefined, + isDirectoryCandidate: false, communities: {} as Record, useThemeMock: vi.fn(), })); @@ -72,7 +74,11 @@ vi.mock('../hooks/use-is-mobile', () => ({ })); vi.mock('../hooks/use-resolved-community-address', () => ({ - useResolvedCommunityAddress: () => testState.resolvedCommunityAddress, + useResolvedCommunityAddress: (boardIdentifier?: string) => testState.resolvedCommunityAddress ?? boardIdentifier, + useResolvedDirectoryBoardPath: () => ({ + boardPath: testState.resolvedDirectoryBoardPath, + isDirectoryCandidate: testState.isDirectoryCandidate, + }), })); vi.mock('../hooks/use-theme', () => ({ @@ -340,6 +346,8 @@ describe('App', () => { threadNumber: null, } as ReplyModalShape; testState.resolvedCommunityAddress = undefined; + testState.resolvedDirectoryBoardPath = undefined; + testState.isDirectoryCandidate = false; testState.communities = {}; testState.useThemeMock.mockReset(); testState.closeCreateBoardModalMock.mockReset(); @@ -416,6 +424,25 @@ describe('App', () => { expect(container.querySelector('[data-testid="post-view"]')).toBeTruthy(); }); + it('canonicalizes a direct route for the current resolved directory board', async () => { + testState.resolvedDirectoryBoardPath = 'biz'; + testState.isDirectoryCandidate = true; + + await renderApp('/bizraelis.bso/thread/comment-1?focus=1'); + + expect(latestLocation).toBe('/biz/thread/comment-1?focus=1'); + expect(container.querySelector('[data-testid="post-view"]')).toBeTruthy(); + }); + + it('does not canonicalize a directory candidate address when another board is resolved', async () => { + testState.directories = [{ address: 'business-and-finance.bso', directoryCode: 'biz', title: '/biz/ - Business & Finance', nsfw: false }]; + testState.isDirectoryCandidate = true; + + await renderApp('/business-and-finance.bso?focus=1'); + + expect(latestLocation).toBe('/business-and-finance.bso?focus=1'); + }); + it('routes invalid mod aliases and unknown mod paths to not-found', async () => { await renderApp('/mu/modqueue'); expect(latestLocation).toBe('/not-found'); diff --git a/src/app.tsx b/src/app.tsx index 2e6d8ed5..81e762b1 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -14,12 +14,11 @@ import { useAccountCommunityAddresses } from './hooks/use-account-community-addr import useTheme from './hooks/use-theme'; import { useDirectories } from './hooks/use-directories'; import { useCommunityIdentifier } from './hooks/use-community-identifiers'; -import { useResolvedCommunityAddress } from './hooks/use-resolved-community-address'; +import { useResolvedCommunityAddress, useResolvedDirectoryBoardPath } from './hooks/use-resolved-community-address'; import useSafeAccountComment from './hooks/use-safe-account-comment'; import { getCommentCommunityAddress } from './lib/utils/comment-utils'; import { getBoardPath, - getCommunityAddress, isBoardModRoute, isDirectoryBoard, isArchiveRoute, @@ -77,7 +76,8 @@ const BoardLayout = () => { const isInSubscriptionsView = isSubscriptionsView(pathname, useParams()); const isInModView = isModView(pathname); const directories = useDirectories(); - const communityAddress = boardIdentifier ? getCommunityAddress(boardIdentifier, directories) : undefined; + const communityAddress = useResolvedCommunityAddress(boardIdentifier); + const { boardPath: resolvedDirectoryBoardPath, isDirectoryCandidate } = useResolvedDirectoryBoardPath(boardIdentifier); const pendingPost = useSafeAccountComment({ commentIndex: accountCommentIndex }); const pendingPostCommunityAddress = getCommentCommunityAddress(pendingPost); const { closeCreateBoardModal } = useCreateBoardModalStore(); @@ -128,7 +128,7 @@ const BoardLayout = () => { // Normalize address URLs to directory codes: /anime-and-manga.eth/thread/xxx -> /a/thread/xxx if (boardIdentifier && !isDirectoryBoard(boardIdentifier, directories)) { - const canonicalBoardIdentifier = getBoardPath(boardIdentifier, directories); + const canonicalBoardIdentifier = resolvedDirectoryBoardPath ?? (isDirectoryCandidate ? boardIdentifier : getBoardPath(boardIdentifier, directories)); if (canonicalBoardIdentifier !== boardIdentifier) { const canonicalPath = pathname.replace(`/${boardIdentifier}`, `/${canonicalBoardIdentifier}`); return ; diff --git a/src/hooks/__tests__/use-resolved-community-address.test.tsx b/src/hooks/__tests__/use-resolved-community-address.test.tsx index 03700fd0..805bbaea 100644 --- a/src/hooks/__tests__/use-resolved-community-address.test.tsx +++ b/src/hooks/__tests__/use-resolved-community-address.test.tsx @@ -2,13 +2,14 @@ import * as React from 'react'; import { createElement } from 'react'; import { createRoot, type Root } from 'react-dom/client'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { useResolvedCommunityAddress } from '../use-resolved-community-address'; +import { useResolvedCommunityAddress, useResolvedDirectoryBoardPath } from '../use-resolved-community-address'; (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; const act = (React as { act?: (cb: () => void | Promise) => void | Promise }).act as (cb: () => void | Promise) => void | Promise; const testState = vi.hoisted(() => ({ boardIdentifier: 'biz', + boardIdentifierOverride: undefined as string | undefined, directories: [ { address: 'business-and-finance.bso', @@ -20,7 +21,7 @@ const testState = vi.hoisted(() => ({ directoryCode: 'biz', boards: [ { address: 'business-and-finance.bso', score: 100 }, - { address: 'backup-business.bso', score: 10 }, + { address: 'bizraelis.bso', score: 10 }, ], }, offlineStates: {} as Record, @@ -37,6 +38,7 @@ vi.mock('react-router-dom', async () => { vi.mock('../use-directories', () => ({ useDirectories: () => testState.directories, + normalizeBoardAddress: (address: string) => address.replace(/\.(bso|eth)$/, ''), })); vi.mock('../use-directory-list', async () => { @@ -56,11 +58,13 @@ vi.mock('../../stores/use-community-offline-store', () => ({ })); let latestValue: string | undefined; +let latestDirectoryBoardPath: { boardPath: string | undefined; isDirectoryCandidate: boolean }; let container: HTMLDivElement; let root: Root; const HookHarness = () => { - latestValue = useResolvedCommunityAddress(); + latestValue = useResolvedCommunityAddress(testState.boardIdentifierOverride); + latestDirectoryBoardPath = useResolvedDirectoryBoardPath(testState.boardIdentifier); return null; }; @@ -75,7 +79,9 @@ describe('useResolvedCommunityAddress', () => { vi.useFakeTimers(); vi.setSystemTime(new Date('2024-01-01T00:00:10Z')); latestValue = undefined; + latestDirectoryBoardPath = { boardPath: undefined, isDirectoryCandidate: false }; testState.boardIdentifier = 'biz'; + testState.boardIdentifierOverride = undefined; testState.offlineStates = {}; testState.offlineSelections = []; @@ -99,7 +105,7 @@ describe('useResolvedCommunityAddress', () => { await renderHook(); - expect(latestValue).toBe('backup-business.bso'); + expect(latestValue).toBe('bizraelis.bso'); }); it('keeps a higher-ranked directory board when its last update is newer than 30 minutes', async () => { @@ -125,7 +131,7 @@ describe('useResolvedCommunityAddress', () => { await renderHook(); expect(latestValue).toBe('custom-board.bso'); - expect(testState.offlineSelections).toEqual([undefined]); + expect(testState.offlineSelections.every((selection) => selection === undefined)).toBe(true); }); it('switches away from a directory board when it crosses the offline threshold while mounted', async () => { @@ -143,6 +149,52 @@ describe('useResolvedCommunityAddress', () => { vi.advanceTimersByTime(2 * 60 * 1000); }); - expect(latestValue).toBe('backup-business.bso'); + expect(latestValue).toBe('bizraelis.bso'); + }); + + it('uses an explicit directory identifier for cached board feeds', async () => { + testState.boardIdentifier = 'all'; + testState.boardIdentifierOverride = 'biz'; + testState.offlineStates = { + 'business-and-finance.bso': { + updatedAt: 1_704_067_210 - 31 * 60, + }, + }; + + await renderHook(); + + expect(latestValue).toBe('bizraelis.bso'); + }); + + it('canonicalizes the direct address for the current directory winner', async () => { + testState.boardIdentifier = 'bizraelis.bso'; + testState.offlineStates = { + 'business-and-finance.bso': { + updatedAt: 1_704_067_210 - 31 * 60, + }, + }; + + await renderHook(); + + expect(latestDirectoryBoardPath).toEqual({ + boardPath: 'biz', + isDirectoryCandidate: true, + }); + }); + + it('does not canonicalize a directory candidate address when it is not the current winner', async () => { + testState.boardIdentifier = 'business-and-finance.bso'; + testState.offlineStates = { + 'business-and-finance.bso': { + updatedAt: 1_704_067_210 - 31 * 60, + }, + }; + + await renderHook(); + + expect(latestDirectoryBoardPath).toEqual({ + boardPath: undefined, + isDirectoryCandidate: true, + }); }); }); diff --git a/src/hooks/use-directory-list.ts b/src/hooks/use-directory-list.ts index fef0924e..9df4eb71 100644 --- a/src/hooks/use-directory-list.ts +++ b/src/hooks/use-directory-list.ts @@ -1,6 +1,7 @@ import { useEffect, useMemo, useState } from 'react'; -import { DirectoryCommunity, useDirectories } from './use-directories'; +import { type DirectoryCommunity, normalizeBoardAddress, useDirectories } from './use-directories'; import { type DirectoryList, type DirectoryListBoard, normalizeDirectoryList, sortDirectoryBoardsByRank } from '../lib/utils/directory-list-utils'; +import directoryListsData from '../data/5chan-directory-lists.json'; export type { DirectoryListBoard } from '../lib/utils/directory-list-utils'; @@ -28,6 +29,33 @@ const moduleCaches = new Map(); const inFlightFetches = new Map>(); const lastFetchSuccessAt = new Map(); const lastFetchAttemptAt = new Map(); +let vendoredDirectoryListsCache: DirectoryList[] | null = null; + +const getVendoredDirectoryLists = (): DirectoryList[] => { + if (vendoredDirectoryListsCache) return vendoredDirectoryListsCache; + + const directories = Array.isArray(directoryListsData.directories) ? directoryListsData.directories : []; + vendoredDirectoryListsCache = directories.flatMap((directory) => { + const directoryCode = typeof directory.directoryCode === 'string' ? directory.directoryCode : undefined; + if (!directoryCode) return []; + const normalized = normalizeDirectoryList(directory, directoryCode); + return normalized ? [normalized] : []; + }); + + return vendoredDirectoryListsCache; +}; + +const getVendoredDirectoryList = (directoryCode: string): DirectoryList | null => + getVendoredDirectoryLists().find((directory) => directory.directoryCode === directoryCode) ?? null; + +export const getDirectoryCodeForBoardAddress = (address: string | undefined): string | undefined => { + if (!address) return undefined; + + const normalizedAddress = normalizeBoardAddress(address); + return getVendoredDirectoryLists().find((directory) => + directory.boards.some((board) => normalizeBoardAddress(board.address) === normalizedAddress || board.publicKey === address), + )?.directoryCode; +}; const synthesizeFromMainDirectory = (directoryCode: string, directories: DirectoryCommunity[]): DirectoryList | null => { const match = directories.find((community) => community.directoryCode === directoryCode); @@ -48,6 +76,9 @@ const synthesizeFromMainDirectory = (directoryCode: string, directories: Directo }; }; +const getFallbackDirectoryList = (directoryCode: string, directories: DirectoryCommunity[]): DirectoryList | null => + getVendoredDirectoryList(directoryCode) ?? synthesizeFromMainDirectory(directoryCode, directories); + const mergeDirectoryListDefaults = (list: DirectoryList, fallback: DirectoryList | null): DirectoryList => ({ ...list, ...(list.title || !fallback?.title ? {} : { title: fallback.title }), @@ -145,13 +176,13 @@ const fetchDirectoryListDeduped = (code: string): Promise /** * Fetch the candidate boards for a single directory code (e.g. 'biz'). * - * Source: `bitsocialnet/lists/5chan-directories/5chan-{code}-directory.json`. When the network is unavailable - * or the file is not yet published, falls back to a synthesized single-entry list derived - * from the merged directory assignments. + * Source: `bitsocialnet/lists/5chan-directories/5chan-{code}-directory.json`. While the network + * is unavailable or the remote file is still loading, falls back to the vendored list + * generated from that repo, then to a synthesized single-entry list from directory assignments. */ export const useDirectoryList = (directoryCode: string | undefined): DirectoryListState => { const directories = useDirectories(); - const fallback = useMemo(() => (directoryCode ? synthesizeFromMainDirectory(directoryCode, directories) : null), [directoryCode, directories]); + const fallback = useMemo(() => (directoryCode ? getFallbackDirectoryList(directoryCode, directories) : null), [directoryCode, directories]); const [state, setState] = useState(() => { if (!directoryCode) { @@ -233,7 +264,7 @@ export const useDirectoryLists = (directoryCodes: string[] | undefined): Directo const fallbackByCode = useMemo(() => { const normalizedDirectoryCodes = directoryCodesKey ? directoryCodesKey.split('\0') : []; - return Object.fromEntries(normalizedDirectoryCodes.map((directoryCode) => [directoryCode, synthesizeFromMainDirectory(directoryCode, directories)])) as Record< + return Object.fromEntries(normalizedDirectoryCodes.map((directoryCode) => [directoryCode, getFallbackDirectoryList(directoryCode, directories)])) as Record< string, DirectoryList | null >; diff --git a/src/hooks/use-resolved-community-address.ts b/src/hooks/use-resolved-community-address.ts index 56a2d7a6..442941e8 100644 --- a/src/hooks/use-resolved-community-address.ts +++ b/src/hooks/use-resolved-community-address.ts @@ -1,23 +1,28 @@ import { useMemo } from 'react'; import { useParams } from 'react-router-dom'; import { useDirectories } from './use-directories'; -import { pickDirectoryWinner, useDirectoryList } from './use-directory-list'; +import { getDirectoryCodeForBoardAddress, pickDirectoryWinner, useDirectoryList } from './use-directory-list'; import useCommunityOfflineStore from '../stores/use-community-offline-store'; -import { getCommunityAddress, getBoardPath, isDirectoryRoute } from '../lib/utils/route-utils'; +import { areSameBoardAddress, getCommunityAddress, getBoardPath, isDirectoryRoute } from '../lib/utils/route-utils'; import { isCommunityKnownOffline } from '../lib/utils/community-freshness-utils'; import { useNowSeconds } from './use-now-seconds'; +interface ResolvedDirectoryBoardPath { + boardPath: string | undefined; + isDirectoryCandidate: boolean; +} + /** - * Resolve a board identifier from URL params to canonical community address. + * Resolve a board identifier to its canonical community address. * * For directory codes (e.g. /biz) with a per-directory list of candidates, picks the * highest-ranked candidate that is not currently flagged offline. Falls back to the - * vendored single-candidate default while the per-directory list is still loading. + * vendored directory list while the remote list is still loading. */ -export const useResolvedCommunityAddress = (): string | undefined => { +export const useResolvedCommunityAddress = (boardIdentifierOverride?: string): string | undefined => { const params = useParams<{ boardIdentifier?: string }>(); const directories = useDirectories(); - const boardIdentifier = params.boardIdentifier; + const boardIdentifier = boardIdentifierOverride ?? params.boardIdentifier; const isCode = !!boardIdentifier && isDirectoryRoute(boardIdentifier, directories); const { list } = useDirectoryList(isCode ? boardIdentifier : undefined); const offlineStates = useCommunityOfflineStore((state) => (isCode ? state.communityOfflineState : undefined)); @@ -34,6 +39,37 @@ export const useResolvedCommunityAddress = (): string | undefined => { }, [boardIdentifier, directories, isCode, list, offlineStates, nowSeconds]); }; +/** + * Return the directory code only when a direct board-address route points at the + * board currently winning that directory. + */ +export const useResolvedDirectoryBoardPath = (boardIdentifier: string | undefined): ResolvedDirectoryBoardPath => { + const directories = useDirectories(); + const isCode = !!boardIdentifier && isDirectoryRoute(boardIdentifier, directories); + const directoryCode = useMemo(() => (boardIdentifier && !isCode ? getDirectoryCodeForBoardAddress(boardIdentifier) : undefined), [boardIdentifier, isCode]); + const { list } = useDirectoryList(directoryCode); + const offlineStates = useCommunityOfflineStore((state) => (directoryCode ? state.communityOfflineState : undefined)); + const nowSeconds = useNowSeconds(!!directoryCode); + + return useMemo(() => { + if (!boardIdentifier || !directoryCode) { + return { boardPath: undefined, isDirectoryCandidate: false }; + } + + if (!list || list.boards.length === 0) { + return { boardPath: undefined, isDirectoryCandidate: true }; + } + + const isOffline = (address: string) => isCommunityKnownOffline(offlineStates?.[address], nowSeconds); + const winner = pickDirectoryWinner(list.boards, isOffline); + + return { + boardPath: winner && areSameBoardAddress(winner.address, boardIdentifier) ? directoryCode : undefined, + isDirectoryCandidate: true, + }; + }, [boardIdentifier, directoryCode, list, offlineStates, nowSeconds]); +}; + /** * Resolve a community address to board path (directory code or address) for links. */ diff --git a/src/views/archive/archive.tsx b/src/views/archive/archive.tsx index f6e97460..f07aff1f 100644 --- a/src/views/archive/archive.tsx +++ b/src/views/archive/archive.tsx @@ -10,7 +10,7 @@ import LoadingEllipsis from '../../components/loading-ellipsis'; import { useResolvedCommunityAddress } from '../../hooks/use-resolved-community-address'; import { useCommunityField } from '../../hooks/use-stable-community'; import { useFeedStateString } from '../../hooks/use-state-string'; -import { getCommunityAddress, getBoardPath } from '../../lib/utils/route-utils'; +import { getBoardPath } from '../../lib/utils/route-utils'; import { isCommentArchived } from '../../lib/utils/comment-moderation-utils'; import { removeMarkdown } from '../../lib/utils/post-utils'; import { useDirectories } from '../../hooks/use-directories'; @@ -151,13 +151,7 @@ const Archive = () => { const boardIdentifier = params.boardIdentifier; const directories = useDirectories(); - const resolvedAddressFromUrl = useResolvedCommunityAddress(); - const communityAddress = useMemo(() => { - if (boardIdentifier) { - return getCommunityAddress(boardIdentifier, directories); - } - return resolvedAddressFromUrl; - }, [boardIdentifier, directories, resolvedAddressFromUrl]); + const communityAddress = useResolvedCommunityAddress(boardIdentifier); const boardPath = useMemo(() => { if (!communityAddress) { diff --git a/src/views/board/__tests__/board.test.tsx b/src/views/board/__tests__/board.test.tsx index 3410a0d8..76749414 100644 --- a/src/views/board/__tests__/board.test.tsx +++ b/src/views/board/__tests__/board.test.tsx @@ -25,7 +25,7 @@ const testState = vi.hoisted(() => ({ accountComments: [] as TestComment[], accountCommentsCalls: [] as Array<{ commentIndices?: number[]; communityAddress?: string; newerThan?: number; sortType?: 'new' | 'old' } | undefined>, accountCommunityAddresses: [] as string[], - directories: [{ address: 'music-posting.eth', title: '/mu/ - Music' }] as Array<{ address: string; title?: string }>, + directories: [{ address: 'music-posting.eth', title: '/mu/ - Music' }] as Array<{ address: string; title?: string; directoryCode?: string }>, directoryByAddress: { 'music-posting.eth': { address: 'music-posting.eth', @@ -33,7 +33,7 @@ const testState = vi.hoisted(() => ({ }, } as Record }>, feed: [] as TestComment[], - feedOptionsCalls: [] as Array<{ communitiesLength?: number; newerThan?: number; postsPerPage?: number; sortType?: string }>, + feedOptionsCalls: [] as Array<{ communities?: unknown[]; communitiesLength?: number; newerThan?: number; postsPerPage?: number; sortType?: string }>, feedState: undefined as string | undefined, feedStateString: 'syncing' as string | undefined, filteredDirectoryAddresses: ['music-posting.eth'] as string[], @@ -129,6 +129,7 @@ vi.mock('@bitsocial/bitsocial-react-hooks', () => ({ sortType?: string; }) => { testState.feedOptionsCalls.push({ + communities: options?.communities, communitiesLength: options?.communities?.length, newerThan: options?.newerThan, postsPerPage: options?.postsPerPage, @@ -379,6 +380,25 @@ describe('Board', () => { localStorage.clear(); }); + it('uses the resolved directory winner for cached board feeds', async () => { + testState.directories = [{ address: 'business-and-finance.bso', directoryCode: 'biz', title: '/biz/ - Business & Finance' }]; + testState.directoryByAddress = { + 'bizraelis.bso': { + address: 'bizraelis.bso', + features: { postsPerPage: 2 }, + }, + }; + testState.resolvedCommunityAddress = 'bizraelis.bso'; + + await renderBoard({ + boardProps: { boardIdentifier: 'biz', viewType: 'board' }, + initialEntry: '/biz', + routePath: '/:boardIdentifier/*', + }); + + expect(testState.feedOptionsCalls.map((call) => call.communities)).toContainEqual([{ name: 'bizraelis.bso' }]); + }); + it('renders the current page feed, inserts recent account comments, and wires footer actions', async () => { const currentTimestamp = Math.floor(Date.now() / 1000); testState.feed = [ diff --git a/src/views/board/board.tsx b/src/views/board/board.tsx index 7e4f1dd0..525b0bbc 100644 --- a/src/views/board/board.tsx +++ b/src/views/board/board.tsx @@ -22,7 +22,7 @@ import useIsMobile from '../../hooks/use-is-mobile'; import { useSuggestionFeedLoader } from '../../hooks/use-suggestion-feed-loader'; import useTimeFilter from '../../hooks/use-time-filter'; import { getPageSlice } from '../../lib/utils/board-feed-pagination'; -import { getPageFromFeedPath, getCommunityAddress, isDirectoryBoard, normalizeMultiboardFeedPath, stripPageFromFeedPath } from '../../lib/utils/route-utils'; +import { getPageFromFeedPath, isDirectoryBoard, normalizeMultiboardFeedPath, stripPageFromFeedPath } from '../../lib/utils/route-utils'; import { isCommentArchived } from '../../lib/utils/comment-moderation-utils'; import { getCommentCommunityAddress } from '../../lib/utils/comment-utils'; import { getSearchWithTimeFilter, getTimeFilterSuggestion, type TimeFilterSuggestion } from '../../lib/utils/time-filter-utils'; @@ -166,13 +166,7 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t const multiboardTimeFilterSeconds = isMultiboardView ? timeFilterSeconds : undefined; const directories = useDirectories(); - const resolvedAddressFromUrl = useResolvedCommunityAddress(); - const communityAddress = useMemo(() => { - if (boardIdentifierProp) { - return getCommunityAddress(boardIdentifierProp, directories); - } - return resolvedAddressFromUrl; - }, [boardIdentifierProp, directories, resolvedAddressFromUrl]); + const communityAddress = useResolvedCommunityAddress(boardIdentifierProp); const filteredDirectoryAddresses = useFilteredDirectoryAddresses(); diff --git a/src/views/catalog/catalog.tsx b/src/views/catalog/catalog.tsx index f2307a8a..9d3efd78 100644 --- a/src/views/catalog/catalog.tsx +++ b/src/views/catalog/catalog.tsx @@ -23,7 +23,7 @@ import useFeedResetStore from '../../stores/use-feed-reset-store'; import useHiddenCatalogThreadsStore from '../../stores/use-hidden-catalog-threads-store'; import useSortingStore from '../../stores/use-sorting-store'; import useCatalogFiltersStore from '../../stores/use-catalog-filters-store'; -import { getCommunityAddress, isDirectoryBoard, normalizeMultiboardFeedPath } from '../../lib/utils/route-utils'; +import { isDirectoryBoard, normalizeMultiboardFeedPath } from '../../lib/utils/route-utils'; import CatalogRow from '../../components/catalog-row'; import { CatalogFooterFirstRow, CatalogFooterStyleRow, PageFooterDesktop, PageFooterMobile } from '../../components/footer'; import { ReturnButton, ArchiveButton, TopButton, RefreshButton } from '../../components/board-buttons/board-buttons'; @@ -285,13 +285,7 @@ const Catalog = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, const effectiveInfiniteScroll = isMultiboard; const directories = useDirectories(); - const resolvedAddressFromUrl = useResolvedCommunityAddress(); - const communityAddress = useMemo(() => { - if (boardIdentifierProp) { - return getCommunityAddress(boardIdentifierProp, directories); - } - return resolvedAddressFromUrl; - }, [boardIdentifierProp, directories, resolvedAddressFromUrl]); + const communityAddress = useResolvedCommunityAddress(boardIdentifierProp); const filterItems = useCatalogFiltersStore((state) => state.filterItems); const searchText = useCatalogFiltersStore((state) => state.searchText);