Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/import identity string #648

Merged
merged 10 commits into from
Nov 4, 2022
3 changes: 3 additions & 0 deletions source/Background/Keyring/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export const HANDLER_TYPES = {
GET_CURRENT_NETWORK: 'get-current-network',
IMPORT_PEM_ACCOUNT: 'import-pem-account',
REMOVE_PEM_ACCOUNT: 'remove-pem-account',
VALIDATE_PEM: 'validate-pem',
REMOVE_CUSTOM_TOKEN: 'remove-custom-token',
};

Expand Down Expand Up @@ -146,6 +147,7 @@ export const getKeyringErrorMessage = (type) => ({
[HANDLER_TYPES.REMOVE_CUSTOM_TOKEN]: 'removing custom token',
[HANDLER_TYPES.IMPORT_PEM_ACCOUNT]: 'importing account from pem',
[HANDLER_TYPES.REMOVE_PEM_ACCOUNT]: 'removing pem account',
[HANDLER_TYPES.VALIDATE_PEM]: 'validate pem',
}[type]);

export const sendMessage = (args, callback) => {
Expand Down Expand Up @@ -199,6 +201,7 @@ export const getKeyringHandler = (type, keyring) => ({
[HANDLER_TYPES.IMPORT_PEM_ACCOUNT]: async (params) => keyring.importAccountFromPem(params),
[HANDLER_TYPES.CREATE_PRINCIPAL]: async (params) => keyring.createPrincipal(params),
[HANDLER_TYPES.REMOVE_PEM_ACCOUNT]: async (params) => keyring.deleteImportedAccount(params),
[HANDLER_TYPES.VALIDATE_PEM]: async (params) => keyring.validatePem(params),
[HANDLER_TYPES.SET_CURRENT_PRINCIPAL]:
async (walletId) => {
await keyring.setCurrentPrincipal(walletId);
Expand Down
9 changes: 9 additions & 0 deletions source/assets/new-key.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions source/assets/paper.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions source/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -396,8 +396,12 @@
"dfxUse": "dfx identity use <identity name>",
"selectAccount": "Select Account"
},
"importWallet": {
"importWallet": "Import Wallet"
},
"importPem": {
"importPEMfile": "Import PEM file",
"description": "Import wallet through a PEM file",
"editWalletPic": "Edit Wallet Pic",
"walletDetails": "Wallet Details",
"dragAndDrop": "Drag and Drop",
Expand All @@ -406,6 +410,12 @@
"fileNotSupported": "File not supported. Try a different file.",
"dropIt": "Drop it!"
},
"importPrivateKey": {
"importPrivateKey": "Import Private Key",
"description": "Import wallet through a Private Key",
"privateKey": "Private Key",
"invalidString": "Invalid String. Please, try again."
},
"nfts": {
"allNfts": "All NFTs",
"expandNFT": "View",
Expand Down
4 changes: 4 additions & 0 deletions source/views/Extension/Popup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import ClockError from './Views/ClockError';
import Network from './Views/Network';
import NetworkCreation from './Views/NetworkCreation';
import ImportWallet from './Views/ImportWallet';
import ImportPemFile from './Views/ImportPemFile';
import ImportPrivateKey from './Views/ImportPrivateKey';

const Popup = ({ initialRoute }) => (
<Router initialRouteName={initialRoute}>
Expand All @@ -38,6 +40,8 @@ const Popup = ({ initialRoute }) => (
{/* <Route name="swap" component={Swap} /> */}
<Route name="clockError" component={ClockError} />
<Route name="import-wallet" component={ImportWallet} />
<Route name="import-pem-file" component={ImportPemFile} />
<Route name="import-private-key" component={ImportPrivateKey} />
<Route name="send" component={Send} />
<Route name="contacts" component={Contacts} />
<Route name="error" component={ErrorScreen} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ const useSteps = () => {
const steps = [
{
component: <Step1 handleChangeStep={handleChangeStep} setUserPemFile={setUserPemFile} userPemFile={userPemFile} />,
left: leftButton(() => handleClose()),
left: leftButton(() => navigator.navigate('import-wallet')),
right: rightButton,
center: `${t("importPem.importPEMfile")}`,
center: `${t("importWallet.importWallet")}`,
},
{
component: <Step2
handleClose={handleClose}
userPemFile={userPemFile}
/>,
right: rightButton,
center: `${t("importPem.walletDetails")}`,
center: `${t("importWallet.importWallet")}`,
},
];

Expand Down
21 changes: 21 additions & 0 deletions source/views/Extension/Views/ImportPemFile/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import { Layout, Header } from '@components';
import useSteps from './hooks/useSteps';

const ImportWallet = () => {
const {
component,
left,
right,
center,
} = useSteps();

return (
<Layout>
<Header left={left} center={center} right={right} />
{component}
</Layout>
);
};

export default ImportWallet;
76 changes: 76 additions & 0 deletions source/views/Extension/Views/ImportPrivateKey/Steps/Step1.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React, { useState, useCallback, useEffect } from "react";
import { useTranslation } from "react-i18next";
import useStyles from "../styles";
import { Typography, Grid } from "@material-ui/core";
import { Container, Button, TextInput, FormItem, UserIcon } from "@components";
import { HANDLER_TYPES, sendMessage } from "@background/Keyring";

const Step1 = ({ handleChangeStep, setPrivateKey, privateKey }) => {
const { t } = useTranslation();
const classes = useStyles();

const [loading, setLoading] = useState(false);
const [disabled, setDisabled] = useState(true);
const [invalidPem, setInvalidPem] = useState(null);

const handlePrivateKey = (e) => {
setLoading(true);
setPrivateKey(e.target.value);
sendMessage(
{
type: HANDLER_TYPES.VALIDATE_PEM,
params: {
pem: e.target.value
},
},
(a) => {
if (a) {
setDisabled(false);
setInvalidPem(false);
setLoading(false);
} else {
setInvalidPem(true);
setLoading(false);
setDisabled(true);
}
},
);
}

return (
<Container>
<Grid container spacing={2}>
<Grid item xs={12}>
<FormItem
label={`${t("importPrivateKey.privateKey")}`}
smallLabel
component={
<TextInput
fullWidth
value={privateKey}
onChange={(e) => handlePrivateKey(e)}
type="text"
data-testid="import-private-key-fill"
error={invalidPem}
/>
}
/>
{invalidPem && <Typography variant="body2" color="error">{`${t("importPrivateKey.invalidString")}`}</Typography>}
</Grid>
<Grid item xs={12}>
<Button
variant="rainbow"
value={t("common.continue")}
onClick={() => handleChangeStep(1)}
loading={loading}
disabled={disabled}
fullWidth
data-testid="add-button"
/>
</Grid>
</Grid>
</Container>
);
};

export default Step1;
118 changes: 118 additions & 0 deletions source/views/Extension/Views/ImportPrivateKey/Steps/Step2.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { Container, Button, TextInput, FormItem, UserIcon } from "@components";
import Grid from "@material-ui/core/Grid";
import useStyles from "../styles";
import React, { useState } from "react";
import { useRouter } from "@components/Router";
import { HANDLER_TYPES, sendMessage } from "@background/Keyring";
import Picker from "emoji-picker-react";
import { useEffect } from "react";
import { useTranslation } from "react-i18next";

const Step2 = ({ privateKey }) => {
const { t } = useTranslation();

const [loading, setLoading] = useState(false);
const [disabled, setDisabled] = useState(true);
const [openEmojis, setOpenEmojis] = useState(false);
const [walletName, setWalletName] = useState(""); // add deafault wallet name, for example the next wallet not used number
const [currentEmoji, setCurrentEmoji] = useState("😎"); // add default emoji, not used in other wallets
const [openEmojiSelector, setOpenEmojiSelector] = useState(false);

const { navigator } = useRouter();

const classes = useStyles();

useEffect(() => {
if (walletName && walletName !== "") {
setDisabled(false);
} else {
setDisabled(true);
}
}, [currentEmoji, walletName]);

const onEmojiClick = (_event, emojiObject) => {
setCurrentEmoji(emojiObject.emoji);
setOpenEmojis(false);
setOpenEmojiSelector(false);
};

const createImportedAccount = () => {
setLoading(true);
sendMessage(
{
type: HANDLER_TYPES.IMPORT_PEM_ACCOUNT,
params: { icon: currentEmoji, name: walletName, pem: privateKey },
},
() => {},
);
setLoading(false);
navigator.navigate("home");
};


return (
<Container>
<Grid container spacing={2}>
<Grid item xs={12}>
<div className={classes.chooseEmojiContainer}>
<UserIcon icon={currentEmoji} size="big" />
<Button
variant="primary"
value={t("importPem.editWalletPic")}
onClick={() => setOpenEmojiSelector(!openEmojiSelector)}
style={{
minWidth: 115,
height: 24,
borderRadius: 6,
}}
/>
{openEmojiSelector && (
<Picker
pickerStyle={{
height: 190,
width: "auto",
position: "absolute",
top: 180,
left: 40,
right: 40,
zIndex: 500,
}}
onEmojiClick={onEmojiClick}
native
disableSearchBar
groupVisibility={{
recently_used: false,
flags: false,
}}
/>
)}
</div>
<FormItem
smallLabel
label={t("common.name")}
className={classes.formItem}
component={
<TextInput
fullWidth
onChange={(e) => setWalletName(e.target.value.trim())}
type="text"
// error={}
/>
}
/>
<Button
variant="rainbow"
value={t("common.save")}
onClick={createImportedAccount}
loading={loading}
disabled={disabled}
fullWidth
data-testid="add-button"
/>
</Grid>
</Grid>
</Container>
);
};

export default Step2;
44 changes: 44 additions & 0 deletions source/views/Extension/Views/ImportPrivateKey/hooks/useSteps.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React, { useState } from 'react';
import { LinkButton } from '@components';
import { useTranslation } from 'react-i18next';
import { useRouter } from '@components/Router';
import BackIcon from '@assets/icons/back.svg';
import Step1 from '../Steps/Step1';
import Step2 from '../Steps/Step2';

const useSteps = () => {
const [step, setStep] = useState(0);
const { navigator } = useRouter();
const { t } = useTranslation();

const [privateKey, setPrivateKey] = useState(null);

const handleChangeStep = (index) => setStep(index);
const handleClose = () => navigator.navigate('home');

const leftButton = (onClick) => <LinkButton value={t('common.back')} onClick={onClick} startIcon={BackIcon} />;
const rightButton = <LinkButton value={t('common.close')} onClick={handleClose} />;



const steps = [
{
component: <Step1 handleChangeStep={handleChangeStep} setPrivateKey={setPrivateKey} privateKey={privateKey} />,
left: leftButton(() => navigator.navigate('import-wallet')),
right: rightButton,
center: `${t("importWallet.importWallet")}`,
},
{
component: <Step2
handleClose={handleClose}
privateKey={privateKey}
/>,
right: rightButton,
center: `${t("importWallet.importWallet")}`,
},
];

return steps[step];
};

export default useSteps;
21 changes: 21 additions & 0 deletions source/views/Extension/Views/ImportPrivateKey/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import { Layout, Header } from '@components';
import useSteps from './hooks/useSteps';

const ImportPrivateKey = () => {
const {
component,
left,
right,
center,
} = useSteps();

return (
<Layout>
<Header left={left} center={center} right={right} />
{component}
</Layout>
);
};

export default ImportPrivateKey;
Loading