From a9040a54258065c5a9d01ec39dad8e2effd9f7d8 Mon Sep 17 00:00:00 2001 From: Tommaso Casaburi Date: Sat, 1 Aug 2026 19:12:20 +0200 Subject: [PATCH] perf(settings): speed up board settings navigation (#1191) * perf(settings): speed up board settings navigation * perf(settings): parallelize account section loading --- src/app.tsx | 2 +- .../__tests__/settings-modal.test.tsx | 22 +++--- .../settings-modal/settings-modal.tsx | 69 ++++++++++++++----- src/index.tsx | 2 +- 4 files changed, 63 insertions(+), 32 deletions(-) diff --git a/src/app.tsx b/src/app.tsx index b9619e79..ac0d36eb 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -56,6 +56,7 @@ import BoardBlotter from './components/board-blotter/board-blotter'; import BoardsBar from './components/boards-bar/boards-bar'; import ExternalQuoteStatus from './components/external-quote-status/external-quote-status'; import ModEmptyState from './components/mod-empty-state/mod-empty-state'; +import SettingsModal from './components/settings-modal'; const AccountDataEditor = lazy(() => import('./views/account-data-editor')); const BoardsBarEditModal = lazy(() => import('./components/boards-bar-edit-modal')); @@ -64,7 +65,6 @@ const ChallengeModal = lazy(() => import('./components/challenge-modal')); const DirectoryModal = lazy(() => import('./components/directory-modal')); const DisclaimerModal = lazy(() => import('./components/disclaimer-modal')); const ReplyModal = lazy(() => import('./components/reply-modal')); -const SettingsModal = lazy(() => import('./components/settings-modal')); const SettingsUpgradeModal = lazy(() => import('./components/settings-upgrade-modal')); // Preload all theme assets (buttons, backgrounds) immediately on app load diff --git a/src/components/settings-modal/__tests__/settings-modal.test.tsx b/src/components/settings-modal/__tests__/settings-modal.test.tsx index 2958c354..b2b4111b 100644 --- a/src/components/settings-modal/__tests__/settings-modal.test.tsx +++ b/src/components/settings-modal/__tests__/settings-modal.test.tsx @@ -76,8 +76,8 @@ const LocationProbe = () => { let root: Root; let container: HTMLDivElement; -const render = (initialEntry = '/all/settings') => { - act(() => { +const render = async (initialEntry = '/all/settings') => { + await act(async () => { root.render( createElement(MemoryRouter, { initialEntries: [initialEntry] }, createElement(React.Fragment, {}, createElement(SettingsModal), createElement(LocationProbe))), ); @@ -123,8 +123,8 @@ describe('SettingsModal', () => { container.remove(); }); - it('opens the account section for crypto subsection hashes', () => { - render('/all/settings#crypto-wallet-settings'); + it('opens the account section for crypto subsection hashes', async () => { + await render('/all/settings#crypto-wallet-settings'); expect(container.querySelector('[data-testid="account-settings"]')).not.toBeNull(); expect(container.querySelector('[data-testid="crypto-address-setting"]')).not.toBeNull(); @@ -132,7 +132,7 @@ describe('SettingsModal', () => { }); it('updates the section query when sections open and close', async () => { - render('/all/settings?section=account-settings'); + await render('/all/settings?section=account-settings'); expect(getLocationText()).toBe('/all/settings?section=account-settings'); @@ -160,7 +160,7 @@ describe('SettingsModal', () => { }); it('expands and collapses all settings sections', async () => { - render('/all/settings'); + await render('/all/settings'); const expandAllControl = Array.from(container.querySelectorAll('button')).find((candidate) => (candidate.textContent ?? '').includes('expand_all_settings')); if (!expandAllControl) { @@ -208,7 +208,7 @@ describe('SettingsModal', () => { }; useSettingsUpgradeReviewStore.getState().dismissUpgradeKeys([upgradeKey]); - render('/all/settings'); + await render('/all/settings'); expect(container.textContent).toContain('settings_upgrade_review_notice'); const reviewButton = Array.from(container.querySelectorAll('button')).find((candidate) => candidate.textContent === 'settings_upgrade_review_button'); @@ -233,14 +233,14 @@ describe('SettingsModal', () => { expect(useSettingsUpgradeReviewStore.getState().reviewRequestId).toBe(1); }); - it.each(['/all/settings?section=p2p-stats-settings', '/all/settings#p2p-stats-settings'])('opens the p2p stats section from route %s', (route) => { - render(route); + it.each(['/all/settings?section=p2p-stats-settings', '/all/settings#p2p-stats-settings'])('opens the p2p stats section from route %s', async (route) => { + await render(route); expect(container.querySelector('[data-testid="p2p-stats-settings-panel"]')).not.toBeNull(); }); it('closes the modal when the overlay is clicked', async () => { - render('/all/settings#interface-settings'); + await render('/all/settings#interface-settings'); const overlay = container.querySelector('button'); if (!overlay) { @@ -255,7 +255,7 @@ describe('SettingsModal', () => { }); it('closes the modal when Escape is pressed', async () => { - render('/all/settings'); + await render('/all/settings'); await act(async () => { document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true })); diff --git a/src/components/settings-modal/settings-modal.tsx b/src/components/settings-modal/settings-modal.tsx index 390aa53e..24121eb5 100644 --- a/src/components/settings-modal/settings-modal.tsx +++ b/src/components/settings-modal/settings-modal.tsx @@ -1,22 +1,23 @@ -import { useCallback, useEffect, useMemo, useState } from 'react'; +import { lazy, Suspense, useCallback, useEffect, useMemo, useState } from 'react'; import { useAccount, usePkcRpcSettings } from '@bitsocial/bitsocial-react-hooks'; import { useLocation, useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import styles from './settings-modal.module.css'; -import AccountSettings from './account-settings/account-settings'; -import CryptoAddressSetting from './crypto-address-setting/crypto-address-setting'; -import CryptoWalletsSetting from './crypto-wallets-setting/crypto-wallets-setting'; -import InterfaceSettings from './interface-settings/interface-settings'; -import MediaHostingSettings from './media-hosting-settings/media-hosting-settings'; -import AdvancedSettings from './advanced-settings/advanced-settings'; -import SubscriptionsSetting from './subscriptions-setting/subscriptions-setting'; -import TrustedBoardLinksSetting from './trusted-board-links-setting/trusted-board-links-setting'; -import P2PStatsSettings from './p2p-stats-settings/p2p-stats-settings'; import { P2P_STATS_SECTION_ID, shouldShowP2PSettingsSection } from '../../lib/p2p-runtime'; import { getReviewableSettingsUpgrades, getSettingsUpgradeKey, type SettingsUpgradeAccount } from '../../lib/settings-upgrades'; import useSettingsUpgradeReviewStore from '../../stores/use-settings-upgrade-review-store'; import { getSettingsSectionPath } from '../../lib/utils/route-utils'; +const AccountSettings = lazy(() => import('./account-settings/account-settings')); +const CryptoAddressSetting = lazy(() => import('./crypto-address-setting/crypto-address-setting')); +const CryptoWalletsSetting = lazy(() => import('./crypto-wallets-setting/crypto-wallets-setting')); +const InterfaceSettings = lazy(() => import('./interface-settings/interface-settings')); +const MediaHostingSettings = lazy(() => import('./media-hosting-settings/media-hosting-settings')); +const AdvancedSettings = lazy(() => import('./advanced-settings/advanced-settings')); +const SubscriptionsSetting = lazy(() => import('./subscriptions-setting/subscriptions-setting')); +const TrustedBoardLinksSetting = lazy(() => import('./trusted-board-links-setting/trusted-board-links-setting')); +const P2PStatsSettings = lazy(() => import('./p2p-stats-settings/p2p-stats-settings')); + const allSectionIds = [ 'interface-settings', 'media-hosting-settings', @@ -164,14 +165,22 @@ const SettingsModal = () => { {t('interface')} - {showInterfaceSettings && } + {showInterfaceSettings && ( + + + + )}
- {showMediaHostingSettings && } + {showMediaHostingSettings && ( + + + + )}
{showAccountSettings && ( <> - + + +
{t('crypto_address')}
- + + +
{t('crypto_wallets')}
- + + + )}
@@ -193,21 +208,33 @@ const SettingsModal = () => { {t('board_subscriptions')}
- {showSubscriptionsSettings && } + {showSubscriptionsSettings && ( + + + + )} - {showBoardLinkPermissionsSettings && } + {showBoardLinkPermissionsSettings && ( + + + + )}
- {showAdvancedSettings && } + {showAdvancedSettings && ( + + + + )} {sectionIds.includes(P2P_STATS_SECTION_ID) && ( <>
@@ -216,7 +243,11 @@ const SettingsModal = () => { {t('p2p_stats')}
- {showP2PStatsSettings && } + {showP2PStatsSettings && ( + + + + )} )} {showSettingsUpgradeReview && ( diff --git a/src/index.tsx b/src/index.tsx index ee55b6c3..ec2e23f1 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -55,7 +55,7 @@ const renderRoot = async () => { root.render( - + {Analytics && }