diff --git a/.eslintrc.json b/.eslintrc.json
index 91bad378..4636c068 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -5,12 +5,14 @@
"jest/globals": true
},
"parser": "babel-eslint",
- "extends": ["airbnb"],
+ "extends": [
+ "airbnb",
+ "plugin:jsdoc/recommended"
+ ],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
-
"parserOptions": {
"ecmaFeatures": {
"jsx": true
@@ -18,7 +20,11 @@
"ecmaVersion": 2018,
"sourceType": "module"
},
- "plugins": ["react", "jest"],
+ "plugins": [
+ "react",
+ "jsdoc",
+ "jest"
+ ],
"rules": {
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"no-underscore-dangle":"off",
diff --git a/package-lock.json b/package-lock.json
index 5b262551..38aa348c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5120,6 +5120,12 @@
"graceful-readlink": ">= 1.0.0"
}
},
+ "comment-parser": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.7.0.tgz",
+ "integrity": "sha512-m0SGP0RFO4P3hIBlIor4sBFPe5Y4HUeGgo/UZK/1Zdea5eUiqxroQ3lFqBDDSfWo9z9Q6LLnt2u0JqwacVEd/A==",
+ "dev": true
+ },
"common-tags": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz",
@@ -7543,6 +7549,30 @@
}
}
},
+ "eslint-plugin-jsdoc": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-18.1.3.tgz",
+ "integrity": "sha512-QmdxsDzGG9eb20VD3V8hw4huehTnU6x1/we9tN56p8MOkJNEiHDFW59stcS2/sk+BSnsJy61qZ+6wCPya8B45w==",
+ "dev": true,
+ "requires": {
+ "comment-parser": "^0.7.0",
+ "debug": "^4.1.1",
+ "jsdoctypeparser": "^6.0.0",
+ "lodash": "^4.17.15",
+ "object.entries-ponyfill": "^1.0.1",
+ "regextras": "^0.6.1",
+ "semver": "^6.3.0",
+ "spdx-expression-parse": "^3.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
"eslint-plugin-jest": {
"version": "23.1.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-23.1.1.tgz",
@@ -11633,6 +11663,12 @@
}
}
},
+ "jsdoctypeparser": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-6.0.0.tgz",
+ "integrity": "sha512-61VtBXLkHfOFSIdp/VDVNMksxK0ID0cPTNvxDR92tPA6K7r2AX0OcJegYxhJIwtpWKU4p3D9L3U02hhlP1kQLQ==",
+ "dev": true
+ },
"jsdom": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz",
@@ -13519,6 +13555,12 @@
"has": "^1.0.3"
}
},
+ "object.entries-ponyfill": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object.entries-ponyfill/-/object.entries-ponyfill-1.0.1.tgz",
+ "integrity": "sha1-Kavfd8v70mVm3RqiTp2I9lQz0lY=",
+ "dev": true
+ },
"object.fromentries": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.1.tgz",
@@ -15949,6 +15991,12 @@
"unicode-match-property-value-ecmascript": "^1.1.0"
}
},
+ "regextras": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.6.1.tgz",
+ "integrity": "sha512-EzIHww9xV2Kpqx+corS/I7OBmf2rZ0pKKJPsw5Dc+l6Zq1TslDmtRIP9maVn3UH+72MIXmn8zzDgP07ihQogUA==",
+ "dev": true
+ },
"registry-auth-token": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.0.0.tgz",
diff --git a/package.json b/package.json
index cf708e48..76a3abc3 100644
--- a/package.json
+++ b/package.json
@@ -71,6 +71,7 @@
"eslint-config-airbnb": "^18.0.1",
"eslint-loader": "^3.0.2",
"eslint-plugin-import": "^2.18.2",
+ "eslint-plugin-jsdoc": "^18.1.3",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.16.0",
"eslint-plugin-react-hooks": "^1.7.0",
diff --git a/src/assets/styles/includes/_mixin.scss b/src/assets/styles/includes/_mixin.scss
new file mode 100644
index 00000000..0738f6c3
--- /dev/null
+++ b/src/assets/styles/includes/_mixin.scss
@@ -0,0 +1,10 @@
+@mixin title {
+ margin-top: 18px;
+ margin-bottom: 8px;
+ color: #000;
+ font-weight: 700;
+ font-size: 24px;
+ font-family: "Grotesk";
+ line-height: 28px;
+ text-align: center;
+}
\ No newline at end of file
diff --git a/src/components/Button/Button.js b/src/components/Button/Button.js
index 522fa169..198a67f6 100644
--- a/src/components/Button/Button.js
+++ b/src/components/Button/Button.js
@@ -42,7 +42,7 @@ Button.propTypes = {
iconPosition: propTypes.bool,
type: propTypes.string,
disabled: propTypes.bool,
- onClick: propTypes.func.isRequired,
+ onClick: propTypes.func,
theme: propTypes.string,
size: propTypes.string,
};
@@ -54,6 +54,7 @@ Button.defaultProps = {
icon: null,
iconPosition: false,
disabled: false,
+ onClick: () => {},
};
export default Button;
diff --git a/src/components/Decision/Decision.js b/src/components/Decision/Decision.js
new file mode 100644
index 00000000..13bed15e
--- /dev/null
+++ b/src/components/Decision/Decision.js
@@ -0,0 +1,49 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+import FinPassForm from '../../stores/FormsStore/FinPassForm';
+import FinPassFormWrapper from '../FinPassFormWrapper/FinPassFormWrapper';
+
+import styles from './Decision.scss';
+
+@withTranslation()
+class Decision extends React.Component {
+ form = new FinPassForm({
+ hooks: {
+ onSuccess() {
+ return Promise.resolve();
+ },
+ onError() {
+ /* eslint-disable-next-line */
+ console.error('error');
+ },
+ },
+ })
+
+ static propTypes = {
+ t: PropTypes.func.isRequired,
+ icon: PropTypes.node.isRequired,
+ title: PropTypes.string.isRequired,
+ };
+
+ render() {
+ const { props, form } = this;
+ const { t, icon, title } = props;
+ return (
+
+
+ {icon}
+
+
+ {title}
+
+
+ {t('other:enterPassForConfirm')}
+
+
+
+ );
+ }
+}
+
+export default Decision;
diff --git a/src/components/Decision/Decision.scss b/src/components/Decision/Decision.scss
new file mode 100644
index 00000000..427bb311
--- /dev/null
+++ b/src/components/Decision/Decision.scss
@@ -0,0 +1,25 @@
+@import '../../assets/styles/includes/mixin';
+
+.decision {
+ width: 100%;
+ text-align: center;
+
+ &__title {
+ @include title;
+ }
+
+ &__subtext {
+ color: rgba(0, 0, 0, 0.7);
+ font-size: 14px;
+ line-height: 16px;
+ text-align: center;
+ }
+
+ &__icon {
+ svg {
+ width: auto;
+ height: auto;
+ margin-top: 47px;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/components/Decision/Decision.test.js b/src/components/Decision/Decision.test.js
new file mode 100644
index 00000000..0b78456f
--- /dev/null
+++ b/src/components/Decision/Decision.test.js
@@ -0,0 +1,31 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import { DecisionReject, DecisionAgree } from '.';
+
+describe('DecisionReject', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = shallow(
+ ,
+ ).dive();
+ });
+
+ it('should render without error', () => {
+ expect(wrapper.length).toEqual(1);
+ });
+});
+
+describe('DecisionAgree', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = shallow(
+ ,
+ ).dive();
+ });
+
+ it('should render without error', () => {
+ expect(wrapper.length).toEqual(1);
+ });
+});
diff --git a/src/components/Decision/DecisionAgree.js b/src/components/Decision/DecisionAgree.js
new file mode 100644
index 00000000..984d0c83
--- /dev/null
+++ b/src/components/Decision/DecisionAgree.js
@@ -0,0 +1,25 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+import Decision from './Decision';
+import { VerifyIcon } from '../Icons';
+
+@withTranslation()
+class DecisionAgree extends React.Component {
+ static propTypes = {
+ t: PropTypes.func.isRequired,
+ };
+
+ render() {
+ const { props } = this;
+ const { t } = props;
+ return (
+ )}
+ />
+ );
+ }
+}
+
+export default DecisionAgree;
diff --git a/src/components/Decision/DecisionReject.js b/src/components/Decision/DecisionReject.js
new file mode 100644
index 00000000..b6e296ff
--- /dev/null
+++ b/src/components/Decision/DecisionReject.js
@@ -0,0 +1,25 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+import Decision from './Decision';
+import { RejectIcon } from '../Icons';
+
+@withTranslation()
+class DecisionReject extends React.Component {
+ static propTypes = {
+ t: PropTypes.func.isRequired,
+ };
+
+ render() {
+ const { props } = this;
+ const { t } = props;
+ return (
+ )}
+ />
+ );
+ }
+}
+
+export default DecisionReject;
diff --git a/src/components/Decision/index.js b/src/components/Decision/index.js
new file mode 100644
index 00000000..9077e969
--- /dev/null
+++ b/src/components/Decision/index.js
@@ -0,0 +1,11 @@
+import Decision from './Decision';
+import DecisionReject from './DecisionReject';
+import DecisionAgree from './DecisionAgree';
+
+export default Decision;
+
+export {
+ Decision,
+ DecisionReject,
+ DecisionAgree,
+};
diff --git a/src/components/Dialog/Dialog.scss b/src/components/Dialog/Dialog.scss
index 80c3a289..27d6f623 100644
--- a/src/components/Dialog/Dialog.scss
+++ b/src/components/Dialog/Dialog.scss
@@ -13,7 +13,7 @@
&__inner {
position: relative;
z-index: 1;
- min-height: 325px;
+ min-height: 309px;
}
}
diff --git a/src/components/Dialog/index.js b/src/components/Dialog/index.js
index 16772f4f..4a07e93e 100644
--- a/src/components/Dialog/index.js
+++ b/src/components/Dialog/index.js
@@ -1,3 +1,8 @@
import Dialog from './Dialog';
+import DefaultDialogFooter from './DefaultDialogFooter';
export default { Dialog };
+
+export {
+ DefaultDialogFooter,
+};
diff --git a/src/components/FinPassFormWrapper/FinPassFormWrapper.js b/src/components/FinPassFormWrapper/FinPassFormWrapper.js
new file mode 100644
index 00000000..924f35f4
--- /dev/null
+++ b/src/components/FinPassFormWrapper/FinPassFormWrapper.js
@@ -0,0 +1,49 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+import Input from '../Input';
+import { Password } from '../Icons';
+import Button from '../Button/Button';
+
+import styles from './FinPassFormWrapper.scss';
+
+@withTranslation()
+class FinPassFormWrapper extends React.Component {
+ static propTypes = {
+ t: PropTypes.func.isRequired,
+ form: PropTypes.shape({
+ onSubmit: PropTypes.func.isRequired,
+ $: PropTypes.func.isRequired,
+ }).isRequired,
+ };
+
+ render() {
+ const { props } = this;
+ const { t, form } = props;
+ return (
+
+ );
+ }
+}
+
+export default FinPassFormWrapper;
diff --git a/src/components/FinPassFormWrapper/FinPassFormWrapper.scss b/src/components/FinPassFormWrapper/FinPassFormWrapper.scss
new file mode 100644
index 00000000..9e1ed67d
--- /dev/null
+++ b/src/components/FinPassFormWrapper/FinPassFormWrapper.scss
@@ -0,0 +1,21 @@
+.form-fin-pass {
+ margin-top: 56px;
+
+ .input__wrapper {
+ .field {
+ width: 100%;
+ max-width: 309px;
+ margin-bottom: 0px;
+ }
+ }
+
+ .button__wrapper {
+ margin-top: 48px;
+ margin-bottom: 59px;
+
+ button {
+ width: 100%;
+ max-width: 309px;
+ }
+ }
+}
diff --git a/src/components/FinPassFormWrapper/FinPassFormWrapper.stories.js b/src/components/FinPassFormWrapper/FinPassFormWrapper.stories.js
new file mode 100644
index 00000000..6df33427
--- /dev/null
+++ b/src/components/FinPassFormWrapper/FinPassFormWrapper.stories.js
@@ -0,0 +1,24 @@
+import React from 'react';
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { storiesOf } from '@storybook/react';
+import FinPassFormWrapper from './FinPassFormWrapper';
+import FinPassForm from '../../stores/FormsStore/FinPassForm';
+
+const form = new FinPassForm({
+ hooks: {
+ onSuccess() {
+ return Promise.resolve();
+ },
+ onError() {
+ /* eslint-disable-next-line */
+ console.error('error');
+ },
+ },
+});
+
+storiesOf('FinPassFormWrapper', module)
+ .add('Default', () => (
+
+ ));
diff --git a/src/components/Input/index.js b/src/components/Input/index.js
index d073daff..42e5c040 100644
--- a/src/components/Input/index.js
+++ b/src/components/Input/index.js
@@ -40,7 +40,7 @@ Input.propTypes = {
children: propTypes.element.isRequired,
className: propTypes.string,
field: propTypes.shape({
- error: propTypes.string.isRequired,
+ error: propTypes.string,
value: propTypes.string.isRequired,
placeholder: propTypes.string.isRequired,
bind: propTypes.func.isRequired,
diff --git a/src/components/Message/Message.scss b/src/components/Message/Message.scss
index e74b429a..1bf06d8a 100644
--- a/src/components/Message/Message.scss
+++ b/src/components/Message/Message.scss
@@ -58,6 +58,26 @@
}
}
+ &--transfer-error {
+ .subtext {
+ color: rgba(0, 0, 0, 0.7);
+ font-size: 14px;
+ line-height: 16px;
+ }
+
+ .message {
+ &__title {
+ margin-top: 57px;
+ margin-bottom: 24px;
+ }
+ }
+
+ .footer {
+ padding-top: 73px;
+ padding-bottom: 51px;
+ }
+ }
+
&--progress {
.message {
&__title {
@@ -78,4 +98,14 @@
text-align: center;
}
}
+
+ &--agreed,
+ &--reject,
+ &--transfer-success,
+ &--transfer-error {
+ button {
+ width: 100%;
+ max-width: 309px;
+ }
+ }
}
diff --git a/src/components/Message/TransferSuccessMessage.js b/src/components/Message/TransferSuccessMessage.js
index 936a2b1f..3efcf783 100644
--- a/src/components/Message/TransferSuccessMessage.js
+++ b/src/components/Message/TransferSuccessMessage.js
@@ -6,6 +6,7 @@ import DefaultMessage from './DefaultMessage';
import Button from '../Button/Button';
import styles from './Message.scss';
+
/**
* Dialog with message about success token transfer
*/
diff --git a/src/components/Message/index.js b/src/components/Message/index.js
index 4e724aae..c506a408 100644
--- a/src/components/Message/index.js
+++ b/src/components/Message/index.js
@@ -3,6 +3,7 @@ import AgreedMessage from './AgreedMessage';
import RejectMessage from './RejectMessage';
import TransferSuccessMessage from './TransferSuccessMessage';
import TokenInProgressMessage from './TokenInProgressMessage';
+import TransferErrorMessage from './TransferErrorMessage';
export default DefaultMessage;
@@ -11,4 +12,5 @@ export {
RejectMessage,
TransferSuccessMessage,
TokenInProgressMessage,
+ TransferErrorMessage,
};
diff --git a/src/components/Messages/TransferErrorMessage.js b/src/components/Messages/TransferErrorMessage.js
new file mode 100644
index 00000000..d8e00751
--- /dev/null
+++ b/src/components/Messages/TransferErrorMessage.js
@@ -0,0 +1,40 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+import DefaultMessage from './DefaultMessage';
+import Button from '../Button/Button';
+
+import styles from './Message.scss';
+
+/**
+ * Dialog with message about success token transfer
+ */
+@withTranslation(['dialogs', 'other'])
+class TransferErrorMessage extends React.Component {
+ static propTypes = {
+ t: PropTypes.func.isRequired,
+ onButtonClick: PropTypes.func.isRequired,
+ }
+
+ render() {
+ const { props: { t, onButtonClick } } = this;
+ return (
+
+
+ {t('other:notEnoughTokens')}
+
+
+
+
+
+ );
+ }
+}
+
+export default TransferErrorMessage;
diff --git a/src/components/Messages/TransferErrorMessage.test.js b/src/components/Messages/TransferErrorMessage.test.js
new file mode 100644
index 00000000..3dd15293
--- /dev/null
+++ b/src/components/Messages/TransferErrorMessage.test.js
@@ -0,0 +1,29 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import TransferErrorMessage from './TransferErrorMessage';
+import Button from '../Button/Button';
+
+describe('TransferErrorMessage', () => {
+ let wrapper;
+ let mockOnClick;
+
+ beforeEach(() => {
+ mockOnClick = jest.fn();
+ wrapper = shallow(
+ ,
+ ).dive();
+ });
+
+ it('should render without error', () => {
+ expect(wrapper.length).toEqual(1);
+ });
+
+ it('should call mockOnClick on button onClick', () => {
+ const button = wrapper.find(Button);
+ expect(button.length).toEqual(1);
+ button.prop('onClick')();
+ expect(mockOnClick).toHaveBeenCalled();
+ });
+});
diff --git a/src/components/TokenTransfer/TokenTransfer.js b/src/components/TokenTransfer/TokenTransfer.js
new file mode 100644
index 00000000..c0e2ba57
--- /dev/null
+++ b/src/components/TokenTransfer/TokenTransfer.js
@@ -0,0 +1,94 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+import TransferTokenForm from '../../stores/FormsStore/TransferTokenForm';
+import Input from '../Input';
+import { Password, Address, TokenCount } from '../Icons';
+import Button from '../Button/Button';
+import { EMPTY_DATA_STRING } from '../../constants';
+
+import styles from './TokenTransfer.scss';
+
+/**
+ * Component form for transfer token
+ */
+@withTranslation()
+class TokenTransfer extends React.Component {
+ form = new TransferTokenForm({
+ hooks: {
+ onSuccess(form) {
+ return Promise.resolve(form);
+ },
+ onError() {
+ /* eslint-disable-next-line */
+ console.error('form error');
+ },
+ },
+ })
+
+ static propTypes = {
+ t: PropTypes.func.isRequired,
+ wallet: PropTypes.string,
+ }
+
+ static defaultProps = {
+ wallet: EMPTY_DATA_STRING,
+ }
+
+ handleClick = () => {
+ /* eslint-disable-next-line */
+ console.log('click');
+ }
+
+ render() {
+ const { form } = this;
+ const { props } = this;
+ const { t, wallet } = props;
+ return (
+
+
+ {t('dialogs:tokenTransfer')}
+
+
+
+
+
+
+ );
+ }
+}
+
+export default TokenTransfer;
diff --git a/src/components/TokenTransfer/TokenTransfer.scss b/src/components/TokenTransfer/TokenTransfer.scss
new file mode 100644
index 00000000..f0941416
--- /dev/null
+++ b/src/components/TokenTransfer/TokenTransfer.scss
@@ -0,0 +1,55 @@
+@import '../../assets/styles/includes/mixin';
+
+.token-transfer {
+ text-align: center;
+
+ .input__wrapper {
+ margin-bottom: 32px;
+
+ .field {
+ width: 100%;
+ max-width: 309px;
+ }
+ }
+
+ .button__wrapper {
+ margin-top: 48px;
+ margin-bottom: 16px;
+
+ .btn {
+ width: 100%;
+ max-width: 298px;
+ }
+ }
+
+ .wallet__wrapper {
+ margin-top: 16px;
+ margin-bottom: 24px;
+ color: #808080;
+ font-size: 14px;
+ line-height: 16px;
+ }
+
+ &__title {
+ @include title;
+
+ margin-top: 72px;
+ margin-bottom: 73px;
+ }
+
+ &__button {
+ // compensate padding in dialog
+ width: calc(100% + 80px);
+ margin: 0px -40px -10px -40px;
+ padding: 15px 20px;
+ color: #c8c9ca;
+ font-size: 14px;
+ line-height: 16px;
+ text-decoration: underline;
+ background-color: transparent;
+ border: unset;
+ border-top: 1px solid #e1e4e8;
+ outline: none;
+ cursor: pointer;
+ }
+}
\ No newline at end of file
diff --git a/src/components/TokenTransfer/TokenTransfer.stories.js b/src/components/TokenTransfer/TokenTransfer.stories.js
new file mode 100644
index 00000000..4de57cb9
--- /dev/null
+++ b/src/components/TokenTransfer/TokenTransfer.stories.js
@@ -0,0 +1,12 @@
+import React from 'react';
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { storiesOf } from '@storybook/react';
+import TokenTransfer from './TokenTransfer';
+
+storiesOf('TokenTransfer', module)
+ .add('Without wallet', () => (
+
+ ))
+ .add('With wallet', () => (
+
+ ));
diff --git a/src/components/TokenTransfer/TokenTransfer.test.js b/src/components/TokenTransfer/TokenTransfer.test.js
new file mode 100644
index 00000000..62a9d0f9
--- /dev/null
+++ b/src/components/TokenTransfer/TokenTransfer.test.js
@@ -0,0 +1,22 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import TokenTransfer from './TokenTransfer';
+
+jest.mock('../../utils/Validator');
+
+describe('TokenTransfer', () => {
+ it('should render correct without "wallet" prop', () => {
+ const wrapper = shallow().dive();
+ expect(wrapper.length).toEqual(1);
+ });
+
+ it('should render correct with props', () => {
+ const wrapper = shallow(
+ ,
+ ).dive();
+ expect(wrapper.length).toEqual(1);
+ expect(wrapper.find('.wallet__wrapper').text()).toEqual('0xD490af05Bf82eF6C6BA034B22D18c39B5D52Cc54');
+ });
+});
diff --git a/src/components/TokenTransfer/index.js b/src/components/TokenTransfer/index.js
new file mode 100644
index 00000000..2bd64e07
--- /dev/null
+++ b/src/components/TokenTransfer/index.js
@@ -0,0 +1,3 @@
+import TokenTransfer from './TokenTransfer';
+
+export default { TokenTransfer };
diff --git a/src/locales/ENG/buttons.js b/src/locales/ENG/buttons.js
index 7303b775..ed308fa5 100644
--- a/src/locales/ENG/buttons.js
+++ b/src/locales/ENG/buttons.js
@@ -17,5 +17,8 @@ const buttons = {
withTokens: 'Connect contract and create project',
withoutTokens: 'Create new contract and project',
toWallets: 'To wallets',
+ transfer: 'Transfer',
+ designateGroupAdministrator: 'designate group administrator',
+ vote: 'Vote',
};
export default buttons;
diff --git a/src/locales/ENG/dialogs.js b/src/locales/ENG/dialogs.js
index bd2146a9..c107f4dc 100644
--- a/src/locales/ENG/dialogs.js
+++ b/src/locales/ENG/dialogs.js
@@ -1,10 +1,13 @@
const dialog = {
definetelyAgree: 'Do you definitely agree?',
+ definetelyReject: 'Do you definitely reject?',
agreedMessage: 'You agreed',
rejectMessage: 'You voted against',
transferInProgress: 'Token transfer in progress',
someTimeText: 'It will take some time',
tokenTransferSuccess: 'Tokens successfully transferred!',
+ tokenTransfer: 'Transfer token',
+ tokenTransferError: 'Transfer error',
};
export default dialog;
diff --git a/src/locales/ENG/fields.js b/src/locales/ENG/fields.js
index 80666846..d030d9f1 100644
--- a/src/locales/ENG/fields.js
+++ b/src/locales/ENG/fields.js
@@ -8,6 +8,8 @@ const placeholders = {
quantity: 'Quantity',
projectTitle: 'Project title',
contractAddress: 'Enter contract address',
+ address: 'Address',
+ countTokens: 'Count tokens',
};
export default placeholders;
diff --git a/src/locales/ENG/other.js b/src/locales/ENG/other.js
index 8395020a..3d883139 100644
--- a/src/locales/ENG/other.js
+++ b/src/locales/ENG/other.js
@@ -14,6 +14,8 @@ const other = {
withTokens: 'If you have ERC20 tokens',
withoutTokens: "If you don't have ERC20 tokens",
yourBalance: 'Your balance',
+ notEnoughTokens: 'Perhaps there are not enough tokens',
+ enterPassForConfirm: 'Enter your password to confirm your decision.',
RUS: 'Русский',
ENG: 'English',
};
diff --git a/src/locales/RUS/buttons.js b/src/locales/RUS/buttons.js
index 0dba007a..384e5444 100644
--- a/src/locales/RUS/buttons.js
+++ b/src/locales/RUS/buttons.js
@@ -17,5 +17,8 @@ const buttons = {
withTokens: 'Подключить контракт и создать проект',
withoutTokens: 'Создать новые токены и проект',
toWallets: 'К выбору кошелька',
+ transfer: 'Перевести',
+ designateGroupAdministrator: 'назначить администратором группы',
+ vote: 'Голосовать',
};
export default buttons;
diff --git a/src/locales/RUS/dialogs.js b/src/locales/RUS/dialogs.js
index 4a7ff65b..f6bec45c 100644
--- a/src/locales/RUS/dialogs.js
+++ b/src/locales/RUS/dialogs.js
@@ -1,10 +1,13 @@
const dialog = {
definetelyAgree: 'Вы точно согласны?',
+ definetelyReject: 'Вы точно против?',
agreedMessage: 'Вы выразили согласие',
rejectMessage: 'Вы проголосовали против',
transferInProgress: 'Переводим токены',
someTimeText: 'Это займет некоторое время',
tokenTransferSuccess: 'Токены успешно переведены!',
+ tokenTransfer: 'Перевести токены',
+ tokenTransferError: 'Ошибка перевода',
};
export default dialog;
diff --git a/src/locales/RUS/fields.js b/src/locales/RUS/fields.js
index 81c14fb6..108f60ed 100644
--- a/src/locales/RUS/fields.js
+++ b/src/locales/RUS/fields.js
@@ -8,6 +8,8 @@ const placeholders = {
quantity: 'Количество',
projectTitle: 'Придумайте название проекта',
contractAddress: 'Введите адрес контракта',
+ address: 'Адрес кошелька',
+ countTokens: 'Количество токенов',
};
export default placeholders;
diff --git a/src/locales/RUS/other.js b/src/locales/RUS/other.js
index 6234e3ae..f35cf2ca 100644
--- a/src/locales/RUS/other.js
+++ b/src/locales/RUS/other.js
@@ -14,6 +14,8 @@ const other = {
withTokens: 'Если есть токены ERC20',
withoutTokens: 'Если токенов ERC20 нет',
yourBalance: 'Ваш баланс',
+ notEnoughTokens: 'Возможно не хватает токенов',
+ enterPassForConfirm: 'Введите пароль, чтобы подтвердить свое решеине',
RUS: 'Русский',
ENG: 'English',
};
diff --git a/src/stores/DialogStore/DialogStore.js b/src/stores/DialogStore/DialogStore.js
index 73bf9304..404fba34 100644
--- a/src/stores/DialogStore/DialogStore.js
+++ b/src/stores/DialogStore/DialogStore.js
@@ -28,7 +28,7 @@ class DialogStore {
/**
* Actual open state
*
- * @returns {string, boolean} name dialog or boolean state
+ * @returns {string|boolean} name dialog or boolean state
*/
get isOpen() {
if (this.open && this.dialog) return this.dialog;
@@ -39,7 +39,7 @@ class DialogStore {
* Method for getting dialog by name in list
*
* @param {string} dialogName name dialog
- * @return {object} dialog item model
+ * @returns {object} dialog item model
*/
getDialog(dialogName) {
const { list } = this;
@@ -144,6 +144,7 @@ class DialogStore {
* Method for adding dialog in history dialogs
*
* @param {object} dialog dialog item model
+ * @returns {number} length history
*/
addToHistory(dialog) {
if (dialog.history === false) return false;
diff --git a/src/stores/FormsStore/FinPassForm.js b/src/stores/FormsStore/FinPassForm.js
index ec5ff96a..1cd7689e 100644
--- a/src/stores/FormsStore/FinPassForm.js
+++ b/src/stores/FormsStore/FinPassForm.js
@@ -6,10 +6,10 @@ class FinPassForm extends ExtendedForm {
setup() {
return {
fields: [{
- name: 'password',
+ name: 'fin-password',
type: 'password',
label: 'Password',
- placeholder: i18n.t('fields:enterPassword'),
+ placeholder: i18n.t('fields:password'),
rules: 'required|password',
}],
};
diff --git a/src/stores/FormsStore/TransferTokenForm.js b/src/stores/FormsStore/TransferTokenForm.js
new file mode 100644
index 00000000..87622d79
--- /dev/null
+++ b/src/stores/FormsStore/TransferTokenForm.js
@@ -0,0 +1,35 @@
+/* eslint-disable class-methods-use-this */
+import i18n from 'i18next';
+import ExtendedForm from '../../models/FormModel';
+
+class TransferTokenForm extends ExtendedForm {
+ setup() {
+ return {
+ fields: [
+ {
+ name: 'address',
+ type: 'text',
+ label: 'Address',
+ placeholder: i18n.t('fields:address'),
+ rules: 'required|string',
+ },
+ {
+ name: 'count',
+ type: 'text',
+ label: 'Count tokens',
+ placeholder: i18n.t('fields:countTokens'),
+ rules: 'required|numeric|min:1|max:2147483647 ',
+ },
+ {
+ name: 'password',
+ type: 'password',
+ label: 'Password',
+ placeholder: i18n.t('fields:password'),
+ rules: 'required|password',
+ },
+ ],
+ };
+ }
+}
+
+export default TransferTokenForm;
diff --git a/src/stores/RootStore/RootStore.js b/src/stores/RootStore/RootStore.js
index b564760c..177a6808 100644
--- a/src/stores/RootStore/RootStore.js
+++ b/src/stores/RootStore/RootStore.js
@@ -42,6 +42,7 @@ class RootStore {
/**
* initiating project
+ *
* @param {string} address adress of project
*/
@action initProject(address) {
diff --git a/webpack.dev.js b/webpack.dev.js
index 616ae052..90ada679 100644
--- a/webpack.dev.js
+++ b/webpack.dev.js
@@ -40,7 +40,7 @@ module.exports = {
loader: 'eslint-loader',
options: {
failOnError: true,
- failOnWarning: true,
+ failOnWarning: false,
},
}],
}, {