mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix: share board offline state between post form and reply modal
This commit is contained in:
@@ -21,6 +21,7 @@ const testState = vi.hoisted(() => ({
|
||||
isMobile: false,
|
||||
isUploading: false,
|
||||
offlineTitle: '' as string | false,
|
||||
offlineStates: {} as Record<string, { isOffline: boolean; isOnlineStatusLoading: boolean; offlineTitle: string | false }>,
|
||||
offlineStatusLoading: false,
|
||||
offlineWarningVisible: false,
|
||||
openEmpty: false,
|
||||
@@ -30,6 +31,7 @@ const testState = vi.hoisted(() => ({
|
||||
quoteInsertSelectedText: '',
|
||||
replyIndex: undefined as number | undefined,
|
||||
resetPublishReplyOptionsMock: vi.fn(),
|
||||
resolvedSubplebbitAddress: undefined as string | undefined,
|
||||
selectedText: 'selected text',
|
||||
setAccountMock: vi.fn(),
|
||||
setPublishReplyOptionsMock: vi.fn(),
|
||||
@@ -77,11 +79,12 @@ vi.mock('@bitsocialhq/bitsocial-react-hooks/dist/stores/subplebbits', () => ({
|
||||
}));
|
||||
|
||||
vi.mock('../../../hooks/use-is-subplebbit-offline', () => ({
|
||||
default: () => ({
|
||||
isOffline: testState.offlineWarningVisible,
|
||||
isOnlineStatusLoading: testState.offlineStatusLoading,
|
||||
offlineTitle: testState.offlineTitle,
|
||||
}),
|
||||
default: (subplebbit?: { address?: string }) =>
|
||||
(subplebbit?.address ? testState.offlineStates[subplebbit.address] : undefined) || {
|
||||
isOffline: testState.offlineWarningVisible,
|
||||
isOnlineStatusLoading: testState.offlineStatusLoading,
|
||||
offlineTitle: testState.offlineTitle,
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('../../../stores/use-selected-text-store', () => ({
|
||||
@@ -116,6 +119,11 @@ vi.mock('../../../stores/use-media-hosting-store', () => ({
|
||||
|
||||
vi.mock('../../../hooks/use-directories', () => ({
|
||||
useDirectoryByAddress: (address: string) => testState.directoryByAddress[address],
|
||||
normalizeBoardAddress: (address: string) => address.replace(/\.(bso|eth)$/, ''),
|
||||
}));
|
||||
|
||||
vi.mock('../../../hooks/use-resolved-subplebbit-address', () => ({
|
||||
useResolvedSubplebbitAddress: () => testState.resolvedSubplebbitAddress,
|
||||
}));
|
||||
|
||||
vi.mock('../../../hooks/use-publish-reply', () => ({
|
||||
@@ -185,7 +193,7 @@ const flushEffects = async (count = 4) => {
|
||||
}
|
||||
};
|
||||
|
||||
const renderReplyModal = async (initialEntry = '/mu/thread/post-1') => {
|
||||
const renderReplyModal = async (initialEntry = '/mu/thread/post-1', subplebbitAddress = 'music-posting.eth') => {
|
||||
await act(async () => {
|
||||
root.render(
|
||||
createElement(
|
||||
@@ -198,7 +206,7 @@ const renderReplyModal = async (initialEntry = '/mu/thread/post-1') => {
|
||||
postCid: 'post-cid',
|
||||
scrollY: 120,
|
||||
showReplyModal: true,
|
||||
subplebbitAddress: 'music-posting.eth',
|
||||
subplebbitAddress,
|
||||
threadNumber: 42,
|
||||
}),
|
||||
),
|
||||
@@ -243,6 +251,7 @@ describe('ReplyModal', () => {
|
||||
testState.isMobile = false;
|
||||
testState.isUploading = false;
|
||||
testState.offlineTitle = '';
|
||||
testState.offlineStates = {};
|
||||
testState.offlineStatusLoading = false;
|
||||
testState.offlineWarningVisible = false;
|
||||
testState.openEmpty = false;
|
||||
@@ -252,6 +261,7 @@ describe('ReplyModal', () => {
|
||||
testState.quoteInsertSelectedText = '';
|
||||
testState.replyIndex = undefined;
|
||||
testState.resetPublishReplyOptionsMock.mockReset();
|
||||
testState.resolvedSubplebbitAddress = undefined;
|
||||
testState.selectedText = 'selected text';
|
||||
testState.setAccountMock.mockReset();
|
||||
testState.setPublishReplyOptionsMock.mockReset();
|
||||
@@ -302,6 +312,29 @@ describe('ReplyModal', () => {
|
||||
expect(container.textContent).not.toContain('subplebbit_offline_info');
|
||||
});
|
||||
|
||||
it('prefers the resolved board entry when the modal prop address uses a different alias', async () => {
|
||||
testState.offlineTitle = 'subplebbit_offline_info';
|
||||
testState.offlineWarningVisible = true;
|
||||
testState.resolvedSubplebbitAddress = 'music-posting.eth';
|
||||
testState.subplebbits = {
|
||||
'music-posting.eth': {
|
||||
address: 'music-posting.eth',
|
||||
},
|
||||
};
|
||||
testState.offlineStates = {
|
||||
'music-posting.eth': {
|
||||
isOffline: false,
|
||||
isOnlineStatusLoading: false,
|
||||
offlineTitle: '',
|
||||
},
|
||||
};
|
||||
|
||||
await renderReplyModal('/mu/thread/post-1', 'music-posting.bso');
|
||||
|
||||
expect(container.querySelector('[class*="offlineBoard"]')).toBeNull();
|
||||
expect(container.textContent).not.toContain('subplebbit_offline_info');
|
||||
});
|
||||
|
||||
it('validates empty and invalid replies, then publishes once the payload is valid', async () => {
|
||||
testState.openEmpty = true;
|
||||
testState.selectedText = '';
|
||||
|
||||
@@ -2,18 +2,17 @@ import { useEffect, useRef, useState } from 'react';
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { setAccount, useAccount } from '@bitsocialhq/bitsocial-react-hooks';
|
||||
import useSubplebbitsStore from '@bitsocialhq/bitsocial-react-hooks/dist/stores/subplebbits';
|
||||
import { isValidURL } from '../../lib/utils/url-utils';
|
||||
import { isAllView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import { isAllView, isModView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import useSelectedTextStore from '../../stores/use-selected-text-store';
|
||||
import useReplyModalStore from '../../stores/use-reply-modal-store';
|
||||
import { getShowUploadControls, isWebRuntime } from '../../lib/media-hosting/show-upload-controls';
|
||||
import useMediaHostingStore from '../../stores/use-media-hosting-store';
|
||||
import { useDirectoryByAddress } from '../../hooks/use-directories';
|
||||
import usePublishReply from '../../hooks/use-publish-reply';
|
||||
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
|
||||
import useIsMobile from '../../hooks/use-is-mobile';
|
||||
import { useFileUpload } from '../../hooks/use-file-upload';
|
||||
import BoardOfflineAlert from '../board-offline-alert/board-offline-alert';
|
||||
import styles from './reply-modal.module.css';
|
||||
import capitalize from 'lodash/capitalize';
|
||||
import debounce from 'lodash/debounce';
|
||||
@@ -31,22 +30,12 @@ interface ReplyModalProps {
|
||||
subplebbitAddress: string;
|
||||
}
|
||||
|
||||
const ReplyModalOfflineAlert = ({ hidden, subplebbitAddress }: { hidden: boolean; subplebbitAddress: string }) => {
|
||||
const subplebbit = useSubplebbitsStore((state) => state.subplebbits[subplebbitAddress]);
|
||||
const { isOffline, isOnlineStatusLoading, offlineTitle } = useIsSubplebbitOffline(subplebbit);
|
||||
|
||||
if (hidden || (!isOffline && !isOnlineStatusLoading)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <div className={styles.offlineBoard}>{offlineTitle}</div>;
|
||||
};
|
||||
|
||||
const ReplyModal = ({ closeModal, showReplyModal, parentCid, parentNumber, threadNumber, postCid, scrollY, subplebbitAddress }: ReplyModalProps) => {
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
const params = useParams();
|
||||
const isInAllView = isAllView(location.pathname);
|
||||
const isInModView = isModView(location.pathname);
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
||||
const directoryEntry = useDirectoryByAddress(subplebbitAddress);
|
||||
const showSpoilerForReply = directoryEntry?.features?.noSpoilerReplies !== true;
|
||||
@@ -376,7 +365,7 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, parentNumber, threa
|
||||
</button>
|
||||
</div>
|
||||
{lengthError ? <div className={styles.error}>{lengthError}</div> : error && <div className={styles.error}>{error}</div>}
|
||||
<ReplyModalOfflineAlert hidden={isInAllView || isInSubscriptionsView} subplebbitAddress={subplebbitAddress} />
|
||||
<BoardOfflineAlert className={styles.offlineBoard} hidden={isInAllView || isInSubscriptionsView || isInModView} subplebbitAddress={subplebbitAddress} />
|
||||
</div>
|
||||
</animated.div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user