Skip to content

Commit

Permalink
Merge remote-tracking branch 'benma/electrum-tsx'
Browse files Browse the repository at this point in the history
  • Loading branch information
benma committed Oct 25, 2022
2 parents 47620fb + 2880f90 commit 169be46
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 178 deletions.
12 changes: 12 additions & 0 deletions frontends/web/src/api/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,15 @@ export const isMoonpayBuySupported = (code: string) => {
return apiGet(`exchange/moonpay/buy-supported/${code}`);
};
};

export const getDefaultConfig = (): Promise<any> => {
return apiGet('config/default');
};

export const getConfig = (): Promise<any> => {
return apiGet('config');
};

export const setConfig = (config: any): Promise<null> => {
return apiPost('config', config);
};
2 changes: 1 addition & 1 deletion frontends/web/src/routes/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { DeviceSwitch } from './device/deviceswitch';
import ManageBackups from './device/manage-backups/manage-backups';
import { ManageAccounts } from './settings/manage-accounts';
import { Exchanges } from './exchanges/exchanges';
import ElectrumSettings from './settings/electrum';
import { ElectrumSettings } from './settings/electrum';
import { Settings } from './settings/settings';
import { Passphrase } from './device/bitbox02/passphrase';
import { Account } from './account/account';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2018 Shift Devices AG
* Copyright 2022 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.
Expand All @@ -16,15 +16,10 @@

import { Component } from 'react';
import { withTranslation } from 'react-i18next';
import { Guide } from '../../components/guide/guide';
import { Entry } from '../../components/guide/entry';
import { ButtonLink, Button, Input } from '../../components/forms';
import { apiGet, apiPost } from '../../utils/request';
import { Header } from '../../components/layout';
import { confirmation } from '../../components/confirm/Confirm';
import { Button, Input } from '../../components/forms';
import { apiPost } from '../../utils/request';
import { alertUser } from '../../components/alert/Alert';
import style from './electrum.module.css';
import A from '../../components/anchor/anchor';

class ElectrumServerClass extends Component {
state = {
Expand Down Expand Up @@ -216,172 +211,3 @@ class ElectrumServerClass extends Component {
}

export const ElectrumServer = withTranslation()(ElectrumServerClass);

class ElectrumServersClass extends Component {
state = {
electrumServers: [],
};

componentDidMount() {
apiGet('config').then(config => {
this.setState({ electrumServers: config.backend[this.props.coin].electrumServers });
});
}

save = () => {
apiGet('config').then(config => {
config.backend[this.props.coin].electrumServers = this.state.electrumServers;
apiPost('config', config);
});
};

onAdd = server => {
let electrumServers = this.state.electrumServers.slice();
electrumServers.push(server);
this.setState({ electrumServers });
this.save();
};

onRemove = index => {
let electrumServers = this.state.electrumServers.slice();
electrumServers.splice(index, 1);
this.setState({ electrumServers });
this.save();
};

resetToDefault = () => {
confirmation(this.props.t('settings.electrum.resetConfirm'), response => {
if (response) {
apiGet('config/default').then(config => {
this.setState({ electrumServers: config.backend[this.props.coin].electrumServers });
this.save();
});
} else {
return;
}
});
};

render() {
const { t } = this.props;
const { electrumServers } = this.state;
let onRemove = (server, index) => (() => {
confirmation(t('settings.electrum.removeConfirm', { server: server.server }), confirmed => {
if (confirmed) {
this.onRemove(index);
}
});
});
return (
<div className={style.serversContainer}>
<div className="row">
<div className={['flex flex-row flex-between flex-items-center', style.titleContainer].join(' ')}>
<h4 className="subTitle m-none">{t('settings.electrum.servers')}</h4>
<A href="#" className={['labelLarge labelLink', style.resetLink].join(' ')} onClick={this.resetToDefault}>{t('settings.electrum.reset')}</A>
</div>
<ul className={style.servers}>
{
electrumServers.map((server, index) => (
<ElectrumServer
// @ts-ignore
key={server.server + server.tls.toString()}
server={server}
onRemove={onRemove(server, index)}
/>
))
}
</ul>
</div>
<hr />
<div className="row">
<h4 className="subTitle">{t('settings.electrum.add')}</h4>
<ElectrumServer server={null} onAdd={this.onAdd} />
</div>
</div>
);
}
}

const ElectrumServers = withTranslation()(ElectrumServersClass);

class ElectrumSettings extends Component {
state = {
testing: false,
activeTab: 'btc',
};

componentDidMount() {
apiGet('testing').then(testing => this.setState({ testing }));
}

handleTab = e => {
const target = e.target.dataset.tab;
this.setState({ activeTab: target });
};

render() {
const { i18n, t } = this.props;
const { testing, activeTab } = this.state;
return (
<div className="contentWithGuide">
<div className="container">
<Header title={<h2>{t('settings.expert.electrum.title')}</h2>} />
<div className="innerContainer scrollableContainer">
<div className="content padded">
<div className="flex flex-row flex-between flex-items-center tabs">
<div className={['tab', activeTab === 'btc' ? 'active' : ''].join(' ')}>
<a href="#" onClick={this.handleTab} data-tab="btc">{t(`settings.electrum.title-${testing ? 'tbtc' : 'btc'}`)}</a>
</div>
<div className={['tab', activeTab === 'ltc' ? 'active' : ''].join(' ')}>
<a href="#" onClick={this.handleTab} data-tab="ltc">{t(`settings.electrum.title-${testing ? 'tltc' : 'ltc'}`)}</a>
</div>
</div>
{
activeTab === 'btc' && (
<ElectrumServers
key={testing ? 'tbtc' : 'btc'}
coin={testing ? 'tbtc' : 'btc'}
/>
)
}
{
activeTab === 'ltc' && (
<ElectrumServers
key={testing ? 'tltc' : 'ltc'}
coin={testing ? 'tltc' : 'ltc'}
/>
)
}
<div style={{ marginBottom: 20 }}>
<ButtonLink
secondary
to={'/settings'}>
{t('button.back')}
</ButtonLink>
</div>
</div>
</div>
</div>
<Guide>
<Entry key="guide.settings-electrum.what" entry={t('guide.settings-electrum.what')} />
<Entry key="guide.settings-electrum.why" entry={t('guide.settings-electrum.why')} />
<Entry key="guide.settings-electrum.options" entry={t('guide.settings-electrum.options')} />
<Entry key="guide.settings-electrum.connection" entry={t('guide.settings-electrum.connection')} />
<Entry key="guide.settings-electrum.tor" entry={t('guide.settings-electrum.tor')} />
<Entry key="guide.settings-electrum.instructions" entry={{
link: {
text: t('guide.settings-electrum.instructions.link.text'),
url: (i18n.language === 'de')
? 'https://shiftcrypto.support/help/de-de/14-privatsphare/29-verbindung-der-bitboxapp-zu-meinem-bitcoin-full-node'
: 'https://shiftcrypto.support/help/en-us/14-privacy/29-how-to-connect-the-bitboxapp-to-my-own-full-node'
},
text: t('guide.settings-electrum.instructions.text'),
title: t('guide.settings-electrum.instructions.title')
}} />
</Guide>
</div>
);
}
}

export default withTranslation()(ElectrumSettings);
111 changes: 111 additions & 0 deletions frontends/web/src/routes/settings/electrum-servers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* Copyright 2022 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 { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ElectrumServer } from './electrum-server';
import { getConfig, getDefaultConfig, setConfig } from '../../api/backend';
import { confirmation } from '../../components/confirm/Confirm';
import style from './electrum.module.css';
import A from '../../components/anchor/anchor';

type Props = {
coin: 'btc' | 'tbtc' | 'ltc' | 'tltc';
};

type IElectrumServer = {
server: string;
tls: boolean;
pemCert: string;
}

export const ElectrumServers = ({
coin
}: Props) => {
const { t } = useTranslation();
const [config, setConfigState] = useState<any>();
const loadConfig = () => {
getConfig().then(setConfigState);
};
useEffect(loadConfig, []);
if (config === undefined) {
return null;
}
const electrumServers: IElectrumServer[] = config.backend[coin].electrumServers;

const save = async (newElectrumServers: IElectrumServer[]) => {
const currentConfig = await getConfig();
currentConfig.backend[coin].electrumServers = newElectrumServers;
await setConfig(currentConfig);
setConfigState(currentConfig);
};

const onAdd = (server: IElectrumServer) => {
let newElectrumServers = [...electrumServers, server];
save(newElectrumServers);
};

const onRemove = (index: number) => {
let newElectrumServers = [...electrumServers];
newElectrumServers.splice(index, 1);
save(newElectrumServers);
};

const resetToDefault = () => {
confirmation(t('settings.electrum.resetConfirm'), response => {
if (response) {
getDefaultConfig().then(config => {
save(config.backend[coin].electrumServers);
});
}
});
};

const onRemoveCb = (server: IElectrumServer, index: number) => (() => {
confirmation(t('settings.electrum.removeConfirm', { server: server.server }), confirmed => {
if (confirmed) {
onRemove(index);
}
});
});

return (
<div className={style.serversContainer}>
<div className="row">
<div className={['flex flex-row flex-between flex-items-center', style.titleContainer].join(' ')}>
<h4 className="subTitle m-none">{t('settings.electrum.servers')}</h4>
<A href="#" className={['labelLarge labelLink', style.resetLink].join(' ')} onClick={resetToDefault}>{t('settings.electrum.reset')}</A>
</div>
<ul className={style.servers}>
{
electrumServers.map((server, index) => (
<ElectrumServer
key={server.server + server.tls.toString()}
server={server}
onRemove={onRemoveCb(server, index)}
/>
))
}
</ul>
</div>
<hr />
<div className="row">
<h4 className="subTitle">{t('settings.electrum.add')}</h4>
<ElectrumServer server={null} onAdd={onAdd} />
</div>
</div>
);
};
Loading

0 comments on commit 169be46

Please sign in to comment.