From 0e787a09c3682f6db84a38228577185faf816157 Mon Sep 17 00:00:00 2001
From: Luke Barnard <lukeb@openmarket.com>
Date: Tue, 16 May 2017 09:44:52 +0100
Subject: [PATCH 1/5] Implement dialog to set password

Until https://github.com/matrix-org/matrix-react-sdk/pull/881, ChangePassword will not know about the cached password (so it won't hide "Current Password" yet).

There's also a bit of work left - informing the SessionStore that the password has changed (marked with a TODO)
---
 .../views/dialogs/SetPasswordDialog.js        | 88 +++++++++++++++++++
 .../views/globals/PasswordNagBar.js           | 12 +--
 src/skins/vector/css/_components.scss         |  1 +
 .../views/dialogs/_SetPasswordDialog.scss     | 35 ++++++++
 4 files changed, 130 insertions(+), 6 deletions(-)
 create mode 100644 src/components/views/dialogs/SetPasswordDialog.js
 create mode 100644 src/skins/vector/css/vector-web/views/dialogs/_SetPasswordDialog.scss

diff --git a/src/components/views/dialogs/SetPasswordDialog.js b/src/components/views/dialogs/SetPasswordDialog.js
new file mode 100644
index 0000000000..977fadbd43
--- /dev/null
+++ b/src/components/views/dialogs/SetPasswordDialog.js
@@ -0,0 +1,88 @@
+/*
+Copyright 2016 OpenMarket Ltd
+Copyright 2017 Vector Creations Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import q from 'q';
+import React from 'react';
+import sdk from 'matrix-react-sdk';
+import {MatrixClientPeg} from 'matrix-react-sdk';
+import classnames from 'classnames';
+
+/**
+ * Prompt the user to set a password
+ *
+ * On success, `onFinished()` when finished
+ */
+export default React.createClass({
+    displayName: 'SetPasswordDialog',
+    propTypes: {
+        onFinished: React.PropTypes.func.isRequired,
+    },
+
+    getInitialState: function() {
+        return {
+            error: null,
+        };
+    },
+
+    _onPasswordChanged: function() {
+        this.props.onFinished();
+    },
+
+    _onPasswordChangeError: function(err) {
+        let errMsg = err.error || "";
+        if (err.httpStatus === 403) {
+            errMsg = "Failed to change password. Is your password correct?";
+        } else if (err.httpStatus) {
+            errMsg += ` (HTTP status ${err.httpStatus})`;
+        }
+        this.setState({
+            error: errMsg,
+        });
+    },
+
+    render: function() {
+        const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
+        const ChangePassword = sdk.getComponent('views.settings.ChangePassword');
+        const Spinner = sdk.getComponent('elements.Spinner');
+
+        return (
+            <BaseDialog className="mx_SetPasswordDialog"
+                onFinished={this.props.onFinished}
+                title="Please set a new password!"
+            >
+                <div className="mx_Dialog_content">
+                    <p>
+                        This will allow you to return to your account after signing out,
+                        and sign in on other devices.
+                    </p>
+                    <ChangePassword
+                        className="mx_SetPasswordDialog_change_password"
+                        rowClassName=""
+                        rowLabelClassName=""
+                        rowInputClassName=""
+                        buttonClassName="mx_Dialog_primary mx_SetPasswordDialog_change_password_button"
+                        disableConfirmation={true}
+                        onError={this._onPasswordChangeError}
+                        onFinished={this._onPasswordChanged} />
+                    <div className="error">
+                        { this.state.error }
+                    </div>
+                </div>
+            </BaseDialog>
+        );
+    },
+});
diff --git a/src/components/views/globals/PasswordNagBar.js b/src/components/views/globals/PasswordNagBar.js
index 11168403dc..a42706c3ae 100644
--- a/src/components/views/globals/PasswordNagBar.js
+++ b/src/components/views/globals/PasswordNagBar.js
@@ -22,12 +22,12 @@ import Modal from 'matrix-react-sdk/lib/Modal';
 
 export default React.createClass({
     onUpdateClicked: function() {
-        // TODO: Implement dialog to set password
-        // const SetPasswordDialog = sdk.getComponent('dialogs.SetPasswordDialog');
-        // Modal.createDialog(SetPasswordDialog, {
-        //     onFinished: () => {
-        //     }
-        // });
+        const SetPasswordDialog = sdk.getComponent('dialogs.SetPasswordDialog');
+        Modal.createDialog(SetPasswordDialog, {
+            onFinished: () => {
+                //TODO: Notify SessionStore of changed password: dispatch password_changed
+            }
+        });
     },
 
     render: function() {
diff --git a/src/skins/vector/css/_components.scss b/src/skins/vector/css/_components.scss
index a0864817fe..b1964dca04 100644
--- a/src/skins/vector/css/_components.scss
+++ b/src/skins/vector/css/_components.scss
@@ -69,6 +69,7 @@
 @import "./vector-web/views/context_menus/_MessageContextMenu.scss";
 @import "./vector-web/views/context_menus/_RoomTileContextMenu.scss";
 @import "./vector-web/views/dialogs/_ChangelogDialog.scss";
+@import "./vector-web/views/dialogs/_SetPasswordDialog.scss";
 @import "./vector-web/views/directory/_NetworkDropdown.scss";
 @import "./vector-web/views/elements/_ImageView.scss";
 @import "./vector-web/views/elements/_Spinner.scss";
diff --git a/src/skins/vector/css/vector-web/views/dialogs/_SetPasswordDialog.scss b/src/skins/vector/css/vector-web/views/dialogs/_SetPasswordDialog.scss
new file mode 100644
index 0000000000..28a8b7c9d7
--- /dev/null
+++ b/src/skins/vector/css/vector-web/views/dialogs/_SetPasswordDialog.scss
@@ -0,0 +1,35 @@
+/*
+Copyright 2017 Vector Creations Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_SetPasswordDialog_change_password input {
+    border-radius: 3px;
+    border: 1px solid $input-border-color;
+    padding: 9px;
+    color: $primary-fg-color;
+    background-color: $primary-bg-color;
+    font-size: 15px;
+    width: 100%;
+    max-width: 280px;
+    margin-bottom: 10px;
+}
+
+.mx_SetPasswordDialog_change_password_button {
+    margin-top: 68px;
+}
+
+.mx_SetPasswordDialog .mx_Dialog_content {
+    margin-bottom: 0px;
+}

From 5814a3fdc8d82ac864ce271cd5211131b7aa9298 Mon Sep 17 00:00:00 2001
From: Luke Barnard <lukeb@openmarket.com>
Date: Tue, 16 May 2017 10:11:44 +0100
Subject: [PATCH 2/5] Fix copyright

---
 src/components/views/dialogs/SetPasswordDialog.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/components/views/dialogs/SetPasswordDialog.js b/src/components/views/dialogs/SetPasswordDialog.js
index 977fadbd43..1aabf1816d 100644
--- a/src/components/views/dialogs/SetPasswordDialog.js
+++ b/src/components/views/dialogs/SetPasswordDialog.js
@@ -1,5 +1,4 @@
 /*
-Copyright 2016 OpenMarket Ltd
 Copyright 2017 Vector Creations Ltd
 
 Licensed under the Apache License, Version 2.0 (the "License");

From e367fb5a987f6b3621704688eb3af7c6593bc9f5 Mon Sep 17 00:00:00 2001
From: Luke Barnard <lukeb@openmarket.com>
Date: Tue, 16 May 2017 12:45:30 +0100
Subject: [PATCH 3/5] disabledConfirmation -> confirm

---
 src/components/views/dialogs/SetPasswordDialog.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/views/dialogs/SetPasswordDialog.js b/src/components/views/dialogs/SetPasswordDialog.js
index 1aabf1816d..a0b6fd1e37 100644
--- a/src/components/views/dialogs/SetPasswordDialog.js
+++ b/src/components/views/dialogs/SetPasswordDialog.js
@@ -74,7 +74,7 @@ export default React.createClass({
                         rowLabelClassName=""
                         rowInputClassName=""
                         buttonClassName="mx_Dialog_primary mx_SetPasswordDialog_change_password_button"
-                        disableConfirmation={true}
+                        confirm={false}
                         onError={this._onPasswordChangeError}
                         onFinished={this._onPasswordChanged} />
                     <div className="error">

From 48856c31f893815f3d3731717219d17db83dfc12 Mon Sep 17 00:00:00 2001
From: Luke Barnard <lukeb@openmarket.com>
Date: Tue, 16 May 2017 13:48:56 +0100
Subject: [PATCH 4/5] Dispatch password_changed when SetPasswordDialog finished

---
 src/components/views/globals/PasswordNagBar.js | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/components/views/globals/PasswordNagBar.js b/src/components/views/globals/PasswordNagBar.js
index a42706c3ae..b44950ad31 100644
--- a/src/components/views/globals/PasswordNagBar.js
+++ b/src/components/views/globals/PasswordNagBar.js
@@ -25,7 +25,10 @@ export default React.createClass({
         const SetPasswordDialog = sdk.getComponent('dialogs.SetPasswordDialog');
         Modal.createDialog(SetPasswordDialog, {
             onFinished: () => {
-                //TODO: Notify SessionStore of changed password: dispatch password_changed
+                // Notify SessionStore that the user's password was changed
+                dis.dispatch({
+                    action: 'password_changed',
+                });
             }
         });
     },

From 11d88aa6a2b9b1f447c432bb52eb72e2579f8bd8 Mon Sep 17 00:00:00 2001
From: Luke Barnard <lukeb@openmarket.com>
Date: Tue, 16 May 2017 13:55:25 +0100
Subject: [PATCH 5/5] import dispatcher

---
 src/components/views/globals/PasswordNagBar.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/components/views/globals/PasswordNagBar.js b/src/components/views/globals/PasswordNagBar.js
index b44950ad31..3fd0191a31 100644
--- a/src/components/views/globals/PasswordNagBar.js
+++ b/src/components/views/globals/PasswordNagBar.js
@@ -19,6 +19,7 @@ limitations under the License.
 import React from 'react';
 import sdk from 'matrix-react-sdk';
 import Modal from 'matrix-react-sdk/lib/Modal';
+import dis from 'matrix-react-sdk/lib/dispatcher';
 
 export default React.createClass({
     onUpdateClicked: function() {