diff --git a/src/actions/OptionsActions.js b/src/actions/OptionsActions.js
index df1e03b..583c669 100644
--- a/src/actions/OptionsActions.js
+++ b/src/actions/OptionsActions.js
@@ -13,12 +13,23 @@ class OptionsActions {
'activateShortLoginFailure',
'deactivateShortLoginSuccess',
'deactivateShortLoginFailure',
+ 'showImportKeepass',
+ 'hideImportKeepass',
+ 'showChangePassword',
+ 'hideChangePassword',
+ 'importKeepassProgress',
+ 'importKeepassSuccess',
+ 'importKeepassFailure',
'hideQRCode',
'hideShortLogin',
'changeDelaySuccess',
'changeDelayFailure',
'showRescueCodesSuccess',
- 'hideRescueCodes'
+ 'hideRescueCodes',
+ 'changeNewPass1',
+ 'changeNewPass2',
+ 'changePasswordSuccess',
+ 'changePasswordFailure'
);
}
@@ -87,6 +98,20 @@ class OptionsActions {
};
}
+ changePassword({ newPass }) {
+ return dispatch => {
+ dispatch();
+ secretin
+ .changePassword(newPass)
+ .then(() => {
+ this.changePasswordSuccess();
+ })
+ .catch(() => {
+ this.changePasswordFailure();
+ });
+ };
+ }
+
toggleTotp({ checked }) {
if (checked) {
return true;
diff --git a/src/components/options/ChangePasswordShow.js b/src/components/options/ChangePasswordShow.js
new file mode 100644
index 0000000..701785a
--- /dev/null
+++ b/src/components/options/ChangePasswordShow.js
@@ -0,0 +1,138 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import connectToStores from 'alt-utils/lib/connectToStores';
+
+import Modal from 'components/utilities/Modal';
+import Button from 'components/utilities/Button';
+import Input from 'components/utilities/Input';
+
+import OptionsStore from 'stores/OptionsStore';
+import OptionsActions from 'actions/OptionsActions';
+
+class ChangePasswordShow extends Component {
+ static propTypes = {
+ shown: PropTypes.bool,
+ loading: PropTypes.bool,
+ error: PropTypes.string,
+ newPass1: PropTypes.string,
+ newPass2: PropTypes.string,
+ };
+
+ static defaultProps = {
+ shown: false,
+ loading: false,
+ newPass1: '',
+ newPass2: '',
+ error: '',
+ };
+
+ static getStores() {
+ return [OptionsStore];
+ }
+
+ static getPropsFromStores() {
+ const state = OptionsStore.getNewPass();
+
+ return {
+ errors: state.get('error'),
+ shown: state.get('shown'),
+ loading: state.get('loading'),
+ newPass1: state.get('newPass1'),
+ newPass2: state.get('newPass2'),
+ };
+ }
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ success: false,
+ };
+ this.handleChangePassword = this.handleChangePassword.bind(this);
+ }
+
+ handleChangePassword() {
+ OptionsActions.changePassword({
+ newPass: this.props.newPass1,
+ });
+ }
+
+ componentWillReceiveProps(nextProps) {
+ if (this.props.loading && !nextProps.loading && nextProps.error === '') {
+ this.setState({
+ success: true,
+ });
+ } else {
+ this.setState({
+ success: false,
+ });
+ }
+ }
+
+ render() {
+ return (
+
+
+ Change master password
+
+
+ {!this.state.success
+ ?
+
+ {this.props.newPass1.length > 0 &&
+
+
+ }
+
+ {this.props.error === '' &&
+ this.props.newPass1.length > 0 &&
+ this.props.newPass1 !== this.props.newPass2 &&
+ 'Passwords mismatch'}
+ {this.props.error !== '' && this.props.error}
+
+
+ :
+ Success
+ }
+
+
+
+ {this.props.newPass1.length > 0 &&
+ }
+
+
+ );
+ }
+}
+
+export default connectToStores(ChangePasswordShow);
diff --git a/src/components/options/OptionsContainer.js b/src/components/options/OptionsContainer.js
index 3c7c5fe..ff93fed 100644
--- a/src/components/options/OptionsContainer.js
+++ b/src/components/options/OptionsContainer.js
@@ -7,6 +7,7 @@ import AppUIStore from 'stores/AppUIStore';
import ShortLoginShow from 'components/options/ShortLoginShow';
import QRCodeShow from 'components/options/QRCodeShow';
import RescueCodesShow from 'components/options/RescueCodesShow';
+import ChangePasswordShow from 'components/options/ChangePasswordShow';
import Title from 'components/utilities/Title';
import Checkbox from 'components/utilities/Checkbox';
import Input from 'components/utilities/Input';
@@ -19,6 +20,7 @@ import OptionsStore from 'stores/OptionsStore';
class OptionsContainer extends Component {
static propTypes = {
options: PropTypes.instanceOf(Immutable.Map),
+ newPass: PropTypes.instanceOf(Immutable.Map),
};
static getStores() {
@@ -39,7 +41,6 @@ class OptionsContainer extends Component {
render() {
const { options } = this.props;
-
return (
@@ -117,8 +118,17 @@ class OptionsContainer extends Component {
-
Password generation
-
SOON BY @dqms
+
+
+
+
diff --git a/src/components/utilities/Button.js b/src/components/utilities/Button.js
index ab5b3e0..c0be20a 100644
--- a/src/components/utilities/Button.js
+++ b/src/components/utilities/Button.js
@@ -11,7 +11,13 @@ class Button extends Component {
form: PropTypes.string,
disabled: PropTypes.bool,
size: PropTypes.string,
- buttonStyle: PropTypes.oneOf(['default', 'primary', 'icon']),
+ buttonStyle: PropTypes.oneOf([
+ 'default',
+ 'primary',
+ 'icon',
+ 'success',
+ 'warning',
+ ]),
to: PropTypes.string,
onClick: PropTypes.func,
children: PropTypes.oneOfType([
diff --git a/src/stores/OptionsStore.js b/src/stores/OptionsStore.js
index f17a921..f2fc458 100644
--- a/src/stores/OptionsStore.js
+++ b/src/stores/OptionsStore.js
@@ -11,6 +11,13 @@ const OptionsState = new Record({
showQRCode: false,
showShortLogin: false,
showRescueCodes: false,
+ newPass: new Immutable.Map({
+ shown: false,
+ newPass1: '',
+ newPass2: '',
+ error: '',
+ loading: false,
+ }),
rescueCodes: new Immutable.List(),
loading: false,
});
@@ -108,6 +115,62 @@ class OptionsStore {
this.setState(this.state.setIn(['options', 'timeToClose'], timeToClose));
}
+ onChangeNewPass1(newPass1) {
+ this.setState(this.state.setIn(['newPass', 'newPass1'], newPass1.value));
+ }
+
+ onChangeNewPass2(newPass2) {
+ this.setState(this.state.setIn(['newPass', 'newPass2'], newPass2.value));
+ }
+
+ onShowChangePassword() {
+ this.setState(
+ this.state
+ .setIn(['newPass', 'newPass1'], '')
+ .setIn(['newPass', 'newPass2'], '')
+ .setIn(['newPass', 'error'], '')
+ .setIn(['newPass', 'loading'], false)
+ .setIn(['newPass', 'shown'], true)
+ );
+ }
+
+ onHideChangePassword() {
+ this.setState(
+ this.state
+ .setIn(['newPass', 'newPass1'], '')
+ .setIn(['newPass', 'newPass2'], '')
+ .setIn(['newPass', 'error'], '')
+ .setIn(['newPass', 'loading'], false)
+ .setIn(['newPass', 'shown'], false)
+ );
+ }
+
+ onChangePassword() {
+ this.setState(
+ this.state
+ .setIn(['newPass', 'loading'], true)
+ .setIn(['newPass', 'error'], '')
+ );
+ }
+
+ onChangePasswordSuccess() {
+ this.setState(
+ this.state
+ .setIn(['newPass', 'newPass1'], '')
+ .setIn(['newPass', 'newPass2'], '')
+ .setIn(['newPass', 'error'], '')
+ .setIn(['newPass', 'loading'], false)
+ );
+ }
+
+ onChangePasswordFailure() {
+ this.setState(
+ this.state
+ .setIn(['newPass', 'error'], 'Password change failed')
+ .setIn(['newPass', 'loading'], false)
+ );
+ }
+
onShowRescueCodesSuccess({ rescueCodes }) {
this.setState(
this.state.merge({
@@ -129,6 +192,10 @@ class OptionsStore {
static getOptions() {
return this.getState().get('options');
}
+
+ static getNewPass() {
+ return this.getState().get('newPass');
+ }
}
export default alt.createStore(makeImmutable(OptionsStore), 'OptionsStore');
diff --git a/src/stylesheets/application.sass b/src/stylesheets/application.sass
index f14c0d3..643a777 100644
--- a/src/stylesheets/application.sass
+++ b/src/stylesheets/application.sass
@@ -30,5 +30,6 @@
@import 'components/users/UserConnect'
@import 'components/options/OptionsContainer'
+@import 'components/options/ChangePassword'
@import 'components/options/OptionsTOTP'
@import 'components/options/ImportKeepass'
diff --git a/src/stylesheets/components/options/ChangePassword.sass b/src/stylesheets/components/options/ChangePassword.sass
new file mode 100644
index 0000000..ef27225
--- /dev/null
+++ b/src/stylesheets/components/options/ChangePassword.sass
@@ -0,0 +1,10 @@
+.options-changepassword
+ margin-left: 20px
+
+.options-changepassword-infos
+ margin-top: 10px
+
+.options-changepassword-success
+ color: $color-nephritis
+ text-align: center
+ font-size: 20px
\ No newline at end of file
diff --git a/src/stylesheets/components/utilities/Button.sass b/src/stylesheets/components/utilities/Button.sass
index 8aaa2e7..8bd5b0d 100644
--- a/src/stylesheets/components/utilities/Button.sass
+++ b/src/stylesheets/components/utilities/Button.sass
@@ -40,8 +40,17 @@
background-color: $color-peter-river
color: white
+.button--style-warning
+ @extend .button--style-primary
+ background-color: $color-pomegranate
+
+.button--style-success
+ @extend .button--style-primary
+ background-color: $color-nephritis
+
.button--style-default,
-.button--style-primary
+.button--style-primary,
+.button--style-warning
&.button--size-base
.icon
margin-left: -12px