From dd7410e7a872f976512276b212596326b0c2afdb Mon Sep 17 00:00:00 2001 From: Danilo Prates Date: Tue, 1 Dec 2020 15:31:29 -0300 Subject: [PATCH] [DDW-481] Basic UI --- source/main/cardano/CardanoWalletLauncher.js | 1 + source/renderer/app/Routes.js | 5 + .../renderer/app/actions/staking-actions.js | 5 + .../settings/categories/StakePoolsSettings.js | 134 ++++++++++++++++++ .../categories/StakePoolsSettings.scss | 7 + .../components/settings/menu/SettingsMenu.js | 11 ++ source/renderer/app/config/stakingConfig.js | 25 +++- .../categories/StakePoolsSettingsPage.js | 27 ++++ source/renderer/app/i18n/locales/en-US.json | 7 +- source/renderer/app/routes-config.js | 1 + source/renderer/app/stores/StakingStore.js | 27 +++- source/renderer/app/types/stakingTypes.js | 1 + 12 files changed, 247 insertions(+), 4 deletions(-) create mode 100644 source/renderer/app/components/settings/categories/StakePoolsSettings.js create mode 100644 source/renderer/app/components/settings/categories/StakePoolsSettings.scss create mode 100644 source/renderer/app/containers/settings/categories/StakePoolsSettingsPage.js diff --git a/source/main/cardano/CardanoWalletLauncher.js b/source/main/cardano/CardanoWalletLauncher.js index 7f8ab36bd9..44c07c0db2 100644 --- a/source/main/cardano/CardanoWalletLauncher.js +++ b/source/main/cardano/CardanoWalletLauncher.js @@ -59,6 +59,7 @@ export async function CardanoWalletLauncher(walletOpts: WalletOpts): Launcher { isStaging, smashUrl, } = walletOpts; + console.log('smashUrl ------------', smashUrl); // TODO: Update launcher config to pass number const syncToleranceSeconds = parseInt(syncTolerance.replace('s', ''), 10); diff --git a/source/renderer/app/Routes.js b/source/renderer/app/Routes.js index 22f0932ca7..3c5fa66337 100644 --- a/source/renderer/app/Routes.js +++ b/source/renderer/app/Routes.js @@ -8,6 +8,7 @@ import Root from './containers/Root'; import InitialSettingsPage from './containers/profile/InitialSettingsPage'; import Settings from './containers/settings/Settings'; import GeneralSettingsPage from './containers/settings/categories/GeneralSettingsPage'; +import StakePoolsSettingsPage from './containers/settings/categories/StakePoolsSettingsPage'; import SupportSettingsPage from './containers/settings/categories/SupportSettingsPage'; import TermsOfUseSettingsPage from './containers/settings/categories/TermsOfUseSettingsPage'; import TermsOfUsePage from './containers/profile/TermsOfUsePage'; @@ -89,6 +90,10 @@ export const Routes = withRouter(() => ( path={ROUTES.SETTINGS.GENERAL} component={GeneralSettingsPage} /> + = new Action(); requestCSVFileSuccess: Action = new Action(); + selectSmashServerType: Action<{ + smashServerType: SmashServerType, + }> = new Action(); + selectSmashServerUrl: Action<{ smashServerUrl: string }> = new Action(); /* ---------- Redeem ITN Rewards ---------- */ onRedeemStart: Action = new Action(); onConfigurationContinue: Action<{ diff --git a/source/renderer/app/components/settings/categories/StakePoolsSettings.js b/source/renderer/app/components/settings/categories/StakePoolsSettings.js new file mode 100644 index 0000000000..b8540ebd87 --- /dev/null +++ b/source/renderer/app/components/settings/categories/StakePoolsSettings.js @@ -0,0 +1,134 @@ +// @flow +import React, { Component } from 'react'; +import classnames from 'classnames'; +import { Select } from 'react-polymorph/lib/components/Select'; +import { SelectSkin } from 'react-polymorph/lib/skins/simple/SelectSkin'; +import { Input } from 'react-polymorph/lib/components/Input'; +import { InputSkin } from 'react-polymorph/lib/skins/simple/InputSkin'; +import { observer } from 'mobx-react'; +import { defineMessages, intlShape } from 'react-intl'; +import { submitOnEnter } from '../../../utils/form'; +import styles from './StakePoolsSettings.scss'; +import { + INTERNAL_SMASH_SERVERS, + SMASH_SERVER_TYPES, +} from '../../../config/stakingConfig'; +import type { SmashServerType } from '../../../types/stakingTypes'; + +const messages = defineMessages({ + smashSelectLabel: { + id: 'settings.stakePools.smash.select.label', + defaultMessage: '!!!Off-chain data server (SMASH)', + description: + 'smashSelectLabel for the "Smash" selection on the Stake Pools settings page.', + }, + smashSelectCustomServer: { + id: 'settings.stakePools.smash.select.placeholder', + defaultMessage: '!!!Custom server', + description: + 'smashSelectCustomServer option for the "Smash" selection on the Stake Pools settings page.', + }, + smashURLSelectLabel: { + id: 'settings.stakePools.smashUrl.select.label', + defaultMessage: '!!!SMASH server URL', + description: + 'smashURLSelectLabel for the "Smash Custom Server" selection on the Stake Pools settings page.', + }, + smashUrlSelectPlaceholder: { + id: 'settings.stakePools.smashUrl.select.placeholder', + defaultMessage: '!!!Enter custom server', + description: + 'smashUrlSelectPlaceholder for the "Smash Custom Server" selection on the Stake Pools settings page.', + }, +}); + +type Props = { + smashServerType: string, + smashServerUrl?: string, + onSelectSmashServerType: Function, + onSelectSmashServerUrl: Function, +}; + +@observer +export default class StakePoolsSettings extends Component { + static contextTypes = { + intl: intlShape.isRequired, + }; + + componentWillUnmount() { + const { + smashServerType, + smashServerUrl, + onSelectSmashServerType, + } = this.props; + + if (smashServerType === SMASH_SERVER_TYPES.CUSTOM && !smashServerUrl) { + onSelectSmashServerType({ smashServerType: SMASH_SERVER_TYPES.IOHK }); + } + } + + handleSubmit = () => { + console.log('handleSubmit'); + // if (this.isConfirmDisabled()) { + // return false; + // } + + // return this.form.submit({ + // onSuccess: (form) => { + // const { onConfirm } = this.props; + // const { passphrase } = form.values(); + // onConfirm(passphrase); + // }, + // onError: () => null, + // }); + }; + + handleSubmitOnEnter = (event: KeyboardEvent) => + submitOnEnter(this.handleSubmit, event); + + render() { + const { + smashServerType, + smashServerUrl, + onSelectSmashServerType, + onSelectSmashServerUrl, + } = this.props; + const { intl } = this.context; + + const smashSelectOptions = [ + ...INTERNAL_SMASH_SERVERS.map(({ name: label, id: value }) => ({ + label, + value, + })), + { + label: intl.formatMessage(messages.smashSelectCustomServer), + value: SMASH_SERVER_TYPES.CUSTOM, + }, + ]; + + return ( +
+ + )} +
+ ); + } +} diff --git a/source/renderer/app/components/settings/categories/StakePoolsSettings.scss b/source/renderer/app/components/settings/categories/StakePoolsSettings.scss new file mode 100644 index 0000000000..3851c4fb21 --- /dev/null +++ b/source/renderer/app/components/settings/categories/StakePoolsSettings.scss @@ -0,0 +1,7 @@ +.component { + :global { + .SimpleFormField_root:not(:first-child) { + margin-top: 20px; + } + } +} diff --git a/source/renderer/app/components/settings/menu/SettingsMenu.js b/source/renderer/app/components/settings/menu/SettingsMenu.js index dee4a3c685..0ccfb901bf 100644 --- a/source/renderer/app/components/settings/menu/SettingsMenu.js +++ b/source/renderer/app/components/settings/menu/SettingsMenu.js @@ -12,6 +12,11 @@ const messages = defineMessages({ defaultMessage: '!!!General', description: 'Label for the "General" link in the settings menu.', }, + stakePools: { + id: 'settings.menu.stakePools.link.label', + defaultMessage: '!!!Stake Pools', + description: 'Label for the "Support" link in the settings menu.', + }, support: { id: 'settings.menu.support.link.label', defaultMessage: '!!!Support', @@ -54,6 +59,12 @@ export default class SettingsMenu extends Component { active={isActiveItem(ROUTES.SETTINGS.GENERAL)} className="general" /> + onItemClick(ROUTES.SETTINGS.STAKE_POOLS)} + active={isActiveItem(ROUTES.SETTINGS.STAKE_POOLS)} + className="stakePools" + /> {!isFlight && !global.isShelleyTestnet && ( = [ + { + id: SMASH_SERVER_TYPES.CARDANO, + name: 'Cardano Foundation', + uri: 'https://smash.cardano-mainnet.iohk.io', + }, + { id: SMASH_SERVER_TYPES.IOHK, name: 'IOHK', uri: 'http://smash.iohk.io' }, +]; export const RANKING_SLIDER_RATIO = 60; export const MIN_DELEGATION_FUNDS_LOG = Math.log(10); diff --git a/source/renderer/app/containers/settings/categories/StakePoolsSettingsPage.js b/source/renderer/app/containers/settings/categories/StakePoolsSettingsPage.js new file mode 100644 index 0000000000..9613c6e92b --- /dev/null +++ b/source/renderer/app/containers/settings/categories/StakePoolsSettingsPage.js @@ -0,0 +1,27 @@ +// @flow +import React, { Component } from 'react'; +import { inject, observer } from 'mobx-react'; +import StakePoolsSettings from '../../../components/settings/categories/StakePoolsSettings'; +import type { InjectedProps } from '../../../types/injectedPropsType'; + +@inject('stores', 'actions') +@observer +export default class StakePoolsSettingsPage extends Component { + static defaultProps = { actions: null, stores: null }; + + render() { + const { stores, actions } = this.props; + const { smashServerType, smashServerUrl } = stores.staking; + const { selectSmashServerType, selectSmashServerUrl } = actions.staking; + // If `smashServerType` is null, waits for it to be set + if (!smashServerType) return false; + return ( + + ); + } +} diff --git a/source/renderer/app/i18n/locales/en-US.json b/source/renderer/app/i18n/locales/en-US.json index 0e2932f43d..a1fff2fb28 100755 --- a/source/renderer/app/i18n/locales/en-US.json +++ b/source/renderer/app/i18n/locales/en-US.json @@ -272,8 +272,13 @@ "settings.display.themeNames.yellow": "Yellow", "settings.menu.display.link.label": "Themes", "settings.menu.general.link.label": "General", + "settings.menu.stakePools.link.label": "Stake Pools", "settings.menu.support.link.label": "Support", "settings.menu.termsOfUse.link.label": "Terms of service", + "settings.stakePools.smash.select.label": "Off-chain data server (SMASH)", + "settings.stakePools.smash.select.placeholder": "Custom server", + "settings.stakePools.smashUrl.select.label": "SMASH server URL", + "settings.stakePools.smashUrl.select.placeholder": "Enter custom server", "settings.support.faq.content": "If you are experiencing a problem, please look for guidance using the list of {faqLink} on the support pages. If you can’t find a solution, please submit a support ticket.", "settings.support.faq.faqLink": "Known Issues", "settings.support.faq.faqLinkURL": "https://daedaluswallet.io/known-issues/", @@ -957,4 +962,4 @@ "wallet.transferFunds.dialog2.sourceWalletAmount.label": "{sourceWalletName} amount", "wallet.transferFunds.dialog2.title": "Transfer funds", "wallet.transferFunds.dialog2.total.label": "Total" -} \ No newline at end of file +} diff --git a/source/renderer/app/routes-config.js b/source/renderer/app/routes-config.js index feaa756eae..6616ac8dbd 100644 --- a/source/renderer/app/routes-config.js +++ b/source/renderer/app/routes-config.js @@ -39,6 +39,7 @@ export const ROUTES = { SETTINGS: { ROOT: '/settings', GENERAL: '/settings/general', + STAKE_POOLS: '/settings/stake-pools', TERMS_OF_USE: '/settings/terms-of-service', SUPPORT: '/settings/support', DISPLAY: '/settings/display', diff --git a/source/renderer/app/stores/StakingStore.js b/source/renderer/app/stores/StakingStore.js index 651ad16832..c3c3a0b796 100644 --- a/source/renderer/app/stores/StakingStore.js +++ b/source/renderer/app/stores/StakingStore.js @@ -20,7 +20,6 @@ import type { RewardForIncentivizedTestnet, JoinStakePoolRequest, GetDelegationFeeRequest, - QuitStakePoolRequest, } from '../api/staking/types'; import Wallet from '../domains/Wallet'; import StakePool from '../domains/StakePool'; @@ -29,7 +28,10 @@ import LocalizableError from '../i18n/LocalizableError'; import { showSaveDialogChannel } from '../ipc/show-file-dialog-channels'; import REWARDS from '../config/stakingRewards.dummy.json'; import { generateFileNameWithTimestamp } from '../../../common/utils/files'; -import type { RedeemItnRewardsStep } from '../types/stakingTypes'; +import type { + RedeemItnRewardsStep, + SmashServerType, +} from '../types/stakingTypes'; import type { CsvFileContent } from '../../../common/types/csv-request.types'; export default class StakingStore extends Store { @@ -39,6 +41,9 @@ export default class StakingStore extends Store { @observable selectedDelegationWalletId = null; @observable stake = INITIAL_DELEGATION_FUNDS; @observable isRanking = false; + // @SMASH TODO: Leave it null until the API response + @observable smashServerType: ?SmashServerType = 'iohk'; // null; + @observable smashServerUrl: ?string = null; /* ---------- Redeem ITN Rewards ---------- */ @observable redeemStep: ?RedeemItnRewardsStep = null; @@ -87,6 +92,8 @@ export default class StakingStore extends Store { stakingActions.fakeStakePoolsLoading.listen(this._setFakePoller); stakingActions.updateDelegatingStake.listen(this._setStake); stakingActions.rankStakePools.listen(this._rankStakePools); + stakingActions.selectSmashServerType.listen(this._selectSmashServerType); + stakingActions.selectSmashServerUrl.listen(this._selectSmashServerUrl); stakingActions.selectDelegationWallet.listen( this._setSelectedDelegationWalletId ); @@ -132,6 +139,22 @@ export default class StakingStore extends Store { this.getStakePoolsData(); }; + @action _selectSmashServerType = ({ + smashServerType, + }: { + smashServerType: SmashServerType, + }) => { + this.smashServerType = smashServerType; + }; + + @action _selectSmashServerUrl = ({ + smashServerUrl, + }: { + smashServerUrl: string, + }) => { + this.smashServerUrl = smashServerUrl; + }; + @action _joinStakePool = async (request: JoinStakePoolRequest) => { const { walletId, stakePoolId, passphrase } = request; diff --git a/source/renderer/app/types/stakingTypes.js b/source/renderer/app/types/stakingTypes.js index 1141d34c2f..c3882dd018 100644 --- a/source/renderer/app/types/stakingTypes.js +++ b/source/renderer/app/types/stakingTypes.js @@ -1,3 +1,4 @@ // @flow export type RedeemItnRewardsStep = 'configuration' | 'confirmation' | 'result'; +export type SmashServerType = 'iohk' | 'cardano' | 'custom';