",
+ "defaultMessage": "!!!These wallets were found in your Daedalus state directory.Please select the wallets you want to import.
",
"description": "These wallets were found in your Daedalus state directory. Please select the wallets you want to import.",
"end": {
"column": 3,
diff --git a/source/renderer/app/i18n/locales/en-US.json b/source/renderer/app/i18n/locales/en-US.json
index 82c1c2db08..2410809878 100755
--- a/source/renderer/app/i18n/locales/en-US.json
+++ b/source/renderer/app/i18n/locales/en-US.json
@@ -515,6 +515,12 @@
"wallet.create.dialog.title.itn": "Create a new Rewards wallet",
"wallet.create.dialog.validateStep": "Validate",
"wallet.create.dialog.walletNameHint": "Enter wallet name",
+ "wallet.hardware.hardwareWalletBegin": "To begin, connect and unlock your Hardware wallet Device",
+ "wallet.hardware.hardwareWalletExport": "Export public key on your device",
+ "wallet.hardware.hardwareWalletInstructions": "Follow instructions to access your wallet",
+ "wallet.hardware.hardwareWalletLedgerBegin": "To begin, connect and unlock your Ledger Device",
+ "wallet.hardware.hardwareWalletTitle": "Hardware wallet",
+ "wallet.hardware.ledgerWalletTitle": "Ledger wallet",
"wallet.import.file.dialog.buttonLabel": "Import wallets",
"wallet.import.file.dialog.description": "This feature enables you to import wallets from the previous version of Daedalus, from the Daedalus state directory, or from a ‘secret.key’ file.
It can be used to import wallets quickly without entering the wallet recovery phrase for each wallet, or to import wallets for which you have lost your wallet recovery phrase.
After importing a wallet for which you have lost your wallet recovery phrase, please create a new wallet and transfer all funds from the old wallet to the new wallet. Keep the wallet recovery phrase for your new wallet secure.
",
"wallet.import.file.dialog.importFromLabel": "Import from:",
diff --git a/source/renderer/app/i18n/locales/ja-JP.json b/source/renderer/app/i18n/locales/ja-JP.json
index 0a9d103149..23b3dcce52 100755
--- a/source/renderer/app/i18n/locales/ja-JP.json
+++ b/source/renderer/app/i18n/locales/ja-JP.json
@@ -515,6 +515,12 @@
"wallet.create.dialog.title.itn": "報酬ウォレットを作成する",
"wallet.create.dialog.validateStep": "!!!Validate",
"wallet.create.dialog.walletNameHint": "ウォレット名を入力してください",
+ "wallet.hardware.hardwareWalletBegin": "!!!To begin, connect and unlock your Hardware wallet Device",
+ "wallet.hardware.hardwareWalletExport": "!!!Export public key on your device",
+ "wallet.hardware.hardwareWalletInstructions": "!!!Follow instructions to access your wallet",
+ "wallet.hardware.hardwareWalletLedgerBegin": "!!!To begin, connect and unlock your Ledger Device",
+ "wallet.hardware.hardwareWalletTitle": "!!!Hardware wallet",
+ "wallet.hardware.ledgerWalletTitle": "!!!Ledger wallet",
"wallet.import.file.dialog.buttonLabel": "ウォレットをインポートする",
"wallet.import.file.dialog.description": "この機能により、Daedalusの旧バージョン、Daedalusステータスディレクトリー、またはsecret.keyファイルからウォレットをインポートすることができます。
各ウォレットの復元フレーズを入力せずに素早くウォレットをインポートできるほか、復元フレーズを紛失したウォレットのインポートも可能です。
復元フレーズを紛失したウォレットをインポートした場合は、インポート後に新規ウォレットを作成してすべての資金を旧ウォレットから移し、新しいウォレットの復元フレーズを安全な場所に保管してください。
",
"wallet.import.file.dialog.importFromLabel": "インポート元:",
diff --git a/source/renderer/app/routes-config.js b/source/renderer/app/routes-config.js
index 8e49fd388d..2f7c28912a 100644
--- a/source/renderer/app/routes-config.js
+++ b/source/renderer/app/routes-config.js
@@ -29,6 +29,11 @@ export const ROUTES = {
SETTINGS: '/wallets/:id/settings',
UTXO: '/wallets/:id/utxo',
},
+ HARDWARE_WALLETS: {
+ ROOT: '/hardware-wallets',
+ PAGE: '/hardware-wallets/:id/:page',
+ SUMMARY: '/hardware-wallets/:id/summary',
+ },
SETTINGS: {
ROOT: '/settings',
GENERAL: '/settings/general',
diff --git a/source/renderer/app/stores/SidebarStore.js b/source/renderer/app/stores/SidebarStore.js
index 575d6a2314..8cd13b4492 100644
--- a/source/renderer/app/stores/SidebarStore.js
+++ b/source/renderer/app/stores/SidebarStore.js
@@ -3,7 +3,10 @@ import { action, computed, observable } from 'mobx';
import Store from './lib/Store';
import { sidebarConfig } from '../config/sidebarConfig';
import { formattedWalletAmount } from '../utils/formatters';
-import type { SidebarWalletType } from '../types/sidebarTypes';
+import type {
+ SidebarHardwareWalletType,
+ SidebarWalletType,
+} from '../types/sidebarTypes';
export default class SidebarStore extends Store {
@observable CATEGORIES: Array = sidebarConfig.CATEGORIES;
@@ -18,6 +21,9 @@ export default class SidebarStore extends Store {
this._onActivateSidebarCategory
);
sidebarActions.walletSelected.listen(this._onWalletSelected);
+ sidebarActions.hardwareWalletSelected.listen(
+ this._onHardwareWalletSelected
+ );
this.registerReactions([this._syncSidebarRouteWithRouter]);
this._configureCategories();
}
@@ -45,6 +51,26 @@ export default class SidebarStore extends Store {
});
}
+ @computed.struct get hardwareWallets(): Array {
+ const { networkStatus, wallets, walletSettings } = this.stores;
+ return wallets.all.map(wallet => {
+ const {
+ hasNotification,
+ } = walletSettings.getWalletsRecoveryPhraseVerificationData(wallet.id);
+ return {
+ id: wallet.id,
+ title: wallet.name,
+ info: formattedWalletAmount(wallet.amount, true, false),
+ isConnected: networkStatus.isConnected,
+ isRestoreActive: wallet.isRestoring,
+ restoreProgress: wallet.restorationProgress,
+ isNotResponding: wallet.isNotResponding,
+ isLegacy: wallet.isLegacy,
+ hasNotification,
+ };
+ });
+ }
+
@action _configureCategories = () => {
const { isIncentivizedTestnet, isFlight } = global;
if (isIncentivizedTestnet) {
@@ -77,6 +103,10 @@ export default class SidebarStore extends Store {
this.stores.wallets.goToWalletRoute(walletId);
};
+ @action _onHardwareWalletSelected = ({ walletId }: { walletId: string }) => {
+ this.stores.wallets.goToHardwareWalletRoute(walletId);
+ };
+
@action _setActivateSidebarCategory = (category: string) => {
this.activeSidebarCategory = category;
};
diff --git a/source/renderer/app/stores/WalletsStore.js b/source/renderer/app/stores/WalletsStore.js
index aaf0dc0b20..2ebf06f91c 100644
--- a/source/renderer/app/stores/WalletsStore.js
+++ b/source/renderer/app/stores/WalletsStore.js
@@ -169,6 +169,14 @@ export default class WalletsStore extends Store {
@observable transferFundsStep: number = 0;
@observable transferFundsFee: ?BigNumber = null;
+ /* ---------- Hardware Wallet ---------- */
+ @observable isExportingPublicKeyAborted = false;
+ @observable exportingExtendedPublicKey = false;
+ @observable isDeviceConnected = false;
+ @observable fetchingDevice = false;
+ @observable isTrezor = false;
+ @observable isLedger = false;
+
/* ---------- Other ---------- */
_newWalletDetails: {
@@ -734,6 +742,11 @@ export default class WalletsStore extends Store {
return matchRoute(`${ROUTES.WALLETS.ROOT}(/*rest)`, currentRoute);
}
+ @computed get isHardwareWalletRoute(): boolean {
+ const { currentRoute } = this.stores.app;
+ return matchRoute(`${ROUTES.HARDWARE_WALLETS.ROOT}(/*rest)`, currentRoute);
+ }
+
@computed get restoreRequest(): Request {
switch (this.walletKind) {
case WALLET_KINDS.DAEDALUS:
@@ -764,6 +777,11 @@ export default class WalletsStore extends Store {
getWalletRoute = (walletId: string, page: string = 'summary'): string =>
buildRoute(ROUTES.WALLETS.PAGE, { id: walletId, page });
+ getHardwareWalletRoute = (
+ walletId: string,
+ page: string = 'summary'
+ ): string => buildRoute(ROUTES.HARDWARE_WALLETS.PAGE, { id: walletId, page });
+
// ACTIONS
goToWalletRoute(walletId: string) {
@@ -771,6 +789,11 @@ export default class WalletsStore extends Store {
this.actions.router.goToRoute.trigger({ route });
}
+ goToHardwareWalletRoute(walletId: string) {
+ const route = this.getHardwareWalletRoute(walletId);
+ this.actions.router.goToRoute.trigger({ route });
+ }
+
// =================== PRIVATE API ==================== //
@computed get _canRedirectToWallet(): boolean {
diff --git a/source/renderer/app/themes/daedalus/cardano.js b/source/renderer/app/themes/daedalus/cardano.js
index 4cb0afebb2..250de809b2 100644
--- a/source/renderer/app/themes/daedalus/cardano.js
+++ b/source/renderer/app/themes/daedalus/cardano.js
@@ -249,6 +249,14 @@ export const CARDANO_THEME_OUTPUT = {
'--font-black': 'NotoSans-Black, NotoSansCJKjp-Black',
'--font-mono': 'SFMono-Light',
},
+ hardwareWallet: {
+ '--theme-hardware-wallet-step-background-color': '#fafbfc',
+ '--theme-hardware-wallet-step-border-active-color': '#296fd0',
+ '--theme-hardware-wallet-step-border-color': '#c6cdd6',
+ '--theme-hardware-wallet-step-color': '#5e6066',
+ '--theme-hardware-wallet-title-color': '#5e6066',
+ '--theme-hardware-wallet-message-color': '#5e6066',
+ },
icon: {
'--theme-icon-nav-color': '#cecfd1',
'--theme-icon-nav-color-active': '#5e6066',
diff --git a/source/renderer/app/themes/daedalus/dark-blue.js b/source/renderer/app/themes/daedalus/dark-blue.js
index cd6685f4a8..53b201de11 100644
--- a/source/renderer/app/themes/daedalus/dark-blue.js
+++ b/source/renderer/app/themes/daedalus/dark-blue.js
@@ -252,6 +252,14 @@ export const DARK_BLUE_THEME_OUTPUT = {
'--font-black': 'NotoSans-Black, NotoSansCJKjp-Black',
'--font-mono': 'SFMono-Light',
},
+ hardwareWallet: {
+ '--theme-hardware-wallet-step-background-color': '#fafbfc',
+ '--theme-hardware-wallet-step-border-active-color': '#296fd0',
+ '--theme-hardware-wallet-step-border-color': '#c6cdd6',
+ '--theme-hardware-wallet-step-color': '#5e6066',
+ '--theme-hardware-wallet-title-color': '#5e6066',
+ '--theme-hardware-wallet-message-color': '#5e6066',
+ },
icon: {
'--theme-icon-nav-color': '#9ba6b3',
'--theme-icon-nav-color-active': '#e9f4fe',
diff --git a/source/renderer/app/themes/daedalus/dark-cardano.js b/source/renderer/app/themes/daedalus/dark-cardano.js
index e45ade7c74..e366bf79a9 100644
--- a/source/renderer/app/themes/daedalus/dark-cardano.js
+++ b/source/renderer/app/themes/daedalus/dark-cardano.js
@@ -236,6 +236,14 @@ export const DARK_CARDANO_THEME_OUTPUT = {
'--font-black': 'NotoSans-Black, NotoSansCJKjp-Black',
'--font-mono': 'SFMono-Light',
},
+ hardwareWallet: {
+ '--theme-hardware-wallet-step-background-color': '#fafbfc',
+ '--theme-hardware-wallet-step-border-active-color': '#296fd0',
+ '--theme-hardware-wallet-step-border-color': '#c6cdd6',
+ '--theme-hardware-wallet-step-color': '#5e6066',
+ '--theme-hardware-wallet-title-color': '#5e6066',
+ '--theme-hardware-wallet-message-color': '#5e6066',
+ },
icon: {
'--theme-icon-nav-color': 'rgba(255, 255, 255, 0.6)',
'--theme-icon-nav-color-active': 'rgba(255, 255, 255, 1)',
diff --git a/source/renderer/app/themes/daedalus/flight-candidate.js b/source/renderer/app/themes/daedalus/flight-candidate.js
index 5ee8ced3c2..5c01322569 100644
--- a/source/renderer/app/themes/daedalus/flight-candidate.js
+++ b/source/renderer/app/themes/daedalus/flight-candidate.js
@@ -236,6 +236,14 @@ export const FLIGHT_CANDIDATE_THEME_OUTPUT = {
'--font-black': 'NotoSans-Black, NotoSansCJKjp-Black',
'--font-mono': 'SFMono-Light',
},
+ hardwareWallet: {
+ '--theme-hardware-wallet-step-background-color': '#fafbfc',
+ '--theme-hardware-wallet-step-border-active-color': '#296fd0',
+ '--theme-hardware-wallet-step-border-color': '#c6cdd6',
+ '--theme-hardware-wallet-step-color': '#5e6066',
+ '--theme-hardware-wallet-title-color': '#5e6066',
+ '--theme-hardware-wallet-message-color': '#5e6066',
+ },
icon: {
'--theme-icon-nav-color': 'rgba(255, 255, 255, 0.6)',
'--theme-icon-nav-color-active': 'rgba(255, 255, 255, 1)',
diff --git a/source/renderer/app/themes/daedalus/incentivized-testnet.js b/source/renderer/app/themes/daedalus/incentivized-testnet.js
index bf0b38908a..e086a59397 100644
--- a/source/renderer/app/themes/daedalus/incentivized-testnet.js
+++ b/source/renderer/app/themes/daedalus/incentivized-testnet.js
@@ -237,6 +237,14 @@ export const INCENTIVIZED_TESTNET_THEME_OUTPUT = {
'--font-black': 'NotoSans-Black, NotoSansCJKjp-Black',
'--font-mono': 'SFMono-Light',
},
+ hardwareWallet: {
+ '--theme-hardware-wallet-step-background-color': '#fafbfc',
+ '--theme-hardware-wallet-step-border-active-color': '#296fd0',
+ '--theme-hardware-wallet-step-border-color': '#c6cdd6',
+ '--theme-hardware-wallet-step-color': '#5e6066',
+ '--theme-hardware-wallet-title-color': '#5e6066',
+ '--theme-hardware-wallet-message-color': '#5e6066',
+ },
icon: {
'--theme-icon-nav-color': 'rgba(255, 255, 255, 0.6)',
'--theme-icon-nav-color-active': 'rgba(255, 255, 255, 1)',
diff --git a/source/renderer/app/themes/daedalus/light-blue.js b/source/renderer/app/themes/daedalus/light-blue.js
index 173cb12921..da22262b85 100644
--- a/source/renderer/app/themes/daedalus/light-blue.js
+++ b/source/renderer/app/themes/daedalus/light-blue.js
@@ -249,6 +249,14 @@ export const LIGHT_BLUE_THEME_OUTPUT = {
'--font-black': 'NotoSans-Black, NotoSansCJKjp-Black',
'--font-mono': 'SFMono-Light',
},
+ hardwareWallet: {
+ '--theme-hardware-wallet-step-background-color': '#fafbfc',
+ '--theme-hardware-wallet-step-border-active-color': '#296fd0',
+ '--theme-hardware-wallet-step-border-color': '#c6cdd6',
+ '--theme-hardware-wallet-step-color': '#5e6066',
+ '--theme-hardware-wallet-title-color': '#5e6066',
+ '--theme-hardware-wallet-message-color': '#5e6066',
+ },
icon: {
'--theme-icon-nav-color': 'rgba(250, 251, 252, 0.6)',
'--theme-icon-nav-color-active': '#1d2e47',
diff --git a/source/renderer/app/themes/daedalus/white.js b/source/renderer/app/themes/daedalus/white.js
index 8d78788b70..c48fdbc7ce 100644
--- a/source/renderer/app/themes/daedalus/white.js
+++ b/source/renderer/app/themes/daedalus/white.js
@@ -238,6 +238,14 @@ export const WHITE_THEME_OUTPUT = {
'--font-black': 'NotoSans-Black, NotoSansCJKjp-Black',
'--font-mono': 'SFMono-Light',
},
+ hardwareWallet: {
+ '--theme-hardware-wallet-step-background-color': '#fafbfc',
+ '--theme-hardware-wallet-step-border-active-color': '#296fd0',
+ '--theme-hardware-wallet-step-border-color': '#c6cdd6',
+ '--theme-hardware-wallet-step-color': '#5e6066',
+ '--theme-hardware-wallet-title-color': '#5e6066',
+ '--theme-hardware-wallet-message-color': '#5e6066',
+ },
icon: {
'--theme-icon-nav-color': 'rgba(45, 45, 45, 0.6)',
'--theme-icon-nav-color-active': '#29b595',
diff --git a/source/renderer/app/themes/daedalus/yellow.js b/source/renderer/app/themes/daedalus/yellow.js
index 8730d1f0a6..1e80a846ec 100644
--- a/source/renderer/app/themes/daedalus/yellow.js
+++ b/source/renderer/app/themes/daedalus/yellow.js
@@ -240,6 +240,14 @@ export const YELLOW_THEME_OUTPUT = {
'--font-black': 'NotoSans-Black, NotoSansCJKjp-Black',
'--font-mono': 'SFMono-Light',
},
+ hardwareWallet: {
+ '--theme-hardware-wallet-step-background-color': '#fafbfc',
+ '--theme-hardware-wallet-step-border-active-color': '#296fd0',
+ '--theme-hardware-wallet-step-border-color': '#c6cdd6',
+ '--theme-hardware-wallet-step-color': '#5e6066',
+ '--theme-hardware-wallet-title-color': '#5e6066',
+ '--theme-hardware-wallet-message-color': '#5e6066',
+ },
icon: {
'--theme-icon-nav-color': 'rgba(45, 45, 45, 0.6)',
'--theme-icon-nav-color-active': '#ffffff',
diff --git a/source/renderer/app/themes/utils/createTheme.js b/source/renderer/app/themes/utils/createTheme.js
index b36cfaa60f..36e6e33011 100644
--- a/source/renderer/app/themes/utils/createTheme.js
+++ b/source/renderer/app/themes/utils/createTheme.js
@@ -503,6 +503,14 @@ export const createDaedalusComponentsTheme = (
'--font-black': `${fonts.black}`,
'--font-mono': `${fonts.mono}`,
},
+ hardwareWallet: {
+ '--theme-hardware-wallet-step-background-color': '#fafbfc',
+ '--theme-hardware-wallet-step-border-active-color': '#296fd0',
+ '--theme-hardware-wallet-step-border-color': '#c6cdd6',
+ '--theme-hardware-wallet-step-color': '#5e6066',
+ '--theme-hardware-wallet-title-color': '#5e6066',
+ '--theme-hardware-wallet-message-color': '#5e6066',
+ },
icon: {
'--theme-icon-nav-color': `${text.secondary}`,
'--theme-icon-nav-color-active': `${text.primary}`,
diff --git a/source/renderer/app/types/sidebarTypes.js b/source/renderer/app/types/sidebarTypes.js
index 3f3619fd99..4b69172b87 100644
--- a/source/renderer/app/types/sidebarTypes.js
+++ b/source/renderer/app/types/sidebarTypes.js
@@ -10,3 +10,15 @@ export type SidebarWalletType = {
isNotResponding: boolean,
hasNotification: boolean,
};
+
+export type SidebarHardwareWalletType = {
+ id: string,
+ title: string,
+ info: string,
+ isConnected: boolean,
+ isRestoreActive?: boolean,
+ restoreProgress?: number,
+ isLegacy: boolean,
+ isNotResponding: boolean,
+ hasNotification: boolean,
+};
diff --git a/storybook/stories/_support/StoryLayout.js b/storybook/stories/_support/StoryLayout.js
index 0eb2643aae..6b33e4ad2d 100644
--- a/storybook/stories/_support/StoryLayout.js
+++ b/storybook/stories/_support/StoryLayout.js
@@ -17,7 +17,10 @@ import Wallet, {
} from '../../../source/renderer/app/domains/Wallet.js';
import NewsFeedIcon from '../../../source/renderer/app/components/widgets/NewsFeedIcon';
import type { SidebarMenus } from '../../../source/renderer/app/components/sidebar/Sidebar';
-import type { SidebarWalletType } from '../../../source/renderer/app/types/sidebarTypes';
+import type {
+ SidebarHardwareWalletType,
+ SidebarWalletType,
+} from '../../../source/renderer/app/types/sidebarTypes';
// Empty screen elements
import TopBar from '../../../source/renderer/app/components/layout/TopBar';
@@ -43,12 +46,14 @@ type Props = {
const CATEGORIES_COUNTDOWN = [
CATEGORIES_BY_NAME.WALLETS,
+ CATEGORIES_BY_NAME.HARDWARE_WALLETS,
CATEGORIES_BY_NAME.STAKING_DELEGATION_COUNTDOWN,
CATEGORIES_BY_NAME.SETTINGS,
];
const CATEGORIES = [
CATEGORIES_BY_NAME.WALLETS,
+ CATEGORIES_BY_NAME.HARDWARE_WALLETS,
CATEGORIES_BY_NAME.STAKING,
CATEGORIES_BY_NAME.SETTINGS,
];
@@ -108,7 +113,9 @@ export default class StoryLayout extends Component {
@observable isShowingSubMenus =
this.props.activeSidebarCategory === '/wallets' && !!this.props.children;
- getSidebarWallets = (wallets: Array): Array =>
+ getSidebarWallets = (
+ wallets: Array
+ ): Array =>
wallets.map((wallet: Wallet) => ({
id: wallet.id,
title: wallet.name,
@@ -127,7 +134,7 @@ export default class StoryLayout extends Component {
}));
getSidebarMenus = (
- items: Array,
+ items: Array,
activeWalletId: string,
setActiveWalletId: Function
) => ({
@@ -139,6 +146,14 @@ export default class StoryLayout extends Component {
onWalletItemClick: setActiveWalletId,
},
},
+ hardwareWallets: {
+ items,
+ activeWalletId,
+ actions: {
+ onAddWallet: action('toggleAddWallet'),
+ onHardwareWalletItemClick: setActiveWalletId,
+ },
+ },
});
getSidebar = (
diff --git a/storybook/stories/navigation/Sidebar.stories.js b/storybook/stories/navigation/Sidebar.stories.js
index e8f1bbcb97..8462b873fd 100644
--- a/storybook/stories/navigation/Sidebar.stories.js
+++ b/storybook/stories/navigation/Sidebar.stories.js
@@ -59,6 +59,51 @@ const sidebarMenus = observable({
},
},
},
+ hardwareWallets: null,
+});
+
+const sidebarMenusHardware = observable({
+ wallets: null,
+ hardwareWallets: {
+ items: [
+ {
+ id: '1',
+ title: 'BTC wallet',
+ info: '2.41824 BTC',
+ isNotResponding: false,
+ isConnected: false,
+ isLegacy: false,
+ hasNotification: false,
+ },
+ {
+ id: '2',
+ title: 'ETC wallet',
+ info: '12M ETC',
+ isNotResponding: false,
+ isConnected: false,
+ isLegacy: false,
+ hasNotification: false,
+ },
+ {
+ id: '3',
+ title: 'ADA wallet',
+ info: '9,800 ADA',
+ isNotResponding: false,
+ isConnected: true,
+ isLegacy: false,
+ hasNotification: false,
+ },
+ ],
+ activeWalletId: '3',
+ actions: {
+ onAddWallet: action('toggleAddWallet'),
+ onHardwareWalletItemClick: (walletId: string) => {
+ runInAction(() => {
+ sidebarMenusHardware.hardwareWallets.activeWalletId = walletId;
+ });
+ },
+ },
+ },
});
let emptyMenus;
@@ -116,11 +161,28 @@ storiesOf('Navigation|Sidebar', module)
isIncentivizedTestnet={isIncentivizedTestnetTheme(props.currentTheme)}
/>
))
+ .add('Hardware Wallet Selected', (props: { currentTheme: string }) => (
+ false}
+ onAddWallet={action('onAddWallet')}
+ onOpenDialog={action('openDialog')}
+ onSubmitSupportRequest={() => {}}
+ pathname="/"
+ currentTheme={props.currentTheme}
+ network="testnet"
+ isIncentivizedTestnet={isIncentivizedTestnetTheme(props.currentTheme)}
+ />
+ ))
.add('Delegation Category', (props: { currentTheme: string }) => (
false}
onAddWallet={action('onAddWallet')}
diff --git a/storybook/stories/wallets/_utils/HardwareWalletWithNavigationLayout.js b/storybook/stories/wallets/_utils/HardwareWalletWithNavigationLayout.js
new file mode 100644
index 0000000000..33d9c08dec
--- /dev/null
+++ b/storybook/stories/wallets/_utils/HardwareWalletWithNavigationLayout.js
@@ -0,0 +1,71 @@
+// @flow
+import React, { Component, Children } from 'react';
+import { linkTo } from '@storybook/addon-links';
+import { get } from 'lodash';
+import HardwareWalletWithNavigation from '../../../../source/renderer/app/components/hardware-wallet/layouts/HardwareWalletWithNavigation';
+
+// Context has many changeable props but "kind" is required
+type contextType = {
+ kind: string,
+};
+
+type Props = {
+ context: contextType,
+ children?: any | Node,
+ stores?: ?{},
+};
+
+const walletStories = {
+ send: 'Wallets|Send',
+ receive: 'Wallets|Receive',
+ transactions: 'Wallets|Transactions',
+ summary: 'Wallets|Summary',
+ settings: 'Wallets|Settings',
+};
+
+export default class WalletWithNavigationLayout extends Component {
+ static defaultProps = { stores: null, storiesProps: null };
+
+ getItemFromContext = (context: contextType) => {
+ return context.kind.replace('Wallets|', '').toLocaleLowerCase();
+ };
+
+ render() {
+ const { stores, context, children } = this.props;
+ const activeWallet = get(stores, ['wallets', 'active']);
+ const { hasPassword, isLegacy, isNotResponding } = activeWallet;
+ const contextItem = context.kind
+ .replace('Wallets|', '')
+ .toLocaleLowerCase();
+
+ return (
+ item === contextItem}
+ hasPassword={hasPassword}
+ hasNotification={false}
+ isLegacy={isLegacy}
+ isNotResponding={isNotResponding}
+ isSetWalletPasswordDialogOpen={false}
+ onWalletNavItemClick={linkTo(item => walletStories[item])}
+ onSetWalletPassword={() => {}}
+ onOpenExternalLink={() => {}}
+ onRestartNode={() => {}}
+ walletNotConnected
+ isDeviceConnected={false}
+ fetchingDevice={false}
+ exportingExtendedPublicKey={false}
+ isExportingPublicKeyAborted={false}
+ isLedger
+ isTrezor={false}
+ >
+ {Children.map(children, child =>
+ React.cloneElement(child, {
+ stores,
+ wallet: activeWallet || child.props.wallet,
+ })
+ )}
+
+ );
+ }
+}
diff --git a/storybook/stories/wallets/_utils/HardwareWalletsWrapper.js b/storybook/stories/wallets/_utils/HardwareWalletsWrapper.js
new file mode 100644
index 0000000000..fa3eaed677
--- /dev/null
+++ b/storybook/stories/wallets/_utils/HardwareWalletsWrapper.js
@@ -0,0 +1,19 @@
+// @flow
+import React from 'react';
+import { withKnobs } from '@storybook/addon-knobs';
+import StoryLayout from '../../_support/StoryLayout';
+import StoryProvider from '../../_support/StoryProvider';
+import StoryDecorator from '../../_support/StoryDecorator';
+
+export default (story: any, context: any) => {
+ const storyWithKnobs = withKnobs(story, context);
+ return (
+
+
+
+ {storyWithKnobs}
+
+
+
+ );
+};
diff --git a/storybook/stories/wallets/hardwareWallets/HardwareWallets.stories.js b/storybook/stories/wallets/hardwareWallets/HardwareWallets.stories.js
new file mode 100644
index 0000000000..b923f9a37e
--- /dev/null
+++ b/storybook/stories/wallets/hardwareWallets/HardwareWallets.stories.js
@@ -0,0 +1,126 @@
+// @flow
+import React from 'react';
+import { storiesOf } from '@storybook/react';
+import { action } from '@storybook/addon-actions';
+import { boolean } from '@storybook/addon-knobs';
+import ConnectHardwareWallet from '../../../../source/renderer/app/components/hardware-wallet/settings/ConnectHardwareWallet';
+import HardwareWalletsWrapper from '../_utils/HardwareWalletsWrapper';
+
+storiesOf('Wallets|Hardware Wallets', module)
+ .addDecorator(HardwareWalletsWrapper)
+
+ // ====== Stories ======
+
+ .add('Hardware wallet connect Ledger step 1', () => (
+
+ ))
+
+ .add('Hardware wallet connect Ledger step 2', () => (
+
+ ))
+
+ .add('Hardware wallet connect Ledger step 3', () => (
+
+ ))
+
+ .add('Hardware wallet connect Ledger step 4', () => (
+
+ ))
+
+ .add('Hardware wallet connect Trezor step 1', () => (
+
+ ))
+
+ .add('Hardware wallet connect Trezor step 2', () => (
+
+ ))
+
+ .add('Hardware wallet connect Trezor step 3', () => (
+
+ ))
+
+ .add('Hardware wallet connect Trezor step 4', () => (
+
+ ));
diff --git a/storybook/stories/wallets/index.js b/storybook/stories/wallets/index.js
index 423a152b49..2672425992 100644
--- a/storybook/stories/wallets/index.js
+++ b/storybook/stories/wallets/index.js
@@ -11,4 +11,5 @@ import './import/WalletImportFile.stories';
import './export/WalletExportToFile.stories';
import './transferFunds/TransferFunds.stories';
import './paperWallets/PaperWallets.stories';
+import './hardwareWallets/HardwareWallets.stories';
import './setPassword/SetWalletPassword.stories';