diff --git a/CHANGELOG.md b/CHANGELOG.md index f8edb0457f..b1efc2b509 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ Changelog ========= +## vNext + +### Chores + +- Moved currency related code into a dedicated store ([PR 2546](https://github.com/input-output-hk/daedalus/pull/2546)) + ## 4.1.0-FC1 ### Features diff --git a/source/renderer/app/actions/currency-actions.js b/source/renderer/app/actions/currency-actions.js new file mode 100644 index 0000000000..af128c426c --- /dev/null +++ b/source/renderer/app/actions/currency-actions.js @@ -0,0 +1,9 @@ +// @flow +import Action from './lib/Action'; + +// ======= CURRENCY ACTIONS ======= + +export default class CurrencyActions { + setCurrencySelected: Action<{ code: string }> = new Action(); + toggleCurrencyIsActive: Action = new Action(); +} diff --git a/source/renderer/app/actions/index.js b/source/renderer/app/actions/index.js index c02b17bb01..254fc4952c 100644 --- a/source/renderer/app/actions/index.js +++ b/source/renderer/app/actions/index.js @@ -3,6 +3,7 @@ import AddressesActions from './addresses-actions'; import AppActions from './app-actions'; import AppUpdateActions from './app-update-actions'; import AssetsActions from './assets-actions'; +import CurrencyActions from './currency-actions'; import DialogsActions from './dialogs-actions'; import HardwareWalletsActions from './hardware-wallets-actions'; import NetworkStatusActions from './network-status-actions'; @@ -26,6 +27,7 @@ export type ActionsMap = { appUpdate: AppUpdateActions, assets: AssetsActions, dialogs: DialogsActions, + currency: CurrencyActions, hardwareWallets: HardwareWalletsActions, networkStatus: NetworkStatusActions, notifications: NotificationsActions, @@ -48,6 +50,7 @@ const actionsMap: ActionsMap = { app: new AppActions(), appUpdate: new AppUpdateActions(), assets: new AssetsActions(), + currency: new CurrencyActions(), dialogs: new DialogsActions(), hardwareWallets: new HardwareWalletsActions(), networkStatus: new NetworkStatusActions(), diff --git a/source/renderer/app/actions/wallets-actions.js b/source/renderer/app/actions/wallets-actions.js index 43c74c22c5..8cb6807446 100644 --- a/source/renderer/app/actions/wallets-actions.js +++ b/source/renderer/app/actions/wallets-actions.js @@ -87,8 +87,6 @@ export default class WalletsActions { setCertificateTemplate: Action<{ selectedTemplate: string }> = new Action(); finishCertificate: Action = new Action(); finishRewardsCsv: Action = new Action(); - setCurrencySelected: Action<{ currencyCode: string }> = new Action(); - toggleCurrencyIsActive: Action = new Action(); /* ---------- Transfer Funds ---------- */ setActiveAssetFingerprint: Action<{ diff --git a/source/renderer/app/containers/settings/categories/WalletsSettingsPage.js b/source/renderer/app/containers/settings/categories/WalletsSettingsPage.js index 0937313185..d4ac011552 100644 --- a/source/renderer/app/containers/settings/categories/WalletsSettingsPage.js +++ b/source/renderer/app/containers/settings/categories/WalletsSettingsPage.js @@ -9,29 +9,29 @@ import type { InjectedProps } from '../../../types/injectedPropsType'; export default class WalletsSettingsPage extends Component { static defaultProps = { actions: null, stores: null }; - handleSelectCurrency = (currencyCode: string) => { - this.props.actions.wallets.setCurrencySelected.trigger({ currencyCode }); + handleSelectCurrency = (code: string) => { + this.props.actions.currency.setCurrencySelected.trigger({ code }); }; handleToggleCurrencyIsActive = () => - this.props.actions.wallets.toggleCurrencyIsActive.trigger(); + this.props.actions.currency.toggleCurrencyIsActive.trigger(); render() { const { stores } = this.props; const { - localizedCurrency: currencySelected, + localizedCurrency: selected, localizedCurrencyList: currencyList, - currencyRate, - currencyIsActive, - } = stores.wallets; + rate, + isActive, + } = stores.currency; const { currentLocale } = stores.profile; const { openExternalLink } = stores.app; return ( { render() { const { intl } = this.context; const { stores, actions } = this.props; - const { app, wallets, addresses, transactions, profile, assets } = stores; + const { + app, + wallets, + addresses, + transactions, + profile, + assets, + currency, + } = stores; const { getAssetDetails, assetSettingsDialogWasOpened } = assets; const { isInternalAddress } = addresses; const { onAssetSettingsOpen } = actions.assets; @@ -94,15 +102,16 @@ export default class WalletSummaryPage extends Component { deleteTransactionRequest, pendingTransactionsCount, } = transactions; + const { active: wallet } = wallets; const { - active: wallet, - currencyIsActive, - currencyIsAvailable, - currencyIsFetchingRate, - currencyLastFetched, - currencyRate, - currencySelected, - } = wallets; + isActive, + isAvailable, + isFetchingRate, + lastFetched, + rate, + selected, + } = currency; + const { currentTimeFormat, currentDateFormat, currentLocale } = profile; const hasAssetsEnabled = WALLET_ASSETS_ENABLED; @@ -190,12 +199,12 @@ export default class WalletSummaryPage extends Component { isLoadingTransactions={recentTransactionsRequest.isExecutingFirstTime} isLoadingAssets={isLoadingAssets} hasAssetsEnabled={hasAssetsEnabled && hasRawAssets} - currencyIsActive={currencyIsActive} - currencyIsAvailable={currencyIsAvailable} - currencyIsFetchingRate={currencyIsFetchingRate} - currencyLastFetched={currencyLastFetched} - currencyRate={currencyRate} - currencySelected={currencySelected} + currencyIsActive={isActive} + currencyIsAvailable={isAvailable} + currencyIsFetchingRate={isFetchingRate} + currencyLastFetched={lastFetched} + currencyRate={rate} + currencySelected={selected} onCurrencySettingClick={this.handleCurrencySettingsClick} assets={walletAssets} assetSettingsDialogWasOpened={assetSettingsDialogWasOpened} diff --git a/source/renderer/app/stores/CurrencyStore.js b/source/renderer/app/stores/CurrencyStore.js new file mode 100644 index 0000000000..e396d78593 --- /dev/null +++ b/source/renderer/app/stores/CurrencyStore.js @@ -0,0 +1,123 @@ +// @flow +import { action, observable, computed, runInAction } from 'mobx'; +import Store from './lib/Store'; +import { + CURRENCY_REQUEST_RATE_INTERVAL, + getLocalizedCurrency, + getLocalizedCurrenciesList, + getCurrencyFromCode, +} from '../config/currencyConfig'; +import type { Currency, LocalizedCurrency } from '../types/currencyTypes.js'; + +export default class CurrencyStore extends Store { + @observable isFetchingList: boolean = false; + @observable isFetchingRate: boolean = false; + @observable isAvailable: boolean = false; + @observable isActive: boolean = false; + @observable list: Array = []; + @observable selected: ?Currency = null; + @observable rate: ?number = null; + @observable lastFetched: ?Date = null; + _getCurrencyRateInterval: ?IntervalID = null; + + setup() { + const { currency: currencyActions } = this.actions; + currencyActions.setCurrencySelected.listen(this._setCurrencySelected); + currencyActions.toggleCurrencyIsActive.listen(this._toggleCurrencyIsActive); + + this._setupCurrency(); + } + + // PUBLIC + + @computed get localizedCurrencyList(): Array { + const { list, stores } = this; + const { currentLocale } = stores.profile; + return getLocalizedCurrenciesList(list, currentLocale); + } + + @computed get localizedCurrency(): ?LocalizedCurrency { + const { selected, stores } = this; + const { currentLocale } = stores.profile; + if (!selected) return null; + return getLocalizedCurrency(selected, currentLocale); + } + + @action getCurrencyList = async () => { + this.isFetchingList = true; + const list = await this.api.ada.getCurrencyList(); + runInAction(() => { + this.list = list; + this.isFetchingList = false; + }); + }; + + @action getCurrencyRate = async () => { + const { localizedCurrency } = this; + if (localizedCurrency && localizedCurrency.code) { + try { + this.isFetchingRate = true; + const rate = await this.api.ada.getCurrencyRate(localizedCurrency); + runInAction(() => { + this.isFetchingRate = false; + this.lastFetched = new Date(); + if (rate) { + this.rate = rate; + this.isAvailable = true; + } else { + throw new Error('Error fetching the Currency rate'); + } + }); + } catch (error) { + runInAction(() => { + this.rate = null; + this.isAvailable = false; + }); + clearInterval(this._getCurrencyRateInterval); + } + } + }; + + // PRIVATE + + @action _setupCurrency = async () => { + // Check if the user has enabled currencies + // Otherwise applies the default config + const isActive = await this.api.localStorage.getCurrencyIsActive(); + + // Check if the user has already selected a currency + // Otherwise applies the default currency + const localCurrencyCode = await this.api.localStorage.getCurrencySelected(); + const selected = getCurrencyFromCode(localCurrencyCode); + + runInAction(() => { + this.isActive = isActive; + this.selected = selected; + }); + + clearInterval(this._getCurrencyRateInterval); + this._getCurrencyRateInterval = setInterval( + this.getCurrencyRate, + CURRENCY_REQUEST_RATE_INTERVAL + ); + + // Fetch the currency list and rate + this.getCurrencyList(); + this.getCurrencyRate(); + }; + + @action _setCurrencySelected = async ({ code }: { code: string }) => { + const { list } = this; + const selected = list.find((item) => item.code === code); + if (selected) { + this.selected = selected; + this.getCurrencyRate(); + await this.api.localStorage.setCurrencySelected(selected.code); + } + }; + + @action _toggleCurrencyIsActive = () => { + this.isActive = !this.isActive; + this.api.localStorage.setCurrencyIsActive(this.isActive); + }; +} diff --git a/source/renderer/app/stores/WalletsStore.js b/source/renderer/app/stores/WalletsStore.js index 36469b00e0..3fca523be5 100644 --- a/source/renderer/app/stores/WalletsStore.js +++ b/source/renderer/app/stores/WalletsStore.js @@ -31,19 +31,12 @@ import { RESTORE_WALLET_STEPS, } from '../config/walletRestoreConfig'; import { IS_WALLET_PUBLIC_KEY_SHARING_ENABLED } from '../config/walletsConfig'; -import { - CURRENCY_REQUEST_RATE_INTERVAL, - getLocalizedCurrency, - getLocalizedCurrenciesList, - getCurrencyFromCode, -} from '../config/currencyConfig'; import type { WalletKind, WalletDaedalusKind, WalletYoroiKind, WalletHardwareKind, } from '../types/walletRestoreTypes'; -import type { Currency, LocalizedCurrency } from '../types/currencyTypes.js'; import type { CsvFileContent } from '../../../common/types/csv-request.types'; import type { WalletExportTypeChoices } from '../types/walletExportTypes'; import type { WalletImportFromFileParams } from '../actions/wallets-actions'; @@ -152,16 +145,6 @@ export default class WalletsStore extends Store { @observable activeValue: ?BigNumber = null; @observable activePublicKey: ?string = null; - /* ------------ Currencies ----------- */ - @observable currencyIsFetchingList: boolean = false; - @observable currencyIsFetchingRate: boolean = false; - @observable currencyIsAvailable: boolean = false; - @observable currencyIsActive: boolean = false; - @observable currencyList: Array = []; - @observable currencySelected: ?Currency = null; - @observable currencyRate: ?number = null; - @observable currencyLastFetched: ?Date = null; - /* ---------- Create Wallet ---------- */ @observable createWalletStep = null; @observable createWalletShowAbortConfirmation = false; @@ -226,7 +209,6 @@ export default class WalletsStore extends Store { spendingPassword: '', }; _pollingBlocked = false; - _getCurrencyRateInterval: ?IntervalID = null; setup() { setInterval(this._pollRefresh, this.WALLET_REFRESH_INTERVAL); @@ -310,10 +292,6 @@ export default class WalletsStore extends Store { walletsActions.transferFundsCalculateFee.listen( this._transferFundsCalculateFee ); - walletsActions.setCurrencySelected.listen(this._setCurrencySelected); - walletsActions.toggleCurrencyIsActive.listen(this._toggleCurrencyIsActive); - - this.setupCurrency(); } @action _getAccountPublicKey = async ({ @@ -344,92 +322,6 @@ export default class WalletsStore extends Store { } }; - @action setupCurrency = async () => { - // CURRENCY_REQUEST_RATE_INTERVAL - - // Check if the user has enabled currencies - // Otherwise applies the default config - const currencyIsActive = await this.api.localStorage.getCurrencyIsActive(); - - // Check if the user has already selected a currency - // Otherwise applies the default currency - const localCurrencyCode = await this.api.localStorage.getCurrencySelected(); - const currencySelected = getCurrencyFromCode(localCurrencyCode); - - runInAction(() => { - this.currencyIsActive = currencyIsActive; - this.currencySelected = currencySelected; - }); - - clearInterval(this._getCurrencyRateInterval); - this._getCurrencyRateInterval = setInterval( - this.getCurrencyRate, - CURRENCY_REQUEST_RATE_INTERVAL - ); - - // Fetch the currency list and rate - this.getCurrencyList(); - this.getCurrencyRate(); - }; - - @action getCurrencyList = async () => { - this.currencyIsFetchingList = true; - const currencyList = await this.api.ada.getCurrencyList(); - runInAction(() => { - this.currencyList = currencyList; - this.currencyIsFetchingList = false; - }); - }; - - @action getCurrencyRate = async () => { - const { localizedCurrency } = this; - if (localizedCurrency && localizedCurrency.code) { - try { - this.currencyIsFetchingRate = true; - const currencyRate = await this.api.ada.getCurrencyRate( - localizedCurrency - ); - runInAction(() => { - this.currencyIsFetchingRate = false; - this.currencyLastFetched = new Date(); - if (currencyRate) { - this.currencyRate = currencyRate; - this.currencyIsAvailable = true; - } else { - throw new Error('Error fetching the Currency rate'); - } - }); - } catch (error) { - runInAction(() => { - this.currencyRate = null; - this.currencyIsAvailable = false; - }); - clearInterval(this._getCurrencyRateInterval); - } - } - }; - - @action _setCurrencySelected = async ({ - currencyCode, - }: { - currencyCode: string, - }) => { - const { currencyList } = this; - const currencySelected = currencyList.find( - ({ code }) => currencyCode === code - ); - if (currencySelected) { - this.currencySelected = currencySelected; - this.getCurrencyRate(); - await this.api.localStorage.setCurrencySelected(currencySelected.code); - } - }; - - @action _toggleCurrencyIsActive = () => { - this.currencyIsActive = !this.currencyIsActive; - this.api.localStorage.setCurrencyIsActive(this.currencyIsActive); - }; - _create = async (params: { name: string, spendingPassword: string }) => { Object.assign(this._newWalletDetails, params); try { @@ -1018,19 +910,6 @@ export default class WalletsStore extends Store { } } - @computed get localizedCurrencyList(): Array { - const { currencyList, stores } = this; - const { currentLocale } = stores.profile; - return getLocalizedCurrenciesList(currencyList, currentLocale); - } - - @computed get localizedCurrency(): ?LocalizedCurrency { - const { currencySelected, stores } = this; - const { currentLocale } = stores.profile; - if (!currencySelected) return null; - return getLocalizedCurrency(currencySelected, currentLocale); - } - getWalletById = (id: string): ?Wallet => this.all.find((w) => w.id === id); getWalletByName = (name: string): ?Wallet => diff --git a/source/renderer/app/stores/index.js b/source/renderer/app/stores/index.js index 6ed10b8ea2..38fb050f2d 100644 --- a/source/renderer/app/stores/index.js +++ b/source/renderer/app/stores/index.js @@ -4,6 +4,8 @@ import type Store from './lib/Store'; import AddressesStore from './AddressesStore'; import AppStore from './AppStore'; import AppUpdateStore from './AppUpdateStore'; +import AssetsStore from './AssetsStore'; +import CurrencyStore from './CurrencyStore'; import HardwareWalletsStore from './HardwareWalletsStore'; import NetworkStatusStore from './NetworkStatusStore'; import NewsFeedStore from './NewsFeedStore'; @@ -11,15 +13,14 @@ import ProfileStore from './ProfileStore'; import SidebarStore from './SidebarStore'; import StakingStore from './StakingStore'; import TransactionsStore from './TransactionsStore'; -import AssetsStore from './AssetsStore'; import UiDialogsStore from './UiDialogsStore'; import UiNotificationsStore from './UiNotificationsStore'; import VotingStore from './VotingStore'; -import WalletsStore from './WalletsStore'; -import WalletsLocalStore from './WalletsLocalStore'; import WalletBackupStore from './WalletBackupStore'; import WalletMigrationStore from './WalletMigrationStore'; import WalletSettingsStore from './WalletSettingsStore'; +import WalletsLocalStore from './WalletsLocalStore'; +import WalletsStore from './WalletsStore'; import WindowStore from './WindowStore'; export const storeClasses = { @@ -27,6 +28,7 @@ export const storeClasses = { app: AppStore, appUpdate: AppUpdateStore, assets: AssetsStore, + currency: CurrencyStore, hardwareWallets: HardwareWalletsStore, networkStatus: NetworkStatusStore, newsFeed: NewsFeedStore, @@ -49,6 +51,7 @@ export type StoresMap = { addresses: AddressesStore, app: AppStore, appUpdate: AppUpdateStore, + currency: CurrencyStore, assets: AssetsStore, hardwareWallets: HardwareWalletsStore, networkStatus: NetworkStatusStore, @@ -93,6 +96,7 @@ export default action((api, actions, router): StoresMap => { addresses: createStoreInstanceOf(AddressesStore), app: createStoreInstanceOf(AppStore), assets: createStoreInstanceOf(AssetsStore), + currency: createStoreInstanceOf(CurrencyStore), appUpdate: createStoreInstanceOf(AppUpdateStore), hardwareWallets: createStoreInstanceOf(HardwareWalletsStore), networkStatus: createStoreInstanceOf(NetworkStatusStore),