mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix(board-header): keep banner stable during directory route resolution
Key the banner image by route identifier instead of the resolved community address so directory candidates do not reshuffle the banner mid-load.
This commit is contained in:
@@ -19,6 +19,7 @@ const testState = vi.hoisted(() => ({
|
||||
offlineIconClass: 'offline',
|
||||
offlineTitle: 'Board offline',
|
||||
resolvedAddress: 'music-posting.eth' as string | undefined,
|
||||
resolvedAddressListeners: [] as Array<() => void>,
|
||||
shouldShowSnow: false,
|
||||
stableCommunity: {
|
||||
address: 'music-posting.eth',
|
||||
@@ -89,7 +90,17 @@ vi.mock('../../../hooks/use-community-identifiers', () => ({
|
||||
}));
|
||||
|
||||
vi.mock('../../../hooks/use-resolved-community-address', () => ({
|
||||
useResolvedCommunityAddress: () => testState.resolvedAddress,
|
||||
useResolvedCommunityAddress: () =>
|
||||
React.useSyncExternalStore(
|
||||
(listener) => {
|
||||
testState.resolvedAddressListeners.push(listener);
|
||||
return () => {
|
||||
testState.resolvedAddressListeners = testState.resolvedAddressListeners.filter((candidate) => candidate !== listener);
|
||||
};
|
||||
},
|
||||
() => testState.resolvedAddress,
|
||||
() => testState.resolvedAddress,
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('../../../hooks/use-is-mobile', () => ({
|
||||
@@ -136,6 +147,7 @@ describe('BoardHeader', () => {
|
||||
testState.offlineIconClass = 'offline';
|
||||
testState.offlineTitle = 'Board offline';
|
||||
testState.resolvedAddress = 'music-posting.eth';
|
||||
testState.resolvedAddressListeners = [];
|
||||
testState.shouldShowSnow = false;
|
||||
testState.stableCommunity = {
|
||||
address: 'music-posting.eth',
|
||||
@@ -203,6 +215,21 @@ describe('BoardHeader', () => {
|
||||
expect(container.querySelector('img')?.getAttribute('src')).toBe('banner-a.png');
|
||||
});
|
||||
|
||||
it('keeps the banner stable while a directory route resolves different board candidates', async () => {
|
||||
mathRandomSpy.mockReturnValueOnce(0).mockReturnValue(0.75);
|
||||
|
||||
await renderHeader('/biz');
|
||||
expect(container.querySelector('img')?.getAttribute('src')).toBe('banner-a.png');
|
||||
|
||||
await act(async () => {
|
||||
testState.resolvedAddress = 'bizraelis.bso';
|
||||
testState.resolvedAddressListeners.forEach((listener) => listener());
|
||||
});
|
||||
|
||||
expect(container.querySelector('img')?.getAttribute('src')).toBe('banner-a.png');
|
||||
expect(mathRandomSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('renders hidden special board metadata without a directory entry', async () => {
|
||||
testState.directories = [];
|
||||
testState.resolvedAddress = TRASH_BOARD_ADDRESS;
|
||||
|
||||
@@ -55,6 +55,7 @@ const BoardHeader = memo(() => {
|
||||
const isInModView = isModView(location.pathname);
|
||||
const isInArchiveView = isArchiveRoute(location.pathname);
|
||||
const isInDirectoryListView = isDirectoryListRoute(location.pathname);
|
||||
const bannerKey = isInAllView ? 'all' : isInSubscriptionsView ? 'subscriptions' : isInModView ? 'mod' : params.boardIdentifier || 'board';
|
||||
const accountComment = useAccountComment({ commentIndex: normalizeAccountCommentIndex(params?.accountCommentIndex) });
|
||||
const resolvedAddress = useResolvedCommunityAddress();
|
||||
const communityAddress = resolvedAddress || accountComment?.communityAddress;
|
||||
@@ -98,7 +99,7 @@ const BoardHeader = memo(() => {
|
||||
<div className={`${styles.content} ${shouldShowSnow() ? styles.garland : ''}`}>
|
||||
{!useIsMobile() && (
|
||||
<div className={styles.bannerCnt}>
|
||||
<ImageBanner key={isInAllView ? 'all' : isInSubscriptionsView ? 'subscriptions' : communityAddress} />
|
||||
<ImageBanner key={bannerKey} />
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.boardTitle}>
|
||||
|
||||
Reference in New Issue
Block a user