diff --git a/frontends/web/src/api/keystores.ts b/frontends/web/src/api/keystores.ts new file mode 100644 index 0000000000..23104690f1 --- /dev/null +++ b/frontends/web/src/api/keystores.ts @@ -0,0 +1,33 @@ +/** + * Copyright 2023 Shift Crypto AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { subscribeEndpoint, TUnsubscribe } from './subscribe'; +import { apiGet } from '../utils/request'; + +export type { TUnsubscribe }; + +type TKeystore = { type: 'hardware' | 'software' }; +export type TKeystores = TKeystore[]; + +export const subscribeKeystores = ( + cb: (keystores: TKeystores) => void +) => { + return subscribeEndpoint('keystores', cb); +}; + +export const getKeystores = (): Promise => { + return apiGet('keystores'); +}; diff --git a/frontends/web/src/components/sidebar/sidebar.tsx b/frontends/web/src/components/sidebar/sidebar.tsx index 15a463bafc..acb6bf1637 100644 --- a/frontends/web/src/components/sidebar/sidebar.tsx +++ b/frontends/web/src/components/sidebar/sidebar.tsx @@ -17,6 +17,7 @@ import React, { Component } from 'react'; import { Link, NavLink } from 'react-router-dom'; +import { TKeystores, subscribeKeystores, TUnsubscribe, getKeystores } from '../../api/keystores'; import { IAccount } from '../../api/account'; import coins from '../../assets/icons/coins.svg'; import ejectIcon from '../../assets/icons/eject.svg'; @@ -24,7 +25,6 @@ import info from '../../assets/icons/info.svg'; import settings from '../../assets/icons/settings-alt.svg'; import settingsGrey from '../../assets/icons/settings-alt_disabled.svg'; import { share } from '../../decorators/share'; -import { subscribe } from '../../decorators/subscribe'; import { translate, TranslateProps } from '../../decorators/translate'; import { debug } from '../../utils/env'; import { apiPost } from '../../utils/request'; @@ -41,10 +41,6 @@ interface SidebarProps { accounts: IAccount[]; } -interface SubscribedProps { - keystores?: Array<{ type: 'hardware' | 'software' }>; -} - export type SharedPanelProps = { // eslint-disable-next-line react/no-unused-prop-types activeSidebar: boolean; @@ -52,7 +48,7 @@ export type SharedPanelProps = { sidebarStatus: string; } -type Props = SubscribedProps & SharedPanelProps & SidebarProps & TranslateProps; +type Props = SharedPanelProps & SidebarProps & TranslateProps; type TGetAccountLinkProps = IAccount & { handleSidebarItemClick: ((e: React.SyntheticEvent) => void) }; @@ -93,16 +89,30 @@ const GetAccountLink = ({ coinCode, code, name, handleSidebarItemClick }: TGetAc ); }; +type State = { + keystores: TKeystores; +} class Sidebar extends Component { private swipe!: SwipeAttributes; + private unsubscribeFn?: TUnsubscribe; + + public readonly state: State = { + keystores: [], + }; public componentDidMount() { this.registerTouchEvents(); + getKeystores().then(keystores => this.setState({ keystores }, () => { + this.unsubscribeFn = subscribeKeystores(keystores => this.setState({ keystores })); + })); } public componentWillUnmount() { this.removeTouchEvents(); + if (this.unsubscribeFn) { + this.unsubscribeFn(); + } } private registerTouchEvents = () => { @@ -159,11 +169,11 @@ class Sidebar extends Component { }; public render() { + const { keystores } = this.state; const { t, deviceIDs, accounts, - keystores, activeSidebar, sidebarStatus, } = this.props; @@ -265,12 +275,6 @@ function eject(e: React.SyntheticEvent): void { e.preventDefault(); } -const subscribeHOC = subscribe( - { keystores: 'keystores' }, - false, - false, -)(Sidebar); - -const guideShareHOC = share(panelStore)(subscribeHOC); +const guideShareHOC = share(panelStore)(Sidebar); const translateHOC = translate()(guideShareHOC); export { translateHOC as Sidebar }; diff --git a/frontends/web/src/routes/account/info/buyReceiveCTA.tsx b/frontends/web/src/routes/account/info/buyReceiveCTA.tsx index 6ec08739a0..bbc6a9daa0 100644 --- a/frontends/web/src/routes/account/info/buyReceiveCTA.tsx +++ b/frontends/web/src/routes/account/info/buyReceiveCTA.tsx @@ -22,6 +22,7 @@ import { Balances } from '../summary/accountssummary'; import { isBitcoinCoin } from '../utils'; import { getExchangeSupportedAccounts } from '../../buy/utils'; import styles from './buyReceiveCTA.module.css'; +import { useMountedRef } from '../../../hooks/mount'; type TBuyReceiveCTAProps = { balanceList?: IBalance[]; @@ -62,12 +63,20 @@ export const BuyReceiveCTA = ({ code, unit, balanceList, exchangeBuySupported = export const AddBuyReceiveOnEmptyBalances = ({ balances, accounts }: TAddBuyReceiveOnEmpyBalancesProps) => { - + const mounted = useMountedRef(); const [supportedAccounts, setSupportedAccounts] = useState(); useEffect(() => { - getExchangeSupportedAccounts(accounts).then(setSupportedAccounts); - }, [accounts]); + if (mounted.current) { + getExchangeSupportedAccounts(accounts) + .then(supportedAccounts => { + if (mounted.current) { + setSupportedAccounts(supportedAccounts); + } + }) + .catch(console.error); + } + }, [accounts, mounted]); if (balances === undefined || supportedAccounts === undefined) { return null;