mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
perf(settings): speed up board settings navigation (#1191)
* perf(settings): speed up board settings navigation * perf(settings): parallelize account section loading
This commit is contained in:
+1
-1
@@ -56,6 +56,7 @@ import BoardBlotter from './components/board-blotter/board-blotter';
|
|||||||
import BoardsBar from './components/boards-bar/boards-bar';
|
import BoardsBar from './components/boards-bar/boards-bar';
|
||||||
import ExternalQuoteStatus from './components/external-quote-status/external-quote-status';
|
import ExternalQuoteStatus from './components/external-quote-status/external-quote-status';
|
||||||
import ModEmptyState from './components/mod-empty-state/mod-empty-state';
|
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 AccountDataEditor = lazy(() => import('./views/account-data-editor'));
|
||||||
const BoardsBarEditModal = lazy(() => import('./components/boards-bar-edit-modal'));
|
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 DirectoryModal = lazy(() => import('./components/directory-modal'));
|
||||||
const DisclaimerModal = lazy(() => import('./components/disclaimer-modal'));
|
const DisclaimerModal = lazy(() => import('./components/disclaimer-modal'));
|
||||||
const ReplyModal = lazy(() => import('./components/reply-modal'));
|
const ReplyModal = lazy(() => import('./components/reply-modal'));
|
||||||
const SettingsModal = lazy(() => import('./components/settings-modal'));
|
|
||||||
const SettingsUpgradeModal = lazy(() => import('./components/settings-upgrade-modal'));
|
const SettingsUpgradeModal = lazy(() => import('./components/settings-upgrade-modal'));
|
||||||
|
|
||||||
// Preload all theme assets (buttons, backgrounds) immediately on app load
|
// Preload all theme assets (buttons, backgrounds) immediately on app load
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ const LocationProbe = () => {
|
|||||||
let root: Root;
|
let root: Root;
|
||||||
let container: HTMLDivElement;
|
let container: HTMLDivElement;
|
||||||
|
|
||||||
const render = (initialEntry = '/all/settings') => {
|
const render = async (initialEntry = '/all/settings') => {
|
||||||
act(() => {
|
await act(async () => {
|
||||||
root.render(
|
root.render(
|
||||||
createElement(MemoryRouter, { initialEntries: [initialEntry] }, createElement(React.Fragment, {}, createElement(SettingsModal), createElement(LocationProbe))),
|
createElement(MemoryRouter, { initialEntries: [initialEntry] }, createElement(React.Fragment, {}, createElement(SettingsModal), createElement(LocationProbe))),
|
||||||
);
|
);
|
||||||
@@ -123,8 +123,8 @@ describe('SettingsModal', () => {
|
|||||||
container.remove();
|
container.remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('opens the account section for crypto subsection hashes', () => {
|
it('opens the account section for crypto subsection hashes', async () => {
|
||||||
render('/all/settings#crypto-wallet-settings');
|
await render('/all/settings#crypto-wallet-settings');
|
||||||
|
|
||||||
expect(container.querySelector('[data-testid="account-settings"]')).not.toBeNull();
|
expect(container.querySelector('[data-testid="account-settings"]')).not.toBeNull();
|
||||||
expect(container.querySelector('[data-testid="crypto-address-setting"]')).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 () => {
|
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');
|
expect(getLocationText()).toBe('/all/settings?section=account-settings');
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ describe('SettingsModal', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('expands and collapses all settings sections', async () => {
|
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'));
|
const expandAllControl = Array.from(container.querySelectorAll('button')).find((candidate) => (candidate.textContent ?? '').includes('expand_all_settings'));
|
||||||
if (!expandAllControl) {
|
if (!expandAllControl) {
|
||||||
@@ -208,7 +208,7 @@ describe('SettingsModal', () => {
|
|||||||
};
|
};
|
||||||
useSettingsUpgradeReviewStore.getState().dismissUpgradeKeys([upgradeKey]);
|
useSettingsUpgradeReviewStore.getState().dismissUpgradeKeys([upgradeKey]);
|
||||||
|
|
||||||
render('/all/settings');
|
await render('/all/settings');
|
||||||
|
|
||||||
expect(container.textContent).toContain('settings_upgrade_review_notice');
|
expect(container.textContent).toContain('settings_upgrade_review_notice');
|
||||||
const reviewButton = Array.from(container.querySelectorAll('button')).find((candidate) => candidate.textContent === 'settings_upgrade_review_button');
|
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);
|
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) => {
|
it.each(['/all/settings?section=p2p-stats-settings', '/all/settings#p2p-stats-settings'])('opens the p2p stats section from route %s', async (route) => {
|
||||||
render(route);
|
await render(route);
|
||||||
|
|
||||||
expect(container.querySelector('[data-testid="p2p-stats-settings-panel"]')).not.toBeNull();
|
expect(container.querySelector('[data-testid="p2p-stats-settings-panel"]')).not.toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('closes the modal when the overlay is clicked', async () => {
|
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');
|
const overlay = container.querySelector('button');
|
||||||
if (!overlay) {
|
if (!overlay) {
|
||||||
@@ -255,7 +255,7 @@ describe('SettingsModal', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('closes the modal when Escape is pressed', async () => {
|
it('closes the modal when Escape is pressed', async () => {
|
||||||
render('/all/settings');
|
await render('/all/settings');
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
||||||
|
|||||||
@@ -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 { useAccount, usePkcRpcSettings } from '@bitsocial/bitsocial-react-hooks';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import styles from './settings-modal.module.css';
|
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 { P2P_STATS_SECTION_ID, shouldShowP2PSettingsSection } from '../../lib/p2p-runtime';
|
||||||
import { getReviewableSettingsUpgrades, getSettingsUpgradeKey, type SettingsUpgradeAccount } from '../../lib/settings-upgrades';
|
import { getReviewableSettingsUpgrades, getSettingsUpgradeKey, type SettingsUpgradeAccount } from '../../lib/settings-upgrades';
|
||||||
import useSettingsUpgradeReviewStore from '../../stores/use-settings-upgrade-review-store';
|
import useSettingsUpgradeReviewStore from '../../stores/use-settings-upgrade-review-store';
|
||||||
import { getSettingsSectionPath } from '../../lib/utils/route-utils';
|
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 = [
|
const allSectionIds = [
|
||||||
'interface-settings',
|
'interface-settings',
|
||||||
'media-hosting-settings',
|
'media-hosting-settings',
|
||||||
@@ -164,14 +165,22 @@ const SettingsModal = () => {
|
|||||||
{t('interface')}
|
{t('interface')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{showInterfaceSettings && <InterfaceSettings />}
|
{showInterfaceSettings && (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<InterfaceSettings />
|
||||||
|
</Suspense>
|
||||||
|
)}
|
||||||
<div id='media-hosting-settings' className={`${styles.setting} ${styles.category}`}>
|
<div id='media-hosting-settings' className={`${styles.setting} ${styles.category}`}>
|
||||||
<button type='button' className={styles.categoryButton} onClick={() => handleCategoryClick('media-hosting-settings')}>
|
<button type='button' className={styles.categoryButton} onClick={() => handleCategoryClick('media-hosting-settings')}>
|
||||||
<span className={showMediaHostingSettings ? styles.hideButton : styles.showButton} />
|
<span className={showMediaHostingSettings ? styles.hideButton : styles.showButton} />
|
||||||
{t('media_hosting')}
|
{t('media_hosting')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{showMediaHostingSettings && <MediaHostingSettings />}
|
{showMediaHostingSettings && (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<MediaHostingSettings />
|
||||||
|
</Suspense>
|
||||||
|
)}
|
||||||
<div id='account-settings' className={`${styles.setting} ${styles.category}`}>
|
<div id='account-settings' className={`${styles.setting} ${styles.category}`}>
|
||||||
<button type='button' className={styles.categoryButton} onClick={() => handleCategoryClick('account-settings')}>
|
<button type='button' className={styles.categoryButton} onClick={() => handleCategoryClick('account-settings')}>
|
||||||
<span className={showAccountSettings ? styles.hideButton : styles.showButton} />
|
<span className={showAccountSettings ? styles.hideButton : styles.showButton} />
|
||||||
@@ -180,11 +189,17 @@ const SettingsModal = () => {
|
|||||||
</div>
|
</div>
|
||||||
{showAccountSettings && (
|
{showAccountSettings && (
|
||||||
<>
|
<>
|
||||||
<AccountSettings />
|
<Suspense fallback={null}>
|
||||||
|
<AccountSettings />
|
||||||
|
</Suspense>
|
||||||
<div className={styles.subSectionHeader}>{t('crypto_address')}</div>
|
<div className={styles.subSectionHeader}>{t('crypto_address')}</div>
|
||||||
<CryptoAddressSetting />
|
<Suspense fallback={null}>
|
||||||
|
<CryptoAddressSetting />
|
||||||
|
</Suspense>
|
||||||
<div className={styles.subSectionHeader}>{t('crypto_wallets')}</div>
|
<div className={styles.subSectionHeader}>{t('crypto_wallets')}</div>
|
||||||
<CryptoWalletsSetting />
|
<Suspense fallback={null}>
|
||||||
|
<CryptoWalletsSetting />
|
||||||
|
</Suspense>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div id='subscriptions-settings' className={`${styles.setting} ${styles.category}`}>
|
<div id='subscriptions-settings' className={`${styles.setting} ${styles.category}`}>
|
||||||
@@ -193,21 +208,33 @@ const SettingsModal = () => {
|
|||||||
{t('board_subscriptions')}
|
{t('board_subscriptions')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{showSubscriptionsSettings && <SubscriptionsSetting />}
|
{showSubscriptionsSettings && (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<SubscriptionsSetting />
|
||||||
|
</Suspense>
|
||||||
|
)}
|
||||||
<div id='board-link-permissions-settings' className={`${styles.setting} ${styles.category}`}>
|
<div id='board-link-permissions-settings' className={`${styles.setting} ${styles.category}`}>
|
||||||
<button type='button' className={styles.categoryButton} onClick={() => handleCategoryClick('board-link-permissions-settings')}>
|
<button type='button' className={styles.categoryButton} onClick={() => handleCategoryClick('board-link-permissions-settings')}>
|
||||||
<span className={showBoardLinkPermissionsSettings ? styles.hideButton : styles.showButton} />
|
<span className={showBoardLinkPermissionsSettings ? styles.hideButton : styles.showButton} />
|
||||||
{t('board_link_permissions')}
|
{t('board_link_permissions')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{showBoardLinkPermissionsSettings && <TrustedBoardLinksSetting />}
|
{showBoardLinkPermissionsSettings && (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<TrustedBoardLinksSetting />
|
||||||
|
</Suspense>
|
||||||
|
)}
|
||||||
<div id='advanced-settings' className={`${styles.setting} ${styles.category}`}>
|
<div id='advanced-settings' className={`${styles.setting} ${styles.category}`}>
|
||||||
<button type='button' className={styles.categoryButton} onClick={() => handleCategoryClick('advanced-settings')}>
|
<button type='button' className={styles.categoryButton} onClick={() => handleCategoryClick('advanced-settings')}>
|
||||||
<span className={showAdvancedSettings ? styles.hideButton : styles.showButton} />
|
<span className={showAdvancedSettings ? styles.hideButton : styles.showButton} />
|
||||||
{t('advanced_settings')}
|
{t('advanced_settings')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{showAdvancedSettings && <AdvancedSettings />}
|
{showAdvancedSettings && (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<AdvancedSettings />
|
||||||
|
</Suspense>
|
||||||
|
)}
|
||||||
{sectionIds.includes(P2P_STATS_SECTION_ID) && (
|
{sectionIds.includes(P2P_STATS_SECTION_ID) && (
|
||||||
<>
|
<>
|
||||||
<div id={P2P_STATS_SECTION_ID} className={`${styles.setting} ${styles.category}`}>
|
<div id={P2P_STATS_SECTION_ID} className={`${styles.setting} ${styles.category}`}>
|
||||||
@@ -216,7 +243,11 @@ const SettingsModal = () => {
|
|||||||
{t('p2p_stats')}
|
{t('p2p_stats')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{showP2PStatsSettings && <P2PStatsSettings />}
|
{showP2PStatsSettings && (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<P2PStatsSettings />
|
||||||
|
</Suspense>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{showSettingsUpgradeReview && (
|
{showSettingsUpgradeReview && (
|
||||||
|
|||||||
+1
-1
@@ -55,7 +55,7 @@ const renderRoot = async () => {
|
|||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<Router>
|
<Router useTransitions={false}>
|
||||||
<AppUpdateRegistration />
|
<AppUpdateRegistration />
|
||||||
<App />
|
<App />
|
||||||
{Analytics && <Analytics />}
|
{Analytics && <Analytics />}
|
||||||
|
|||||||
Reference in New Issue
Block a user