feature: wallet sync export button

This commit is contained in:
zeppi 2022-07-15 16:49:24 -04:00
parent 7e0363a563
commit c3c641b6ba
8 changed files with 132 additions and 1 deletions

View file

@ -3,6 +3,7 @@ import { selectHasChannels } from 'redux/selectors/claims';
import { selectWalletIsEncrypted } from 'redux/selectors/wallet';
import { doWalletStatus } from 'redux/actions/wallet';
import { selectUser, selectUserVerifiedEmail } from 'redux/selectors/user';
import { doOpenModal } from 'redux/actions/app';
import SettingAccount from './view';
@ -14,6 +15,7 @@ const select = (state) => ({
});
const perform = (dispatch) => ({
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
doWalletStatus: () => dispatch(doWalletStatus()),
});

View file

@ -1,6 +1,7 @@
// @flow
import * as ICONS from 'constants/icons';
import * as PAGES from 'constants/pages';
import * as MODALS from 'constants/modal_types';
import { SETTINGS_GRP } from 'constants/settings';
import React from 'react';
import Button from 'component/button';
@ -17,10 +18,11 @@ type Props = {
user: User,
hasChannels: boolean,
doWalletStatus: () => void,
openModal: (string, any) => void,
};
export default function SettingAccount(props: Props) {
const { isAuthenticated, walletEncrypted, user, hasChannels, doWalletStatus } = props;
const { isAuthenticated, walletEncrypted, user, hasChannels, doWalletStatus, openModal } = props;
const [storedPassword, setStoredPassword] = React.useState(false);
// Determine if password is stored.
@ -107,6 +109,20 @@ export default function SettingAccount(props: Props) {
<SettingsRow title={__('Purchases')} subtitle={__('View your purchased content.')}>
<Button button="inverse" label={__('Manage')} icon={ICONS.ARROW_RIGHT} navigate={`/$/${PAGES.LIBRARY}`} />
</SettingsRow>
<SettingsRow
title={__('Export Wallet')}
subtitle={__('Export encrypted sync data for import in another app.')}
>
<Button
button="secondary"
className="expandable__button"
label={__('Export')}
aria-label={__('Export wallet')}
onClick={() => {
openModal(MODALS.WALLET_EXPORT, {});
}}
/>
</SettingsRow>
</>
}
/>

View file

@ -0,0 +1,9 @@
import WalletExport from './view';
import { doToast } from 'redux/actions/notifications';
import { connect } from 'react-redux';
const perform = (dispatch) => ({
toast: (message, isError) => dispatch(doToast({ message, isError })),
});
export default connect(null, perform)(WalletExport);

View file

@ -0,0 +1,75 @@
// @flow
import React from 'react';
import Button from 'component/button';
import { Form, FormField } from 'component/common/form';
import Card from 'component/common/card';
import Lbry from 'lbry';
import { clipboard } from 'electron';
import * as ICONS from 'constants/icons';
import FileExporter from 'component/common/file-exporter';
type Props = {
toast: (string, boolean) => void,
};
function WalletExport(props: Props) {
const { toast } = props;
const [password, setPassword] = React.useState();
const [data, setData] = React.useState();
const [fetching, setFetching] = React.useState();
const getData = async (password) => {
setFetching(true);
const data = await Lbry.sync_apply({ password });
setFetching(false);
setData(data);
};
return (
<Card
title={__('Export Wallet')}
subtitle={
data
? __('Your Sync Data is prepared. You can now copy or save it.')
: __('Export wallet sync data. Choose a secure password you will need for import.')
}
actions={
<React.Fragment>
{!data && (
<Form onSubmit={() => alert()}>
<FormField
autoFocus
type="password"
name="password_set"
label={__('Choose Password')}
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<div className="section__actions--between">
<Button button={'primary'} onClick={() => getData(password)} label={'Get Data'} disabled={fetching} />
</div>
</Form>
)}
{data && (
<div className="section__actions">
<div className="section__actions--between">
<FileExporter data={JSON.stringify(data)} label={'Download'} defaultFileName={'data.json'} />
<Button
button={'secondary'}
onClick={() => {
clipboard.writeText(JSON.stringify(data));
toast(__('Sync data copied.'), false);
}}
label={'Copy Data'}
icon={ICONS.COPY}
/>
</div>
</div>
)}
</React.Fragment>
}
/>
);
}
export default WalletExport;

View file

@ -54,3 +54,4 @@ export const CONFIRM_ODYSEE_MEMBERSHIP = 'CONFIRM_ODYSEE_MEMBERSHIP';
export const MEMBERSHIP_SPLASH = 'MEMBERSHIP_SPLASH';
export const HIDE_RECOMMENDATION = 'HIDE_RECOMMENDATION';
export const ANNOUNCEMENTS = 'ANNOUNCEMENTS';
export const WALLET_EXPORT = 'WALLET_EXPORT';

View file

@ -55,6 +55,7 @@ const MAP = Object.freeze({
[MODALS.WALLET_ENCRYPT]: lazyImport(() => import('modal/modalWalletEncrypt' /* webpackChunkName: "modalWalletEncrypt" */)),
[MODALS.WALLET_PASSWORD_UNSAVE]: lazyImport(() => import('modal/modalPasswordUnsave' /* webpackChunkName: "modalPasswordUnsave" */)),
[MODALS.WALLET_UNLOCK]: lazyImport(() => import('modal/modalWalletUnlock' /* webpackChunkName: "modalWalletUnlock" */)),
[MODALS.WALLET_EXPORT]: lazyImport(() => import('modal/modalWalletExport' /* webpackChunkName: "modalWalletUnlock" */)),
[MODALS.YOUTUBE_WELCOME]: lazyImport(() => import('modal/modalYoutubeWelcome' /* webpackChunkName: "modalYoutubeWelcome" */)),
});

View file

@ -0,0 +1,9 @@
import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app';
import ModalWalletExport from './view';
const perform = (dispatch) => ({
closeModal: () => dispatch(doHideModal()),
});
export default connect(null, perform)(ModalWalletExport);

View file

@ -0,0 +1,18 @@
// @flow
import React from 'react';
import { Modal } from 'modal/modal';
import WalletExport from 'component/walletExport';
type Props = {
closeModal: () => void,
};
export default function ModalWalletExport(props: Props) {
const { closeModal } = props;
return (
<Modal isOpen contentLabel={'Export Wallet'} type="card" onAborted={closeModal}>
<WalletExport />
</Modal>
);
}