mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
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:
@@ -13,8 +13,8 @@ const testState = vi.hoisted(() => ({
|
||||
author: { displayName: 'Alice' },
|
||||
subscriptions: ['music-posting.eth'],
|
||||
},
|
||||
accountComment: undefined as { subplebbitAddress?: string } | undefined,
|
||||
accountSubplebbitAddresses: ['mod.eth'] as string[],
|
||||
accountComment: undefined as { communityAddress?: string } | undefined,
|
||||
accountCommunityAddresses: ['mod.eth'] as string[],
|
||||
comments: {} as Record<string, { deleted?: boolean; locked?: boolean; postCid?: string; removed?: boolean }>,
|
||||
directories: [
|
||||
{ address: 'music-posting.eth', features: {}, title: '/mu/ - Music' },
|
||||
@@ -36,12 +36,12 @@ const testState = vi.hoisted(() => ({
|
||||
replyIndex: undefined as number | undefined,
|
||||
resetPublishPostOptionsMock: vi.fn(),
|
||||
resetPublishReplyOptionsMock: vi.fn(),
|
||||
resolvedSubplebbitAddress: undefined as string | undefined,
|
||||
resolvedCommunityAddress: undefined as string | undefined,
|
||||
setAccountMock: vi.fn(),
|
||||
setPublishPostOptionsMock: vi.fn(),
|
||||
setPublishReplyOptionsMock: vi.fn(),
|
||||
showUploadControls: true,
|
||||
subplebbits: {
|
||||
communities: {
|
||||
'music-posting.eth': { address: 'music-posting.eth' },
|
||||
} as Record<string, unknown>,
|
||||
uploadComplete: undefined as ((uploadedUrl: string) => void) | undefined,
|
||||
@@ -70,16 +70,16 @@ vi.mock('@bitsocialnet/bitsocial-react-hooks', () => ({
|
||||
useEditedComment: () => ({ editedComment: testState.editedComment }),
|
||||
}));
|
||||
|
||||
vi.mock('@bitsocialnet/bitsocial-react-hooks/dist/stores/subplebbits', () => ({
|
||||
default: (selector: (state: { subplebbits: typeof testState.subplebbits }) => unknown) => selector({ subplebbits: testState.subplebbits }),
|
||||
vi.mock('@bitsocialnet/bitsocial-react-hooks/dist/stores/communities', () => ({
|
||||
default: (selector: (state: { communities: typeof testState.communities }) => unknown) => selector({ communities: testState.communities }),
|
||||
}));
|
||||
|
||||
vi.mock('@bitsocialnet/bitsocial-react-hooks/dist/stores/subplebbits-pages', () => ({
|
||||
vi.mock('@bitsocialnet/bitsocial-react-hooks/dist/stores/communities-pages', () => ({
|
||||
default: (selector: (state: { comments: typeof testState.comments }) => unknown) => selector({ comments: testState.comments }),
|
||||
}));
|
||||
|
||||
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', () => ({
|
||||
@@ -88,8 +88,8 @@ vi.mock('../../../hooks/use-directories', () => ({
|
||||
normalizeBoardAddress: (address: string) => address.replace(/\.(bso|eth)$/, ''),
|
||||
}));
|
||||
|
||||
vi.mock('../../../hooks/use-resolved-subplebbit-address', () => ({
|
||||
useResolvedSubplebbitAddress: () => testState.resolvedSubplebbitAddress,
|
||||
vi.mock('../../../hooks/use-resolved-community-address', () => ({
|
||||
useResolvedCommunityAddress: () => testState.resolvedCommunityAddress,
|
||||
}));
|
||||
|
||||
vi.mock('../../../hooks/use-fetch-gif-first-frame', () => ({
|
||||
@@ -98,7 +98,7 @@ vi.mock('../../../hooks/use-fetch-gif-first-frame', () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('../../../hooks/use-is-subplebbit-offline', () => ({
|
||||
vi.mock('../../../hooks/use-is-community-offline', () => ({
|
||||
default: () => ({
|
||||
isOffline: testState.isOffline,
|
||||
isOnlineStatusLoading: testState.isOnlineStatusLoading,
|
||||
@@ -114,8 +114,8 @@ vi.mock('../../../hooks/use-publish-post', async () => {
|
||||
const React = await vi.importActual<typeof import('react')>('react');
|
||||
|
||||
return {
|
||||
default: ({ subplebbitAddress }: { subplebbitAddress?: string }) => {
|
||||
const [publishPostOptions, setPublishPostOptionsState] = React.useState<Record<string, unknown>>(subplebbitAddress ? { subplebbitAddress } : {});
|
||||
default: ({ communityAddress }: { communityAddress?: string }) => {
|
||||
const [publishPostOptions, setPublishPostOptionsState] = React.useState<Record<string, unknown>>(communityAddress ? { communityAddress } : {});
|
||||
|
||||
return {
|
||||
postIndex: testState.postIndex,
|
||||
@@ -135,11 +135,11 @@ vi.mock('../../../hooks/use-publish-reply', async () => {
|
||||
const React = await vi.importActual<typeof import('react')>('react');
|
||||
|
||||
return {
|
||||
default: ({ cid, postCid, subplebbitAddress }: { cid: string; postCid?: string; subplebbitAddress: string }) => {
|
||||
default: ({ cid, postCid, communityAddress }: { cid: string; postCid?: string; communityAddress: string }) => {
|
||||
const [publishReplyOptions, setPublishReplyOptionsState] = React.useState<Record<string, unknown>>({
|
||||
parentCid: cid,
|
||||
postCid: postCid ?? cid,
|
||||
subplebbitAddress,
|
||||
communityAddress,
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -269,7 +269,7 @@ describe('PostForm', () => {
|
||||
subscriptions: ['music-posting.eth'],
|
||||
};
|
||||
testState.accountComment = undefined;
|
||||
testState.accountSubplebbitAddresses = ['mod.eth'];
|
||||
testState.accountCommunityAddresses = ['mod.eth'];
|
||||
testState.comments = {};
|
||||
testState.directories = [
|
||||
{ address: 'music-posting.eth', features: {}, title: '/mu/ - Music' },
|
||||
@@ -285,12 +285,12 @@ describe('PostForm', () => {
|
||||
testState.publishReplyError = null;
|
||||
testState.publishReplyStateMessage = null;
|
||||
testState.replyIndex = undefined;
|
||||
testState.resolvedSubplebbitAddress = undefined;
|
||||
testState.resolvedCommunityAddress = undefined;
|
||||
testState.showUploadControls = true;
|
||||
testState.uploadComplete = undefined;
|
||||
testState.uploadMode = 'always';
|
||||
testState.uploadedFileName = 'picked.png';
|
||||
testState.subplebbits = {
|
||||
testState.communities = {
|
||||
'music-posting.eth': { address: 'music-posting.eth' },
|
||||
};
|
||||
testState.handleUploadMock.mockReset();
|
||||
@@ -382,12 +382,12 @@ describe('PostForm', () => {
|
||||
await clickByText(table as HTMLTableElement, 'post');
|
||||
|
||||
expect(testState.publishPostMock).toHaveBeenCalledTimes(1);
|
||||
expect(testState.setPublishPostOptionsMock).toHaveBeenCalledWith({ subplebbitAddress: 'music-posting.eth' });
|
||||
expect(testState.setPublishPostOptionsMock).toHaveBeenCalledWith({ communityAddress: 'music-posting.eth' });
|
||||
});
|
||||
|
||||
it('redirects to the pending route when a post publish index is already available on mount', async () => {
|
||||
testState.postIndex = 7;
|
||||
testState.resolvedSubplebbitAddress = 'music-posting.eth';
|
||||
testState.resolvedCommunityAddress = 'music-posting.eth';
|
||||
|
||||
await renderPostForm('/mu');
|
||||
await clickByText(container, 'start_new_thread');
|
||||
@@ -404,7 +404,7 @@ describe('PostForm', () => {
|
||||
},
|
||||
};
|
||||
testState.replyIndex = 4;
|
||||
testState.resolvedSubplebbitAddress = 'music-posting.eth';
|
||||
testState.resolvedCommunityAddress = 'music-posting.eth';
|
||||
|
||||
await renderPostForm('/mu/thread/thread-cid');
|
||||
await clickByText(container, 'post_a_reply');
|
||||
@@ -421,7 +421,7 @@ describe('PostForm', () => {
|
||||
},
|
||||
};
|
||||
testState.isOffline = true;
|
||||
testState.resolvedSubplebbitAddress = 'music-posting.eth';
|
||||
testState.resolvedCommunityAddress = 'music-posting.eth';
|
||||
|
||||
await renderPostForm('/mu/thread/thread-cid');
|
||||
await clickByText(container, 'post_a_reply');
|
||||
|
||||
@@ -3,14 +3,14 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||
import { Comment, setAccount, useAccount, useAccountComment, useEditedComment } from '@bitsocialnet/bitsocial-react-hooks';
|
||||
import getShortAddress from '../../lib/get-short-address';
|
||||
import useSubplebbitsPagesStore from '@bitsocialnet/bitsocial-react-hooks/dist/stores/subplebbits-pages';
|
||||
import useCommunitiesPagesStore from '@bitsocialnet/bitsocial-react-hooks/dist/stores/communities-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 { useAccountCommunityAddresses } from '../../hooks/use-account-community-addresses';
|
||||
import { useDirectories, useDirectoryByAddress } from '../../hooks/use-directories';
|
||||
import useIsMobile from '../../hooks/use-is-mobile';
|
||||
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
||||
import { useResolvedCommunityAddress } from '../../hooks/use-resolved-community-address';
|
||||
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
|
||||
import usePublishPost from '../../hooks/use-publish-post';
|
||||
import usePublishReply from '../../hooks/use-publish-reply';
|
||||
@@ -101,9 +101,9 @@ interface PostFormFieldsProps {
|
||||
isInSubscriptionsView: boolean;
|
||||
isInModView: boolean;
|
||||
directories: ReturnType<typeof useDirectories>;
|
||||
accountSubplebbitAddresses: string[];
|
||||
accountCommunityAddresses: string[];
|
||||
subscriptions: string[];
|
||||
subplebbitAddress: string | undefined;
|
||||
communityAddress: string | undefined;
|
||||
requirePostLinkIsMedia: boolean;
|
||||
onPublishReply: () => void;
|
||||
onPublishPost: () => void;
|
||||
@@ -134,9 +134,9 @@ const PostFormFields = ({
|
||||
isInSubscriptionsView,
|
||||
isInModView,
|
||||
directories,
|
||||
accountSubplebbitAddresses,
|
||||
accountCommunityAddresses,
|
||||
subscriptions,
|
||||
subplebbitAddress,
|
||||
communityAddress,
|
||||
requirePostLinkIsMedia,
|
||||
onPublishReply,
|
||||
onPublishPost,
|
||||
@@ -263,18 +263,18 @@ const PostFormFields = ({
|
||||
<tr>
|
||||
<td>{t('board')}</td>
|
||||
<td>
|
||||
<select onChange={(e) => setPublishPostOptions({ subplebbitAddress: e.target.value })} value={subplebbitAddress}>
|
||||
<select onChange={(e) => setPublishPostOptions({ communityAddress: e.target.value })} value={communityAddress}>
|
||||
<option value=''>{t('choose_one')}</option>
|
||||
{isInAllView &&
|
||||
directories
|
||||
.filter((subplebbit) => subplebbit.title && subplebbit.address)
|
||||
.map((subplebbit) => (
|
||||
<option key={subplebbit.address} value={subplebbit.address}>
|
||||
{subplebbit.title}
|
||||
.filter((community) => community.title && community.address)
|
||||
.map((community) => (
|
||||
<option key={community.address} value={community.address}>
|
||||
{community.title}
|
||||
</option>
|
||||
))}
|
||||
{isInModView &&
|
||||
accountSubplebbitAddresses.map((address: string) => (
|
||||
accountCommunityAddresses.map((address: string) => (
|
||||
<option key={address} value={address}>
|
||||
{address && getShortAddress(address)}
|
||||
</option>
|
||||
@@ -300,10 +300,10 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
||||
const author = account?.author || {};
|
||||
const { displayName } = author || {};
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const resolvedAddress = useResolvedSubplebbitAddress();
|
||||
const subplebbitAddress = resolvedAddress || accountComment?.subplebbitAddress;
|
||||
const { setPublishPostOptions, postIndex, publishPost, publishPostOptions, resetPublishPostOptions } = usePublishPost({ subplebbitAddress });
|
||||
const effectiveBoardAddress = subplebbitAddress || publishPostOptions.subplebbitAddress;
|
||||
const resolvedAddress = useResolvedCommunityAddress();
|
||||
const communityAddress = resolvedAddress || accountComment?.communityAddress;
|
||||
const { setPublishPostOptions, postIndex, publishPost, publishPostOptions, resetPublishPostOptions } = usePublishPost({ subplebbitAddress: communityAddress });
|
||||
const effectiveBoardAddress = communityAddress || publishPostOptions.communityAddress;
|
||||
|
||||
const textRef = useRef<HTMLTextAreaElement>(null);
|
||||
const urlRef = useRef<HTMLInputElement>(null);
|
||||
@@ -321,7 +321,7 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
||||
const requirePostLinkIsMediaFeature = directoryEntry?.features?.requirePostLinkIsMedia;
|
||||
const requirePostLinkIsMedia = requirePostLinkIsMediaFeature === true || (requirePostLinkIsMediaFeature === undefined && (isInAllView || isInSubscriptionsView));
|
||||
|
||||
const accountSubplebbitAddresses = useAccountSubplebbitAddresses();
|
||||
const accountCommunityAddresses = useAccountCommunityAddresses();
|
||||
|
||||
const [lengthError, setLengthError] = useState<string | null>(null);
|
||||
|
||||
@@ -370,7 +370,7 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
||||
return;
|
||||
}
|
||||
|
||||
if ((isInAllView || isInSubscriptionsView || isInModView) && !publishPostOptions.subplebbitAddress) {
|
||||
if ((isInAllView || isInSubscriptionsView || isInModView) && !publishPostOptions.communityAddress) {
|
||||
alert(t('no_board_selected_warning'));
|
||||
return;
|
||||
}
|
||||
@@ -392,7 +392,7 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
||||
const isInPostView = isPostPageView(location.pathname, params);
|
||||
const cid = params?.commentCid as string;
|
||||
const { isResolvingExternalQuotes, publishReply, publishReplyError, publishReplyStateMessage, resetPublishReplyOptions, replyIndex, setPublishReplyOptions } =
|
||||
usePublishReply({ cid, subplebbitAddress });
|
||||
usePublishReply({ cid, subplebbitAddress: communityAddress, postCid });
|
||||
|
||||
const handleContentChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
const content = e.target.value;
|
||||
@@ -486,9 +486,9 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
||||
isInSubscriptionsView={isInSubscriptionsView}
|
||||
isInModView={isInModView}
|
||||
directories={directories}
|
||||
accountSubplebbitAddresses={accountSubplebbitAddresses}
|
||||
accountCommunityAddresses={accountCommunityAddresses}
|
||||
subscriptions={subscriptions}
|
||||
subplebbitAddress={subplebbitAddress}
|
||||
communityAddress={communityAddress}
|
||||
requirePostLinkIsMedia={requirePostLinkIsMedia}
|
||||
onPublishReply={onPublishReply}
|
||||
onPublishPost={onPublishPost}
|
||||
@@ -516,7 +516,7 @@ const PostForm = () => {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const commentCid = params?.commentCid;
|
||||
const post = useSubplebbitsPagesStore((state) => state.comments[commentCid as string]);
|
||||
const post = useCommunitiesPagesStore((state) => state.comments[commentCid as string]);
|
||||
let comment: Comment = post;
|
||||
// handle pending mod or author edit
|
||||
const { editedComment } = useEditedComment({ comment });
|
||||
@@ -530,15 +530,15 @@ const PostForm = () => {
|
||||
const [showForm, setShowForm] = useState(false);
|
||||
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const resolvedAddress = useResolvedSubplebbitAddress();
|
||||
const subplebbitAddress = resolvedAddress || accountComment?.subplebbitAddress;
|
||||
const resolvedAddress = useResolvedCommunityAddress();
|
||||
const communityAddress = resolvedAddress || accountComment?.communityAddress;
|
||||
|
||||
const shouldShowOfflineAlert = !(isInAllView || isInSubscriptionsView || isInModView) && showForm;
|
||||
|
||||
if (isMobile) {
|
||||
return (
|
||||
<div className={styles.postFormMobile}>
|
||||
{shouldShowOfflineAlert && <BoardOfflineAlert className={styles.offlineBoard} subplebbitAddress={subplebbitAddress} />}
|
||||
{shouldShowOfflineAlert && <BoardOfflineAlert className={styles.offlineBoard} communityAddress={communityAddress} />}
|
||||
{isInModQueueView ? (
|
||||
<div className={styles.modQueueTitle}>{t('moderation_queue')}</div>
|
||||
) : isThreadClosed ? (
|
||||
@@ -562,7 +562,7 @@ const PostForm = () => {
|
||||
|
||||
return (
|
||||
<div className={styles.postFormDesktop}>
|
||||
{shouldShowOfflineAlert && <BoardOfflineAlert className={styles.offlineBoard} subplebbitAddress={subplebbitAddress} />}
|
||||
{shouldShowOfflineAlert && <BoardOfflineAlert className={styles.offlineBoard} communityAddress={communityAddress} />}
|
||||
{isInModQueueView ? (
|
||||
<div className={styles.modQueueTitle}>{t('moderation_queue')}</div>
|
||||
) : isThreadClosed ? (
|
||||
|
||||
Reference in New Issue
Block a user