Skip to content

Commit 909a5da

Browse files
committed
refactor: migrate views and components to useConfig()
Convert React components from direct config import to useConfig() hook: - Views: Terms, Bridge (all subcomponents), Redeem, TxHistory - Components: ConfigurablePageHeader, FooterNavBar - Contexts: WalletProvider - Icons: PoweredBy
1 parent 23ab3b7 commit 909a5da

27 files changed

Lines changed: 206 additions & 84 deletions

src/components/ConfigurablePageHeader.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import React from 'react';
2-
import config from 'config';
2+
import { useConfig } from 'contexts/ConfigContext';
33
import PageHeader from 'components/PageHeader';
44
import type { Alignment } from 'components/Header';
55

66
const ConfigurablePageHeader = () => {
7+
const config = useConfig();
78
const defaults: { text: string; align: Alignment } = {
89
text: '',
910
align: 'left',

src/components/FooterNavBar.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Box, useTheme } from '@mui/material';
44
import { ICON } from 'utils/style';
55
import type { Route } from 'store/router';
66
import { setRoute } from 'store/router';
7-
import config from 'config';
7+
import { useConfig } from 'contexts/ConfigContext';
88
import type { MenuEntry } from 'config/ui';
99

1010
type MenuItem = {
@@ -28,6 +28,7 @@ function defaultMenuItems(navigate: (name: Route) => void): MenuItem[] {
2828
}
2929

3030
export default function FooterNavBar() {
31+
const config = useConfig();
3132
const theme = useTheme();
3233

3334
const styles = useMemo(

src/contexts/wallet/WalletContext.test.tsx

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import * as React from 'react';
22
import { describe, it, expect, vi, beforeEach } from 'vitest';
33
import { renderHook, act } from '@testing-library/react';
44
import { useContext } from 'react';
@@ -8,13 +8,36 @@ import WalletProvider from './WalletProvider';
88
import WalletContext from './WalletContext';
99
import { internalWalletProvider } from 'utils/wallet/InternalWalletProvider';
1010
import { TransferWallet } from 'utils/wallet';
11+
import { TestConfigContext } from 'utils/testHelpers';
1112

1213
const mockStore = configureStore({
1314
reducer: {
1415
wallet: (state = { sending: undefined, receiving: undefined }) => state,
1516
},
1617
});
1718

19+
// Mock config object provided via TestConfigContext
20+
const mockConfig = {
21+
network: 'Mainnet',
22+
chains: {
23+
Ethereum: { sdkName: 'Ethereum' },
24+
Solana: { sdkName: 'Solana' },
25+
},
26+
triggerEvent: vi.fn(),
27+
cacheKey: vi.fn((key: string) => `test-${key}`),
28+
};
29+
30+
// Mock useConfig to read from TestConfigContext
31+
vi.mock('contexts/ConfigContext', () => ({
32+
useConfig: () => {
33+
const context = React.useContext(TestConfigContext);
34+
if (!context) {
35+
throw new Error('useConfig must be used within a ConfigProvider');
36+
}
37+
return context;
38+
},
39+
}));
40+
1841
vi.mock('config', () => ({
1942
default: {
2043
network: 'Mainnet',
@@ -74,11 +97,13 @@ describe('WalletContext with InternalWalletProvider', () => {
7497
});
7598

7699
const wrapper = ({ children }: { children: React.ReactNode }) => (
77-
<Provider store={mockStore}>
78-
<WalletProvider provider={internalWalletProvider}>
79-
{children}
80-
</WalletProvider>
81-
</Provider>
100+
<TestConfigContext.Provider value={mockConfig}>
101+
<Provider store={mockStore}>
102+
<WalletProvider provider={internalWalletProvider}>
103+
{children}
104+
</WalletProvider>
105+
</Provider>
106+
</TestConfigContext.Provider>
82107
);
83108

84109
it('connect and disconnect sending and receiving wallets', async () => {

src/contexts/wallet/WalletProvider.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React, { useState, useCallback, useMemo, useEffect } from 'react';
33
import type { Chain } from '@wormhole-foundation/sdk';
44
import { chainToPlatform } from '@wormhole-foundation/sdk';
55
import { useDispatch } from 'react-redux';
6-
import config from 'config';
6+
import { useConfig } from 'contexts/ConfigContext';
77
import type { Wallet, WormholeConnectWalletProvider } from 'utils/wallet';
88
import { TransferWallet } from 'utils/wallet';
99
import {
@@ -23,6 +23,7 @@ function WalletProvider({
2323
children,
2424
provider: walletProvider,
2525
}: WalletProviderProps) {
26+
const config = useConfig();
2627
const [isConnecting, setIsConnecting] = useState(false);
2728
const dispatch = useDispatch();
2829

src/icons/PoweredBy.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useMemo } from 'react';
2-
import config from 'config';
2+
import { useConfig } from 'contexts/ConfigContext';
33
import Box from '@mui/material/Box';
44
import { useTheme } from '@mui/material/styles';
55
import Link from '@mui/material/Link';
@@ -121,6 +121,7 @@ function PartnerLogo(props: { src: string }) {
121121
}
122122

123123
function PoweredByIcon(props: { color: string }) {
124+
const config = useConfig();
124125
const styles = {
125126
container: {
126127
display: 'flex',

src/views/Terms.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import React from 'react';
22
import Box from '@mui/material/Box';
33
import FooterNavBar from 'components/FooterNavBar';
4-
import config from 'config';
4+
import { useConfig } from 'contexts/ConfigContext';
55
import { FormContent } from 'components/v3/FormContent';
66
import { useTheme } from '@mui/material';
77
import Header from 'components/Header';
88
import { BackButton } from 'components/v3/BackButton';
99

1010
function Terms() {
11+
const config = useConfig();
1112
const theme: any = useTheme();
1213
const termsUrl = config.ui.termsOfServiceUrl || 'https://portalbridge.com';
1314

src/views/v3/Bridge/AssetPicker/FeeOffset.test.tsx

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import * as React from 'react';
22
import { describe, it, expect, vi, beforeEach } from 'vitest';
33
import { render, screen } from '@testing-library/react';
44
import { Provider } from 'react-redux';
@@ -8,13 +8,32 @@ import { amount as sdkAmount } from '@wormhole-foundation/sdk';
88

99
import FeeOffset from './FeeOffset';
1010
import { dark } from 'theme';
11-
import config from 'config';
12-
import { createMockToken } from 'utils/testHelpers';
11+
import { createMockToken, TestConfigContext } from 'utils/testHelpers';
1312

1413
const theme = createTheme({
1514
palette: dark as any,
1615
});
1716

17+
// Mock config object provided via TestConfigContext
18+
const mockConfig = {
19+
ui: {
20+
experimental: {
21+
feeOffsetting: true,
22+
},
23+
},
24+
};
25+
26+
// Mock useConfig to read from TestConfigContext
27+
vi.mock('contexts/ConfigContext', () => ({
28+
useConfig: () => {
29+
const context = React.useContext(TestConfigContext);
30+
if (!context) {
31+
throw new Error('useConfig must be used within a ConfigProvider');
32+
}
33+
return context;
34+
},
35+
}));
36+
1837
// Mock the calculateFeeOffset function
1938
vi.mock('utils/fees', () => ({
2039
calculateFeeOffset: vi.fn(),
@@ -28,17 +47,6 @@ vi.mock('hooks/useGetTokens', () => ({
2847
})),
2948
}));
3049

31-
// Mock the config module
32-
vi.mock('config', () => ({
33-
default: {
34-
ui: {
35-
experimental: {
36-
feeOffsetting: true,
37-
},
38-
},
39-
},
40-
}));
41-
4250
const mockToken = createMockToken({
4351
symbol: 'USDC',
4452
name: 'USD Coin',
@@ -61,9 +69,11 @@ const AppWrapper =
6169
(store: any) =>
6270
({ children }: { children: React.ReactNode }) =>
6371
(
64-
<Provider store={store}>
65-
<ThemeProvider theme={theme}>{children}</ThemeProvider>
66-
</Provider>
72+
<TestConfigContext.Provider value={mockConfig}>
73+
<Provider store={store}>
74+
<ThemeProvider theme={theme}>{children}</ThemeProvider>
75+
</Provider>
76+
</TestConfigContext.Provider>
6777
);
6878

6979
describe('FeeOffset', () => {
@@ -122,8 +132,13 @@ describe('FeeOffset', () => {
122132
const { calculateFeeOffset } = vi.mocked(await import('utils/fees'));
123133
const { useGetTokens } = vi.mocked(await import('hooks/useGetTokens'));
124134

125-
const mockedConfig = vi.mocked(config);
126-
mockedConfig.ui.experimental!.feeOffsetting = false;
135+
const disabledConfig = {
136+
ui: {
137+
experimental: {
138+
feeOffsetting: false,
139+
},
140+
},
141+
};
127142

128143
const feeOffset = sdkAmount.fromBaseUnits(1000n, 6);
129144
calculateFeeOffset.mockReturnValue(feeOffset);
@@ -137,14 +152,20 @@ describe('FeeOffset', () => {
137152
'TestRoute',
138153
);
139154

155+
// Use wrapper with disabled feeOffsetting config
156+
const DisabledWrapper = ({ children }: { children: React.ReactNode }) => (
157+
<TestConfigContext.Provider value={disabledConfig}>
158+
<Provider store={store}>
159+
<ThemeProvider theme={theme}>{children}</ThemeProvider>
160+
</Provider>
161+
</TestConfigContext.Provider>
162+
);
163+
140164
render(<FeeOffset />, {
141-
wrapper: AppWrapper(store),
165+
wrapper: DisabledWrapper,
142166
});
143167

144168
expect(screen.queryByText(/\+.*USDC/)).not.toBeInTheDocument();
145-
146-
// Reset config for other tests
147-
mockedConfig.ui.experimental!.feeOffsetting = true;
148169
});
149170

150171
it('does not render when feeOffsetAmount is undefined', async () => {

src/views/v3/Bridge/AssetPicker/FeeOffset.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Box, Tooltip, Typography, useTheme } from '@mui/material';
44
import InfoOutlineIcon from '@mui/icons-material/InfoOutline';
55
import { amount as sdkAmount } from '@wormhole-foundation/sdk';
66

7-
import config from 'config';
7+
import { useConfig } from 'contexts/ConfigContext';
88
import type { RootState } from 'store';
99
import { calculateFeeOffset } from 'utils/fees';
1010
import { useGetTokens } from 'hooks/useGetTokens';
@@ -14,6 +14,7 @@ import { useGetTokens } from 'hooks/useGetTokens';
1414
* exactly what they requested after protocol fees are deducted
1515
*/
1616
function FeeOffset() {
17+
const config = useConfig();
1718
const theme: any = useTheme();
1819
const { amount, route: selectedRoute } = useSelector(
1920
(state: RootState) => state.transferInput,

src/views/v3/Bridge/AssetPicker/PercentButtons.test.tsx

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import * as React from 'react';
22
import { describe, it, expect, vi, beforeEach } from 'vitest';
33
import { render, screen, fireEvent } from '@testing-library/react';
44
import { Provider } from 'react-redux';
@@ -8,12 +8,35 @@ import { amount as sdkAmount } from '@wormhole-foundation/sdk';
88

99
import PercentButtons from './PercentButtons';
1010
import { dark } from 'theme';
11-
import { createMockToken } from 'utils/testHelpers';
11+
import { createMockToken, TestConfigContext } from 'utils/testHelpers';
1212

1313
const theme = createTheme({
1414
palette: dark as any,
1515
});
1616

17+
// Mock config object provided via TestConfigContext
18+
const mockConfig = {
19+
routes: {
20+
get: vi.fn(),
21+
},
22+
ui: {
23+
experimental: {
24+
feeOffsetting: false,
25+
},
26+
},
27+
};
28+
29+
// Mock useConfig to read from TestConfigContext
30+
vi.mock('contexts/ConfigContext', () => ({
31+
useConfig: () => {
32+
const context = React.useContext(TestConfigContext);
33+
if (!context) {
34+
throw new Error('useConfig must be used within a ConfigProvider');
35+
}
36+
return context;
37+
},
38+
}));
39+
1740
// Mock the hooks and utilities
1841
vi.mock('hooks/useGetTokens', () => ({
1942
useGetTokens: vi.fn(() => ({
@@ -43,19 +66,6 @@ vi.mock('@wormhole-foundation/sdk', async () => {
4366
};
4467
});
4568

46-
vi.mock('config', () => ({
47-
default: {
48-
routes: {
49-
get: vi.fn(),
50-
},
51-
ui: {
52-
experimental: {
53-
feeOffsetting: false,
54-
},
55-
},
56-
},
57-
}));
58-
5969
const mockToken = createMockToken({
6070
symbol: 'ETH',
6171
name: 'Ethereum',
@@ -77,9 +87,11 @@ const AppWrapper =
7787
(store: any) =>
7888
({ children }: { children: React.ReactNode }) =>
7989
(
80-
<Provider store={store}>
81-
<ThemeProvider theme={theme}>{children}</ThemeProvider>
82-
</Provider>
90+
<TestConfigContext.Provider value={mockConfig}>
91+
<Provider store={store}>
92+
<ThemeProvider theme={theme}>{children}</ThemeProvider>
93+
</Provider>
94+
</TestConfigContext.Provider>
8395
);
8496

8597
describe('PercentButtons', () => {

src/views/v3/Bridge/AssetPicker/PercentButtons.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
import type { Chain } from '@wormhole-foundation/sdk';
1212
import { amount as sdkAmount, isSameToken } from '@wormhole-foundation/sdk';
1313

14-
import config from 'config';
14+
import { useConfig } from 'contexts/ConfigContext';
1515
import type { RootState } from 'store';
1616
import { calculateFeeOffset } from 'utils/fees';
1717
import { getGasReserve } from 'utils/gasReserve';
@@ -36,6 +36,7 @@ const GAS_RESERVE_INFO_MESSAGE =
3636
'A small amount of the network token balance is reserved to cover the network cost of this transaction.';
3737

3838
function PercentButtons(props: Props) {
39+
const config = useConfig();
3940
const theme: any = useTheme();
4041
const { route: selectedRoute } = useSelector(
4142
(state: RootState) => state.transferInput,

0 commit comments

Comments
 (0)