PathDetails.tsx 5.93 KB
Newer Older
1
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
Hanwen Cheng's avatar
Hanwen Cheng committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

17
import { StackNavigationProp } from '@react-navigation/stack';
Hanwen Cheng's avatar
Hanwen Cheng committed
18
import React from 'react';
19
import { ScrollView, StyleSheet, View } from 'react-native';
20

21
import { SafeAreaViewContainer } from 'components/SafeAreaContainer';
22
23
import { defaultNetworkKey, UnknownNetworkKeys } from 'constants/networkSpecs';
import testIDs from 'e2e/testIDs';
24
// TODO use typescript 3.8's type import, Wait for prettier update.
25
26
import { AccountsStoreStateWithIdentity } from 'types/identityTypes';
import { NavigationAccountIdentityProps } from 'types/props';
27
import { RootStackParamList } from 'types/routes';
28
import { withAccountStore, withCurrentIdentity } from 'utils/HOC';
29
30
31
32
33
import PathCard from 'components/PathCard';
import PopupMenu from 'components/PopupMenu';
import { LeftScreenHeading } from 'components/ScreenHeading';
import colors from 'styles/colors';
import QrView from 'components/QrView';
Hanwen Cheng's avatar
Hanwen Cheng committed
34
import {
35
	getAddressWithPath,
36
	getNetworkKey,
37
	getPathName,
38
	getPathsWithSubstrateNetworkKey,
39
	isSubstrateHardDerivedPath,
Hanwen Cheng's avatar
Hanwen Cheng committed
40
	isSubstratePath
41
42
} from 'utils/identitiesUtils';
import { alertDeleteAccount, alertPathDeletionError } from 'utils/alertUtils';
43
44
import {
	navigateToPathDerivation,
45
46
	navigateToPathsList,
	useUnlockSeed
47
} from 'utils/navigationHelpers';
48
import { generateAccountId } from 'utils/account';
49
import { UnknownAccountWarning } from 'components/Warnings';
50
import { useSeedRef } from 'utils/seedRefHooks';
51
import QrScannerTab from 'components/QrScannerTab';
Hanwen Cheng's avatar
Hanwen Cheng committed
52

53
interface Props {
54
55
	path: string;
	networkKey: string;
56
57
58
	navigation:
		| StackNavigationProp<RootStackParamList, 'PathDetails'>
		| StackNavigationProp<RootStackParamList, 'PathsList'>;
59
	accounts: AccountsStoreStateWithIdentity;
60
61
62
63
64
65
66
67
}

export function PathDetailsView({
	accounts,
	navigation,
	path,
	networkKey
}: Props): React.ReactElement {
Hanwen Cheng's avatar
Hanwen Cheng committed
68
	const { currentIdentity } = accounts.state;
69
70
	const address = getAddressWithPath(path, currentIdentity);
	const accountName = getPathName(path, currentIdentity);
71
	const { isSeedRefValid } = useSeedRef(currentIdentity.encryptedSeed);
72
	const { unlockWithoutPassword, unlockWithPassword } = useUnlockSeed();
73
	if (!address) return <View />;
74
75
	const isUnknownNetwork = networkKey === UnknownNetworkKeys.UNKNOWN;
	const formattedNetworkKey = isUnknownNetwork ? defaultNetworkKey : networkKey;
76
77
	const accountId = generateAccountId({
		address,
78
		networkKey: formattedNetworkKey
79
	});
Hanwen Cheng's avatar
Hanwen Cheng committed
80

81
	const onOptionSelect = async (value: string): Promise<void> => {
82
83
84
		switch (value) {
			case 'PathDelete':
				alertDeleteAccount('this account', async () => {
85
86
					try {
						await accounts.deletePath(path);
87
88
						if (isSubstratePath(path)) {
							const listedPaths = getPathsWithSubstrateNetworkKey(
89
								accounts.state.currentIdentity,
90
								networkKey
91
92
93
							);
							const hasOtherPaths = listedPaths.length > 0;
							hasOtherPaths
94
								? navigateToPathsList(navigation, networkKey)
95
								: navigation.navigate('Main');
96
						} else {
97
							navigation.navigate('Main');
98
						}
99
100
					} catch (err) {
						alertPathDeletionError(err);
101
102
103
					}
				});
				break;
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
			case 'PathSecret': {
				const pathMeta = currentIdentity.meta.get(path)!;
				if (pathMeta.hasPassword) {
					await unlockWithPassword(
						password => ({
							name: 'PathSecret',
							params: {
								password,
								path
							}
						}),
						isSeedRefValid
					);
				} else {
					await unlockWithoutPassword(
						{ name: 'PathSecret', params: { path } },
						isSeedRefValid
					);
				}
				break;
			}
125
			case 'PathDerivation':
126
				navigateToPathDerivation(navigation, path, isSeedRefValid);
127
128
129
130
				break;
			case 'PathManagement':
				navigation.navigate('PathManagement', { path });
				break;
Hanwen Cheng's avatar
Hanwen Cheng committed
131
132
133
134
		}
	};

	return (
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
		<SafeAreaViewContainer>
			<ScrollView testID={testIDs.PathDetail.screen} bounces={false}>
				<LeftScreenHeading
					title="Public Address"
					networkKey={formattedNetworkKey}
					headMenu={
						<PopupMenu
							testID={testIDs.PathDetail.popupMenuButton}
							onSelect={onOptionSelect}
							menuTriggerIconName={'more-vert'}
							menuItems={[
								{ text: 'Edit', value: 'PathManagement' },
								{
									hide: !isSubstratePath(path),
									text: 'Derive Account',
									value: 'PathDerivation'
								},
152
153
154
155
156
157
								{
									hide: !isSubstrateHardDerivedPath(path),
									testID: testIDs.PathDetail.exportButton,
									text: 'Export Account',
									value: 'PathSecret'
								},
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
								{
									testID: testIDs.PathDetail.deleteButton,
									text: 'Delete',
									textStyle: styles.deleteText,
									value: 'PathDelete'
								}
							]}
						/>
					}
				/>
				<PathCard identity={currentIdentity} path={path} />
				<QrView data={`${accountId}:${accountName}`} />
				{isUnknownNetwork && <UnknownAccountWarning isPath />}
			</ScrollView>
			<QrScannerTab />
		</SafeAreaViewContainer>
Hanwen Cheng's avatar
Hanwen Cheng committed
174
175
176
	);
}

177
178
function PathDetails({
	accounts,
179
180
	navigation,
	route
181
}: NavigationAccountIdentityProps<'PathDetails'>): React.ReactElement {
182
	const path = route.params.path;
183
	const networkKey = getNetworkKey(path, accounts.state.currentIdentity);
Hanwen Cheng's avatar
Hanwen Cheng committed
184
185
186
187
188
189
190
191
192
193
194
195
	return (
		<PathDetailsView
			accounts={accounts}
			navigation={navigation}
			path={path}
			networkKey={networkKey}
		/>
	);
}

const styles = StyleSheet.create({
	deleteText: {
196
		color: colors.signal.error
Hanwen Cheng's avatar
Hanwen Cheng committed
197
198
199
	}
});

200
export default withAccountStore(withCurrentIdentity(PathDetails));