From e80a73663faa50a1d83ed6bdae4e146b76ccbdf9 Mon Sep 17 00:00:00 2001 From: plebeius Date: Sat, 7 Mar 2026 16:50:24 +0800 Subject: [PATCH] feat(subscriptions): use useAccountSubplebbitAddresses for deduplicated addresses Integrate bitsocial-react-hooks#16: replace raw useAccountsStore access with useAccountSubplebbitAddresses so .eth/.bso aliases are deduplicated under .bso. --- src/app.tsx | 16 ++--------- src/components/boards-bar/boards-bar.tsx | 27 ++---------------- src/components/post-form/post-form.tsx | 6 ++-- src/hooks/use-account-subplebbit-addresses.ts | 8 ++++++ .../use-account-subplebbits-with-metadata.ts | 28 ++++++++----------- src/views/board/board.tsx | 6 ++-- src/views/home/boards-list/boards-list.tsx | 11 ++------ src/views/mod-queue/mod-queue.tsx | 28 ++----------------- 8 files changed, 35 insertions(+), 95 deletions(-) create mode 100644 src/hooks/use-account-subplebbit-addresses.ts diff --git a/src/app.tsx b/src/app.tsx index 2d56f761..e8f25a98 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,7 +1,6 @@ import { lazy, Suspense, useEffect } from 'react'; import { Navigate, Outlet, Route, Routes, useLocation, useParams } from 'react-router-dom'; import { useAccount, useAccountComment, useSubplebbit } from '@bitsocialhq/bitsocial-react-hooks'; -import useAccountsStore from '@bitsocialhq/bitsocial-react-hooks/dist/stores/accounts'; import { initSnow, removeSnow } from './lib/snow'; import { isAllView, isCatalogView, isModView, isSubscriptionsView } from './lib/utils/view-utils'; import { preloadThemeAssets } from './lib/utils/preload-utils'; @@ -9,6 +8,7 @@ import useReplyModalStore from './stores/use-reply-modal-store'; import useCreateBoardModalStore from './stores/use-create-board-modal-store'; import useSpecialThemeStore from './stores/use-special-theme-store'; import useIsMobile from './hooks/use-is-mobile'; +import { useAccountSubplebbitAddresses } from './hooks/use-account-subplebbit-addresses'; import useTheme from './hooks/use-theme'; import { useDirectories } from './hooks/use-directories'; import { useResolvedSubplebbitAddress } from './hooks/use-resolved-subplebbit-address'; @@ -237,19 +237,7 @@ const ModQueueRoute = () => { const accountAddress = account?.author?.address; const subplebbitAddress = useResolvedSubplebbitAddress(); const subplebbit = useSubplebbit({ subplebbitAddress }); - - const accountSubplebbitAddresses = useAccountsStore( - (state) => { - const activeAccountId = state.activeAccountId; - const activeAccount = activeAccountId ? state.accounts[activeAccountId] : undefined; - const accountSubplebbits = activeAccount?.subplebbits || {}; - return Object.keys(accountSubplebbits); - }, - (prev, next) => { - if (prev.length !== next.length) return false; - return prev.every((val, idx) => val === next[idx]); - }, - ); + const accountSubplebbitAddresses = useAccountSubplebbitAddresses(); if (!account) { return null; diff --git a/src/components/boards-bar/boards-bar.tsx b/src/components/boards-bar/boards-bar.tsx index c8ad13cd..eae33361 100644 --- a/src/components/boards-bar/boards-bar.tsx +++ b/src/components/boards-bar/boards-bar.tsx @@ -5,6 +5,7 @@ import getShortAddress from '../../lib/get-short-address'; import { useAccountComment } from '@bitsocialhq/bitsocial-react-hooks'; import useAccountsStore from '@bitsocialhq/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 { useDirectories, useDirectoriesMetadata, DirectoryCommunity } from '../../hooks/use-directories'; import { useBoardPath, useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address'; import { getBoardPath, extractDirectoryFromTitle } from '../../lib/utils/route-utils'; @@ -116,18 +117,7 @@ const BoardsBarDesktop = () => { }, ); - const accountSubplebbitAddresses = useAccountsStore( - (state) => { - const activeAccountId = state.activeAccountId; - const activeAccount = activeAccountId ? state.accounts[activeAccountId] : undefined; - const accountSubplebbits = activeAccount?.subplebbits || {}; - return Object.keys(accountSubplebbits); - }, - (prev, next) => { - if (prev.length !== next.length) return false; - return prev.every((val, idx) => val === next[idx]); - }, - ); + const accountSubplebbitAddresses = useAccountSubplebbitAddresses(); // Show all subscriptions when enabled; no separate per-address tracking (avoids drift when subscribing from board-buttons) const visibleSubscriptionAddresses = showSubscriptionsInBoardsBar ? subscriptions : []; @@ -330,18 +320,7 @@ const BoardsBarMobile = ({ subplebbitAddress }: { subplebbitAddress?: string }) const boardPath = useBoardPath(subplebbitAddress); const selectValue = isInAllView ? 'all' : isInSubscriptionsView ? 'subs' : isInModView ? 'mod' : boardPath || subplebbitAddress; - const accountSubplebbitAddresses = useAccountsStore( - (state) => { - const activeAccountId = state.activeAccountId; - const activeAccount = activeAccountId ? state.accounts[activeAccountId] : undefined; - const accountSubplebbits = activeAccount?.subplebbits || {}; - return Object.keys(accountSubplebbits); - }, - (prev, next) => { - if (prev.length !== next.length) return false; - return prev.every((val, idx) => val === next[idx]); - }, - ); + const accountSubplebbitAddresses = useAccountSubplebbitAddresses(); // Check if current subplebbit is a directory board const currentIsDirectoryBoard = directoryBoards.some((board) => board.address === subplebbitAddress); diff --git a/src/components/post-form/post-form.tsx b/src/components/post-form/post-form.tsx index e93d859f..cc012378 100644 --- a/src/components/post-form/post-form.tsx +++ b/src/components/post-form/post-form.tsx @@ -1,13 +1,14 @@ import { useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useLocation, useNavigate, useParams } from 'react-router-dom'; -import { Comment, setAccount, useAccount, useAccountComment, useAccountSubplebbits, useEditedComment } from '@bitsocialhq/bitsocial-react-hooks'; +import { Comment, setAccount, useAccount, useAccountComment, useEditedComment } from '@bitsocialhq/bitsocial-react-hooks'; import getShortAddress from '../../lib/get-short-address'; import useSubplebbitsStore from '@bitsocialhq/bitsocial-react-hooks/dist/stores/subplebbits'; import useSubplebbitsPagesStore from '@bitsocialhq/bitsocial-react-hooks/dist/stores/subplebbits-pages'; import { getLinkMediaInfo } from '../../lib/utils/media-utils'; import { isValidURL } from '../../lib/utils/url-utils'; import { isAllView, isCatalogView, isModQueueView, isModView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils'; +import { useAccountSubplebbitAddresses } from '../../hooks/use-account-subplebbit-addresses'; import { useDirectories, useDirectoryByAddress } from '../../hooks/use-directories'; import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address'; import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame'; @@ -326,8 +327,7 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid: const requirePostLinkIsMediaFeature = directoryEntry?.features?.requirePostLinkIsMedia; const requirePostLinkIsMedia = requirePostLinkIsMediaFeature === true || (requirePostLinkIsMediaFeature === undefined && (isInAllView || isInSubscriptionsView)); - const { accountSubplebbits } = useAccountSubplebbits(); - const accountSubplebbitAddresses = Object.keys(accountSubplebbits); + const accountSubplebbitAddresses = useAccountSubplebbitAddresses(); const [lengthError, setLengthError] = useState(null); diff --git a/src/hooks/use-account-subplebbit-addresses.ts b/src/hooks/use-account-subplebbit-addresses.ts new file mode 100644 index 00000000..9676e3de --- /dev/null +++ b/src/hooks/use-account-subplebbit-addresses.ts @@ -0,0 +1,8 @@ +import { useMemo } from 'react'; +import { useAccountSubplebbits } from '@bitsocialhq/bitsocial-react-hooks'; + +export const useAccountSubplebbitAddresses = (): string[] => { + const { accountSubplebbits } = useAccountSubplebbits({ onlyIfCached: true }); + + return useMemo(() => Object.keys(accountSubplebbits), [accountSubplebbits]); +}; diff --git a/src/hooks/use-account-subplebbits-with-metadata.ts b/src/hooks/use-account-subplebbits-with-metadata.ts index db1745e1..4a31f69d 100644 --- a/src/hooks/use-account-subplebbits-with-metadata.ts +++ b/src/hooks/use-account-subplebbits-with-metadata.ts @@ -1,22 +1,16 @@ -import useAccountsStore from '@bitsocialhq/bitsocial-react-hooks/dist/stores/accounts'; +import { useMemo } from 'react'; +import { useAccountSubplebbits } from '@bitsocialhq/bitsocial-react-hooks'; import { DirectoryCommunity } from './use-directories'; export const useAccountSubplebbitsWithMetadata = (): DirectoryCommunity[] => { - const subplebbitsWithMetadata = useAccountsStore( - (state) => { - const activeAccountId = state.activeAccountId; - const activeAccount = activeAccountId ? state.accounts[activeAccountId] : undefined; - const accountSubplebbits = activeAccount?.subplebbits || {}; - return Object.entries(accountSubplebbits).map(([address, sub]) => ({ - address, - title: (sub as any).title, - })); - }, - (prev, next) => { - if (prev.length !== next.length) return false; - return prev.every((item, idx) => item.address === next[idx].address && item.title === next[idx].title); - }, - ); + const { accountSubplebbits } = useAccountSubplebbits({ onlyIfCached: true }); - return subplebbitsWithMetadata; + return useMemo( + () => + Object.values(accountSubplebbits).map((sub) => ({ + address: (sub as any).address, + title: (sub as any).title, + })), + [accountSubplebbits], + ); }; diff --git a/src/views/board/board.tsx b/src/views/board/board.tsx index eb6f7ec8..3ece9e95 100644 --- a/src/views/board/board.tsx +++ b/src/views/board/board.tsx @@ -1,12 +1,13 @@ import { useCallback, useEffect, useMemo, useRef } from 'react'; import { Link, useLocation, useNavigate, useNavigationType, useParams } from 'react-router-dom'; -import { Comment, useAccount, useAccountComments, useAccountSubplebbits, useFeed, useSubplebbit } from '@bitsocialhq/bitsocial-react-hooks'; +import { Comment, useAccount, useAccountComments, useFeed, useSubplebbit } from '@bitsocialhq/bitsocial-react-hooks'; import { useSubplebbitField } from '../../hooks/use-stable-subplebbit'; import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso'; import { useTranslation } from 'react-i18next'; import styles from './board.module.css'; import mobileFooterStyles from '../../components/footer/footer.module.css'; import { shouldShowSnow } from '../../lib/snow'; +import { useAccountSubplebbitAddresses } from '../../hooks/use-account-subplebbit-addresses'; import { useDirectoryAddresses, useDirectories, useDirectoryByAddress } from '../../hooks/use-directories'; import { useFilteredDirectoryAddresses } from '../../hooks/use-filtered-directory-addresses'; import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address'; @@ -115,8 +116,7 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, i const account = useAccount(); const subscriptions = account?.subscriptions; - const { accountSubplebbits } = useAccountSubplebbits(); - const accountSubplebbitAddresses = Object.keys(accountSubplebbits); + const accountSubplebbitAddresses = useAccountSubplebbitAddresses(); const subplebbitAddresses = useMemo(() => { if (isInAllView) { diff --git a/src/views/home/boards-list/boards-list.tsx b/src/views/home/boards-list/boards-list.tsx index 6dc28c40..b54d60af 100644 --- a/src/views/home/boards-list/boards-list.tsx +++ b/src/views/home/boards-list/boards-list.tsx @@ -1,6 +1,6 @@ import { Link, useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import useAccountsStore from '@bitsocialhq/bitsocial-react-hooks/dist/stores/accounts'; +import { useAccountSubplebbitAddresses } from '../../../hooks/use-account-subplebbit-addresses'; import { useDirectoriesState, useDirectories, DirectoryCommunity } from '../../../hooks/use-directories'; import { getBoardPath } from '../../../lib/utils/route-utils'; import useDisclaimerModalStore from '../../../stores/use-disclaimer-modal-store'; @@ -64,14 +64,7 @@ const BoardsList = ({ multisub }: { multisub: DirectoryCommunity[] }) => { const { useCatalogLinks, boardFilter } = useBoardsFilterStore(); const directories = useDirectories(); - const accountSubplebbitAddresses = useAccountsStore( - (state) => { - const activeAccountId = state.activeAccountId; - const activeAccount = activeAccountId ? state.accounts[activeAccountId] : undefined; - return Object.keys(activeAccount?.subplebbits || {}); - }, - (prev, next) => prev.length === next.length && prev.every((val, idx) => val === next[idx]), - ); + const accountSubplebbitAddresses = useAccountSubplebbitAddresses(); const handleLinkClick = (e: React.MouseEvent, address: string) => { e.preventDefault(); diff --git a/src/views/mod-queue/mod-queue.tsx b/src/views/mod-queue/mod-queue.tsx index 6a6aa50d..74d63d98 100644 --- a/src/views/mod-queue/mod-queue.tsx +++ b/src/views/mod-queue/mod-queue.tsx @@ -2,7 +2,6 @@ import React, { useMemo, useState, useEffect, useCallback, memo } from 'react'; import { useTranslation } from 'react-i18next'; import { useParams, Link } from 'react-router-dom'; import { useFeed, Comment, usePublishCommentModeration, useEditedComment, useSubplebbit, useComment } from '@bitsocialhq/bitsocial-react-hooks'; -import useAccountsStore from '@bitsocialhq/bitsocial-react-hooks/dist/stores/accounts'; import { Virtuoso } from 'react-virtuoso'; import styles from './mod-queue.module.css'; import useModQueueStore from '../../stores/use-mod-queue-store'; @@ -19,6 +18,7 @@ import useFeedResetStore from '../../stores/use-feed-reset-store'; import useChallengesStore from '../../stores/use-challenges-store'; import { alertChallengeVerificationFailed } from '../../lib/utils/challenge-utils'; import Tooltip from '../../components/tooltip'; +import { useAccountSubplebbitAddresses } from '../../hooks/use-account-subplebbit-addresses'; import useIsMobile from '../../hooks/use-is-mobile'; import { useCurrentTime } from '../../hooks/use-current-time'; import { Post } from '../post/post'; @@ -693,18 +693,7 @@ const ModQueueButtonContent = ({ feed, alertThresholdSeconds, boardIdentifier, i export const ModQueueButton = ({ boardIdentifier, isMobile }: ModQueueButtonProps) => { const { getAlertThresholdSeconds } = useModQueueStore(); - const accountSubplebbitAddresses = useAccountsStore( - (state) => { - const activeAccountId = state.activeAccountId; - const activeAccount = activeAccountId ? state.accounts[activeAccountId] : undefined; - const accountSubplebbits = activeAccount?.subplebbits || {}; - return Object.keys(accountSubplebbits); - }, - (prev, next) => { - if (prev.length !== next.length) return false; - return prev.every((val, idx) => val === next[idx]); - }, - ); + const accountSubplebbitAddresses = useAccountSubplebbitAddresses(); const directories = useDirectories(); @@ -756,18 +745,7 @@ const ModQueueView = ({ boardIdentifier: propBoardIdentifier }: ModQueueViewProp const { selectedBoardFilter, viewMode } = useModQueueStore(); const isMobile = useIsMobile(); - const accountSubplebbitAddresses = useAccountsStore( - (state) => { - const activeAccountId = state.activeAccountId; - const activeAccount = activeAccountId ? state.accounts[activeAccountId] : undefined; - const accountSubplebbits = activeAccount?.subplebbits || {}; - return Object.keys(accountSubplebbits); - }, - (prev, next) => { - if (prev.length !== next.length) return false; - return prev.every((val, idx) => val === next[idx]); - }, - ); + const accountSubplebbitAddresses = useAccountSubplebbitAddresses(); const directories = useDirectories();