Skip to content

Commit fb70095

Browse files
committed
Merge branch 'frontend-migrate-rates-store-into-context'
2 parents be7ff87 + 373b7e8 commit fb70095

File tree

13 files changed

+296
-175
lines changed

13 files changed

+296
-175
lines changed

frontends/web/src/app.tsx

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import { DarkModeProvider } from './contexts/DarkmodeProvider';
4242
import { AppProvider } from './contexts/AppProvider';
4343
import { AuthRequired } from './components/auth/authrequired';
4444
import { WCWeb3WalletProvider } from './contexts/WCWeb3WalletProvider';
45+
import { RatesProvider } from './contexts/RatesProvider';
4546
import { WCSigningRequest } from './components/wallet-connect/incoming-signing-request';
4647

4748
type State = {
@@ -182,49 +183,51 @@ class App extends Component<Props, State> {
182183
<ConnectedApp>
183184
<AppProvider>
184185
<DarkModeProvider>
185-
<WCWeb3WalletProvider>
186-
<Darkmode />
187-
<div className="app">
188-
<AuthRequired/>
189-
<Sidebar
190-
accounts={activeAccounts}
191-
deviceIDs={deviceIDs}
192-
/>
193-
<div className="appContent flex flex-column flex-1" style={{ minWidth: 0 }}>
194-
<Update />
195-
<Banner msgKey="bitbox01" />
196-
<Banner msgKey="bitbox02" />
197-
<MobileDataWarning />
198-
<WCSigningRequest />
199-
<Aopp />
200-
<KeystoreConnectPrompt />
201-
{
202-
Object.entries(devices).map(([deviceID, productName]) => {
203-
if (productName === 'bitbox02') {
204-
return (
205-
<Fragment key={deviceID}>
206-
<BitBox02Wizard
207-
deviceID={deviceID}
208-
/>
209-
</Fragment>
210-
);
211-
}
212-
return null;
213-
})
214-
}
215-
<AppRouter
216-
accounts={accounts}
217-
activeAccounts={activeAccounts}
186+
<RatesProvider>
187+
<WCWeb3WalletProvider>
188+
<Darkmode />
189+
<div className="app">
190+
<AuthRequired/>
191+
<Sidebar
192+
accounts={activeAccounts}
218193
deviceIDs={deviceIDs}
219-
devices={devices}
220-
devicesKey={this.devicesKey}
221194
/>
222-
<RouterWatcher onChange={this.handleRoute} />
195+
<div className="appContent flex flex-column flex-1" style={{ minWidth: 0 }}>
196+
<Update />
197+
<Banner msgKey="bitbox01" />
198+
<Banner msgKey="bitbox02" />
199+
<MobileDataWarning />
200+
<WCSigningRequest />
201+
<Aopp />
202+
<KeystoreConnectPrompt />
203+
{
204+
Object.entries(devices).map(([deviceID, productName]) => {
205+
if (productName === 'bitbox02') {
206+
return (
207+
<Fragment key={deviceID}>
208+
<BitBox02Wizard
209+
deviceID={deviceID}
210+
/>
211+
</Fragment>
212+
);
213+
}
214+
return null;
215+
})
216+
}
217+
<AppRouter
218+
accounts={accounts}
219+
activeAccounts={activeAccounts}
220+
deviceIDs={deviceIDs}
221+
devices={devices}
222+
devicesKey={this.devicesKey}
223+
/>
224+
<RouterWatcher onChange={this.handleRoute} />
225+
</div>
226+
<Alert />
227+
<Confirm />
223228
</div>
224-
<Alert />
225-
<Confirm />
226-
</div>
227-
</WCWeb3WalletProvider>
229+
</WCWeb3WalletProvider>
230+
</RatesProvider>
228231
</DarkModeProvider>
229232
</AppProvider>
230233
</ConnectedApp>

frontends/web/src/components/balance/balance.test.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
17-
import { describe, expect, it, vi } from 'vitest';
16+
import { useContext } from 'react';
17+
import { Mock, describe, expect, it, vi } from 'vitest';
1818
import { render } from '@testing-library/react';
1919
import { IBalance } from '../../api/account';
2020
import I18NWrapper from '../../i18n/forTests/i18nwrapper';
@@ -24,8 +24,15 @@ vi.mock('../../utils/request', () => ({
2424
apiGet: vi.fn().mockResolvedValue({}),
2525
}));
2626

27+
vi.mock('react', () => ({
28+
...vi.importActual('react'),
29+
useContext: vi.fn(),
30+
createContext: vi.fn()
31+
}));
32+
2733
describe('components/balance/balance', () => {
2834
it('renders balance properly', () => {
35+
(useContext as Mock).mockReturnValue({ btcUnit: 'default', defaultCurrency: 'USD' });
2936
const MOCK_BALANCE: IBalance = {
3037
hasAvailable: true,
3138
hasIncoming: true,
@@ -60,7 +67,7 @@ describe('components/balance/balance', () => {
6067
}
6168
};
6269
const { getByTestId } = render(<Balance balance={MOCK_BALANCE} />, { wrapper: I18NWrapper });
63-
expect(getByTestId('availableBalance')).toHaveTextContent('0.005BTC');
64-
expect(getByTestId('incomingBalance').textContent).toContain('+0.003 BTC / 512');
70+
expect(getByTestId('availableBalance').textContent).toBe('0.005BTC');
71+
expect(getByTestId('incomingBalance').textContent).toBe('+0.003 BTC / 512 USD');
6572
});
6673
});

frontends/web/src/components/rates/rates.tsx

Lines changed: 13 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,13 @@
1414
* See the License for the specific language governing permissions and
1515
* limitations under the License.
1616
*/
17-
17+
import { useContext } from 'react';
1818
import { Fiat, ConversionUnit, IAmount } from '../../api/account';
19-
import { BtcUnit } from '../../api/coins';
20-
import { reinitializeAccounts } from '../../api/backend';
21-
import { share } from '../../decorators/share';
22-
import { Store } from '../../decorators/store';
23-
import { setConfig } from '../../utils/config';
19+
import { RatesContext } from '../../contexts/RatesContext';
2420
import { Amount } from '../../components/amount/amount';
25-
import { equal } from '../../utils/equal';
26-
import { apiGet } from '../../utils/request';
2721
import style from './rates.module.css';
2822

29-
export interface SharedProps {
30-
active: Fiat;
31-
// eslint-disable-next-line react/no-unused-prop-types
32-
selected: Fiat[];
33-
btcUnit?: BtcUnit;
34-
alwaysShowAmounts?: boolean;
35-
}
36-
37-
export type FiatWithDisplayName = {
23+
type FiatWithDisplayName = {
3824
currency: Fiat,
3925
displayName: string
4026
}
@@ -60,68 +46,6 @@ export const currenciesWithDisplayName: FiatWithDisplayName[] = [
6046
{ currency: 'USD', displayName: 'United States Dollar' },
6147
{ currency: 'BTC', displayName: 'Bitcoin' }
6248
];
63-
export const currencies: Fiat[] = ['AUD', 'BRL', 'CAD', 'CHF', 'CNY', 'CZK', 'EUR', 'GBP', 'HKD', 'ILS', 'JPY', 'KRW', 'NOK', 'PLN', 'RUB', 'SEK', 'SGD', 'USD', 'BTC'];
64-
65-
export const store = new Store<SharedProps>({
66-
active: 'USD',
67-
selected: ['USD', 'EUR', 'CHF'],
68-
btcUnit: 'default',
69-
});
70-
71-
// TODO: should not invoking apiGet imediatelly, see the apiGet() function for more details
72-
updateRatesConfig();
73-
74-
export function updateRatesConfig(): void {
75-
apiGet('config').then((appconf) => {
76-
if (appconf.frontend && appconf.backend.mainFiat) {
77-
store.setState({ active: appconf.backend.mainFiat });
78-
}
79-
if (appconf.backend && appconf.backend.fiatList && appconf.backend.btcUnit) {
80-
store.setState({
81-
selected: appconf.backend.fiatList,
82-
btcUnit: appconf.backend.btcUnit,
83-
});
84-
}
85-
});
86-
}
87-
88-
//this is setting default currency
89-
export function setActiveFiat(fiat: Fiat): void {
90-
if (!store.state.selected.includes(fiat)) {
91-
selectFiat(fiat);
92-
}
93-
store.setState({ active: fiat });
94-
setConfig({ backend: { mainFiat: fiat } });
95-
}
96-
97-
function rotateFiat(): void {
98-
const index = store.state.selected.indexOf(store.state.active);
99-
const fiat = store.state.selected[(index + 1) % store.state.selected.length];
100-
setActiveFiat(fiat);
101-
}
102-
103-
//this is selecting active currency
104-
export function selectFiat(fiat: Fiat): void {
105-
const selected = [...store.state.selected, fiat];
106-
setConfig({ backend: { fiatList: selected } })
107-
.then(() => {
108-
store.setState({ selected });
109-
// Need to reconfigure currency exchange rates updater
110-
// which is done during accounts reset.
111-
reinitializeAccounts();
112-
});
113-
}
114-
115-
export function unselectFiat(fiat: Fiat): void {
116-
const selected = store.state.selected.filter(item => !equal(item, fiat));
117-
setConfig({ backend: { fiatList: selected } })
118-
.then(() => {
119-
store.setState({ selected });
120-
// Need to reconfigure currency exchange rates updater
121-
// which is done during accounts reset.
122-
reinitializeAccounts();
123-
});
124-
}
12549

12650
export function formatNumber(amount: number, maxDigits: number): string {
12751
let formatted = amount.toFixed(maxDigits);
@@ -141,38 +65,37 @@ type TProvidedProps = {
14165
noAction?: boolean;
14266
sign?: string;
14367
noBtcZeroes?: boolean;
68+
alwaysShowAmounts?: boolean;
14469
}
14570

146-
type TProps = TProvidedProps & SharedProps;
14771

14872
function Conversion({
14973
amount,
15074
tableRow,
15175
unstyled,
15276
skipUnit,
153-
active,
15477
noAction,
15578
sign,
15679
noBtcZeroes,
157-
btcUnit,
15880
alwaysShowAmounts = false
159-
}: TProps) {
81+
}: TProvidedProps) {
82+
83+
const { rotateFiat, defaultCurrency, btcUnit } = useContext(RatesContext);
16084

16185
let formattedAmount = <>{'---'}</>;
16286
let isAvailable = false;
16387

164-
var activeUnit: ConversionUnit = active;
165-
if (active === 'BTC' && btcUnit === 'sat') {
88+
let activeUnit: ConversionUnit = defaultCurrency;
89+
if (defaultCurrency === 'BTC' && btcUnit === 'sat') {
16690
activeUnit = 'sat';
16791
}
16892

169-
// amount.conversions[active] can be empty in recent transactions.
170-
if (amount && amount.conversions && amount.conversions[active] && amount.conversions[active] !== '') {
93+
// amount.conversions[defaultCurrency] can be empty in recent transactions.
94+
if (amount && amount.conversions && amount.conversions[defaultCurrency] && amount.conversions[defaultCurrency] !== '') {
17195
isAvailable = true;
172-
formattedAmount = <Amount alwaysShowAmounts={alwaysShowAmounts} amount={amount.conversions[active]} unit={activeUnit} removeBtcTrailingZeroes={!!noBtcZeroes}/>;
96+
formattedAmount = <Amount alwaysShowAmounts={alwaysShowAmounts} amount={amount.conversions[defaultCurrency]} unit={activeUnit} removeBtcTrailingZeroes={!!noBtcZeroes}/>;
17397
}
17498

175-
17699
if (tableRow) {
177100
return (
178101
<tr className={unstyled ? '' : style.fiatRow}>
@@ -211,4 +134,4 @@ function Conversion({
211134

212135
export const formattedCurrencies = currenciesWithDisplayName.map((fiat) => ({ label: `${fiat.displayName} (${fiat.currency})`, value: fiat.currency }));
213136

214-
export const FiatConversion = share<SharedProps, TProvidedProps>(store)(Conversion);
137+
export const FiatConversion = Conversion;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Copyright 2023 Shift Crypto AG
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { createContext } from 'react';
18+
import { Fiat } from '../api/account';
19+
import { BtcUnit } from '../api/coins';
20+
21+
type RatesContextProps = {
22+
defaultCurrency: Fiat;
23+
activeCurrencies: Fiat[];
24+
btcUnit?: BtcUnit;
25+
rotateFiat: () => void;
26+
selectFiat: (fiat: Fiat) => Promise<void>;
27+
updateDefaultFiat: (fiat: Fiat) => void;
28+
updateRatesConfig: () => Promise<void>;
29+
unselectFiat: (fiat: Fiat) => Promise<void>;
30+
}
31+
32+
const RatesContext = createContext<RatesContextProps>({} as RatesContextProps);
33+
34+
export { RatesContext };

0 commit comments

Comments
 (0)