From bc71366fd507f169b92ac6da6ca50715bfd0c789 Mon Sep 17 00:00:00 2001 From: okbel Date: Fri, 20 Apr 2018 18:23:46 -0300 Subject: [PATCH 01/10] Frontend for Change Password --- plugins/talk-plugin-auth/client/index.js | 2 + .../components/ChangePassword.css | 132 ++++++++++++++++++ .../components/ChangePassword.js | 118 ++++++++++++++++ .../containers/ChangePassword.js | 0 4 files changed, 252 insertions(+) create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js create mode 100644 plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js diff --git a/plugins/talk-plugin-auth/client/index.js b/plugins/talk-plugin-auth/client/index.js index 13abce1d9..9851e82c5 100644 --- a/plugins/talk-plugin-auth/client/index.js +++ b/plugins/talk-plugin-auth/client/index.js @@ -4,6 +4,7 @@ import SetUsernameDialog from './stream/containers/SetUsernameDialog'; import translations from './translations.yml'; import Login from './login/containers/Main'; import reducer from './login/reducer'; +import ChangePassword from './profile-settings/components/ChangePassword'; export default { reducer, @@ -11,5 +12,6 @@ export default { slots: { stream: [UserBox, SignInButton, SetUsernameDialog], login: [Login], + profileSettings: [ChangePassword], }, }; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css new file mode 100644 index 000000000..94a938e40 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css @@ -0,0 +1,132 @@ +.container { + position: relative; + color: #202020; + padding: 10px; + border-radius: 2px; + border: solid 1px transparent; + box-sizing: border-box; + justify-content: space-between; + + &.editable { + border-color: #979797; + background-color: #EDEDED; + } +} + +.detailItemContent { + min-width: 280px; +} + +.detailItemMessage { + flex-grow: 1; + display: flex; + align-items: center; + padding-left: 2px; + padding-top: 16px; +} + +.actions { + position: absolute; + top: 10px; + right: 10px; + display: flex; + flex-direction: column; + align-items: center; +} + +.title { + color: #202020; +} + +.detailList { + padding: 0; + margin: 0; + list-style: none; +} + +.detailLabel { + color: #4C4C4D; + font-size: 1em; + display: block; + margin-bottom: 4px; +} + +.detailValue { + padding: 6px 0; + border: solid 1px #979797; + display: block; + font-size: 1.1em; + border-radius: 2px; + background-color: #ffffff; + color: #979797; + box-sizing: border-box; + width: 100%; +} + +.detailItem { + margin-bottom: 12px; +} + +.detailItemContainer { + display: flex; +} + +.detailBottomBox { + display: block; + padding-top: 4px; + text-align: right; + width: 280px; +} + +.detailLink { + color: #00538A; + text-decoration: none; + &:hover { + cursor: pointer; + } +} + +.checkIcon { + color: #00CD73; + & > i { + font-size: 16px; + } +} + +.warningIcon { + color: #FA4643; +} + +.errorMsg { + color: #FA4643; + padding-left: 4px; + font-size: 0.9em; +} + +.button { + border: solid 1px #787D80; + background-color: transparent; + height: 30px; + font-size: 0.9em; +} + +.saveButton { + background-color: #3498DB; + border-color: #3498DB; + color: white; + + &:hover { + background-color: #399ee2; + color: white; + } +} + +.cancelButton { + color:#787D80; + margin-top: 6px; + font-size: 0.9em; + + &:hover { + cursor: pointer; + } +} diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js new file mode 100644 index 000000000..1c2162a4a --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js @@ -0,0 +1,118 @@ +import React from 'react'; +import cn from 'classnames'; +import styles from './ChangePassword.css'; +import { Button, Icon } from 'plugin-api/beta/client/components/ui'; + +class ChangePassword extends React.Component { + state = { editing: false, errors: [], oldPassword: '' }; + + addError = err => { + if (this.state.errors.indexOf(err) === -1) { + this.setState(({ errors }) => ({ + errors: errors.concat(err), + })); + } + }; + + removeError = err => { + this.setState(({ errors }) => ({ + errors: errors.filter(i => i !== err), + })); + }; + + toggleEditing = () => { + this.setState(({ editing }) => ({ + editing: !editing, + })); + }; + + disableEditing = () => { + this.setState(() => ({ + editing: false, + })); + }; + + render() { + return ( +
+

Change Password

+ {this.state.editing && ( + + )} + {this.state.editing ? ( +
+ + + Cancel + +
+ ) : ( +
+ +
+ )} +
+ ); + } +} + +const ErrorMessage = ({ children }) => ( +
+ + {children} +
+); + +export default ChangePassword; diff --git a/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js new file mode 100644 index 000000000..e69de29bb From b5dd63aec1d18b55da6d02bbd2cda7f7a551dca6 Mon Sep 17 00:00:00 2001 From: okbel Date: Mon, 23 Apr 2018 10:32:56 -0300 Subject: [PATCH 02/10] Adding withChangePassword to mutations and plugins API, styles --- client/coral-framework/graphql/fragments.js | 3 ++- client/coral-framework/graphql/mutations.js | 21 +++++++++++++++++++ plugin-api/beta/client/hocs/index.js | 1 + .../components/ChangePassword.css | 18 +++++++++++----- .../containers/ChangePassword.js | 5 +++++ 5 files changed, 42 insertions(+), 6 deletions(-) diff --git a/client/coral-framework/graphql/fragments.js b/client/coral-framework/graphql/fragments.js index a62fd6d92..c5704f719 100644 --- a/client/coral-framework/graphql/fragments.js +++ b/client/coral-framework/graphql/fragments.js @@ -25,6 +25,7 @@ export default { 'UnsuspendUserResponse', 'UpdateAssetSettingsResponse', 'UpdateAssetStatusResponse', - 'UpdateSettingsResponse' + 'UpdateSettingsResponse', + 'ChangePasswordResponse' ), }; diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index bd31be630..228911d4a 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -623,6 +623,27 @@ export const withUpdateSettings = withMutation( } ); +export const withChangePassword = withMutation( + gql` + mutation ChangePassword($input: ChangePasswordInput!) { + changePassword(input: $input) { + ...ChangePasswordResponse + } + } + `, + { + props: ({ mutate }) => ({ + changePassword: input => { + return mutate({ + variables: { + input, + }, + }); + }, + }), + } +); + export const withUpdateAssetSettings = withMutation( gql` mutation UpdateAssetSettings($id: ID!, $input: AssetSettingsInput!) { diff --git a/plugin-api/beta/client/hocs/index.js b/plugin-api/beta/client/hocs/index.js index 215641f32..41ede8445 100644 --- a/plugin-api/beta/client/hocs/index.js +++ b/plugin-api/beta/client/hocs/index.js @@ -25,5 +25,6 @@ export { withUnbanUser, withStopIgnoringUser, withSetCommentStatus, + withChangePassword, } from 'coral-framework/graphql/mutations'; export { compose } from 'recompose'; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css index 94a938e40..6a99de609 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css @@ -23,6 +23,10 @@ align-items: center; padding-left: 2px; padding-top: 16px; + + .warningIcon, .checkIcon { + font-size: 17px; + } } .actions { @@ -36,6 +40,7 @@ .title { color: #202020; + margin: 0 0 20px; } .detailList { @@ -81,6 +86,7 @@ .detailLink { color: #00538A; text-decoration: none; + font-size: 0.9em; &:hover { cursor: pointer; } @@ -88,9 +94,6 @@ .checkIcon { color: #00CD73; - & > i { - font-size: 16px; - } } .warningIcon { @@ -104,16 +107,21 @@ } .button { - border: solid 1px #787D80; + border: 1px solid #787d80; background-color: transparent; height: 30px; - font-size: 0.9em; + font-size: 1em; + line-height: normal; } .saveButton { background-color: #3498DB; border-color: #3498DB; color: white; + + > i { + font-size: 17px; + } &:hover { background-color: #399ee2; diff --git a/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js index e69de29bb..af3a293f9 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js +++ b/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js @@ -0,0 +1,5 @@ +import { compose } from 'recompose'; +import { withChangePassword } from 'plugin-api/beta/client/hocs'; +import ChangePassword from '../components/ChangePassword'; + +export default compose(withChangePassword)(ChangePassword); From 21f942a219b74af75ef2ccf0fdd71bf1646e66a0 Mon Sep 17 00:00:00 2001 From: okbel Date: Mon, 23 Apr 2018 11:43:40 -0300 Subject: [PATCH 03/10] validations --- plugins/talk-plugin-auth/client/index.js | 2 +- .../components/ChangePassword.css | 11 +- .../components/ChangePassword.js | 153 ++++++++++++++++-- .../containers/ChangePassword.js | 3 +- 4 files changed, 148 insertions(+), 21 deletions(-) diff --git a/plugins/talk-plugin-auth/client/index.js b/plugins/talk-plugin-auth/client/index.js index 9851e82c5..039f0f936 100644 --- a/plugins/talk-plugin-auth/client/index.js +++ b/plugins/talk-plugin-auth/client/index.js @@ -4,7 +4,7 @@ import SetUsernameDialog from './stream/containers/SetUsernameDialog'; import translations from './translations.yml'; import Login from './login/containers/Main'; import reducer from './login/reducer'; -import ChangePassword from './profile-settings/components/ChangePassword'; +import ChangePassword from './profile-settings/containers/ChangePassword'; export default { reducer, diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css index 6a99de609..809349bc6 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css @@ -7,7 +7,7 @@ box-sizing: border-box; justify-content: space-between; - &.editable { + &.editing { border-color: #979797; background-color: #EDEDED; } @@ -27,6 +27,13 @@ .warningIcon, .checkIcon { font-size: 17px; } + + .errorMsg { + display: none; + &:nth-child(1) { + display: block; + } + } } .actions { @@ -57,7 +64,7 @@ } .detailValue { - padding: 6px 0; + padding: 6px 2px; border: solid 1px #979797; display: block; font-size: 1.1em; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js index 1c2162a4a..6a278b332 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js @@ -1,10 +1,75 @@ import React from 'react'; +import PropTypes from 'prop-types'; import cn from 'classnames'; import styles from './ChangePassword.css'; import { Button, Icon } from 'plugin-api/beta/client/components/ui'; +import validate from 'coral-framework/helpers/validate'; +import errorMsj from 'coral-framework/helpers/error'; class ChangePassword extends React.Component { - state = { editing: false, errors: [], oldPassword: '' }; + state = { + editing: false, + showErrors: true, + errors: [], + formData: { + oldPassword: '', + newPassword: '', + confirmNewPassword: '', + }, + }; + + onChange = e => { + const { name, value, type } = e.target; + this.setState( + state => ({ + formData: { + ...state.formData, + [name]: value, + }, + }), + () => { + this.fieldValidation(value, type, name); + this.equalityValidation('newPassword', 'confirmNewPassword'); + } + ); + }; + + equalityValidation = (field, field2) => { + const cond = this.state.formData[field] === this.state.formData[field2]; + if (!cond) { + this.addError('matchPasswords'); + } else { + this.removeError('matchPasswords'); + } + return cond; + }; + + fieldValidation = (value, type, name) => { + if (!validate[type](value)) { + this.addError(name); + } else { + this.removeError(name); + } + }; + + formValidation = () => { + // const { formData } = this.state; + // const validKeys = Object.keys(formData); + // // Required Validation + // const empty = validKeys.filter(name => { + // const cond = !formData[name].length; + // if (cond) { + // this.addError('empty'); + // } else { + // this.removeError() + // } + // return cond; + // }); + }; + + hasError = err => { + return this.state.errors.indexOf(err) !== -1; + }; addError = err => { if (this.state.errors.indexOf(err) === -1) { @@ -33,24 +98,37 @@ class ChangePassword extends React.Component { }; render() { + const { formData, showErrors, editing } = this.state; + return ( -

Change Password

- {this.state.editing && ( + {editing && (
  • - +
    - - {/* Incorrect password. Please try again */} + {!this.hasError('oldPassword') && + formData.oldPassword.length ? ( + + ) : null} + {showErrors && + this.hasError('oldPassword') && ( + {errorMsj['password']} + )}
    @@ -61,10 +139,27 @@ class ChangePassword extends React.Component {
    - +
    - Passwords don’t match + {!this.hasError('newPassword') && + !this.hasError('matchPasswords') && + formData.newPassword.length ? ( + + ) : null} + {showErrors && + this.hasError('newPassword') && ( + {errorMsj['password']} + )} + {showErrors && + this.hasError('matchPasswords') && ( + Passwords don`t match amigo + )}
  • @@ -74,21 +169,39 @@ class ChangePassword extends React.Component { - +
- Passwords don’t match + {!this.hasError('confirmNewPassword') && + !this.hasError('matchPasswords') && + formData.confirmNewPassword.length ? ( + + ) : null} + {showErrors && + this.hasError('confirmNewPassword') && ( + {errorMsj['password']} + )} + {showErrors && + this.hasError('matchPasswords') && ( + Passwords don`t match amigo + )}
)} - {this.state.editing ? ( + {editing ? (
@@ -103,16 +216,24 @@ class ChangePassword extends React.Component {
)} - + ); } } +ChangePassword.propTypes = { + changePassword: PropTypes.func, +}; + const ErrorMessage = ({ children }) => ( -
+
- {children} + {children}
); +ErrorMessage.propTypes = { + children: PropTypes.node, +}; + export default ChangePassword; diff --git a/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js index af3a293f9..b4805c166 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js +++ b/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js @@ -1,5 +1,4 @@ -import { compose } from 'recompose'; import { withChangePassword } from 'plugin-api/beta/client/hocs'; import ChangePassword from '../components/ChangePassword'; -export default compose(withChangePassword)(ChangePassword); +export default withChangePassword(ChangePassword); From 9bb3a9f7cb951c5dff6bf97527f0a8c82307fc95 Mon Sep 17 00:00:00 2001 From: okbel Date: Mon, 23 Apr 2018 15:22:50 -0300 Subject: [PATCH 04/10] changes --- .../components/ChangePassword.css | 7 -- .../components/ChangePassword.js | 99 ++++++++++--------- 2 files changed, 51 insertions(+), 55 deletions(-) diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css index 809349bc6..6b34d8112 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css @@ -27,13 +27,6 @@ .warningIcon, .checkIcon { font-size: 17px; } - - .errorMsg { - display: none; - &:nth-child(1) { - display: block; - } - } } .actions { diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js index 6a278b332..fc190626d 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js @@ -10,12 +10,8 @@ class ChangePassword extends React.Component { state = { editing: false, showErrors: true, - errors: [], - formData: { - oldPassword: '', - newPassword: '', - confirmNewPassword: '', - }, + errors: {}, + formData: {}, }; onChange = e => { @@ -37,54 +33,64 @@ class ChangePassword extends React.Component { equalityValidation = (field, field2) => { const cond = this.state.formData[field] === this.state.formData[field2]; if (!cond) { - this.addError('matchPasswords'); + this.addError({ [field2]: 'Passwords don`t match' }); } else { - this.removeError('matchPasswords'); + this.removeError(field2); } return cond; }; fieldValidation = (value, type, name) => { if (!validate[type](value)) { - this.addError(name); + this.addError({ [name]: errorMsj[type] }); } else { this.removeError(name); } }; - formValidation = () => { - // const { formData } = this.state; - // const validKeys = Object.keys(formData); - // // Required Validation - // const empty = validKeys.filter(name => { - // const cond = !formData[name].length; - // if (cond) { - // this.addError('empty'); - // } else { - // this.removeError() - // } - // return cond; - // }); - }; + onSave = () => { + console.log(this.state.errors); + const { formData } = this.state; + const validKeys = Object.keys(formData); - hasError = err => { - return this.state.errors.indexOf(err) !== -1; - }; + // Required Validation + const validation = validKeys.filter(name => { + const cond = !formData[name].length; + if (cond) { + this.addError({ + [name]: 'This Field is required', + }); + } else { + this.removeError(name); + } + return cond; + }); - addError = err => { - if (this.state.errors.indexOf(err) === -1) { - this.setState(({ errors }) => ({ - errors: errors.concat(err), - })); + if (validation.length) { + //error + return; } }; - removeError = err => { + hasError = err => { + return Object.keys(this.state.errors).indexOf(err) !== -1; + }; + + addError = err => { this.setState(({ errors }) => ({ - errors: errors.filter(i => i !== err), + errors: { ...errors, ...err }, })); }; + removeError = errKey => { + this.setState(state => { + const { [errKey]: _, ...errors } = state.errors; + return { + errors, + }; + }); + }; + toggleEditing = () => { this.setState(({ editing }) => ({ editing: !editing, @@ -98,7 +104,7 @@ class ChangePassword extends React.Component { }; render() { - const { formData, showErrors, editing } = this.state; + const { formData, showErrors, editing, errors } = this.state; return (
{errorMsj['password']} + {errors['oldPassword']} )}
@@ -154,11 +160,7 @@ class ChangePassword extends React.Component { ) : null} {showErrors && this.hasError('newPassword') && ( - {errorMsj['password']} - )} - {showErrors && - this.hasError('matchPasswords') && ( - Passwords don`t match amigo + {errors['newPassword']} )} @@ -178,17 +180,15 @@ class ChangePassword extends React.Component {
{!this.hasError('confirmNewPassword') && - !this.hasError('matchPasswords') && + !this.hasError('confirmNewPassword') && formData.confirmNewPassword.length ? ( ) : null} {showErrors && this.hasError('confirmNewPassword') && ( - {errorMsj['password']} - )} - {showErrors && - this.hasError('matchPasswords') && ( - Passwords don`t match amigo + + {errors['confirmNewPassword']} + )}
@@ -200,8 +200,11 @@ class ChangePassword extends React.Component { From 76ede5c541c65337235659b7ff357dbd75662eef Mon Sep 17 00:00:00 2001 From: okbel Date: Mon, 23 Apr 2018 15:32:21 -0300 Subject: [PATCH 05/10] fix for large icons, reorder of styles --- .../server/views/unsubscribe-notifications.ejs | 2 +- views/admin.ejs | 2 +- views/embed/stream.ejs | 2 +- views/login.ejs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/talk-plugin-notifications/server/views/unsubscribe-notifications.ejs b/plugins/talk-plugin-notifications/server/views/unsubscribe-notifications.ejs index a34a45dbb..129c3115c 100644 --- a/plugins/talk-plugin-notifications/server/views/unsubscribe-notifications.ejs +++ b/plugins/talk-plugin-notifications/server/views/unsubscribe-notifications.ejs @@ -3,9 +3,9 @@ <%= t('talk-plugin-notifications.unsubscribe_page.unsubscribe') %> + <%- include(root + '/partials/head') %> - <%- include(root + '/partials/head') %>
diff --git a/views/admin.ejs b/views/admin.ejs index 979e2ec41..b8f775d79 100644 --- a/views/admin.ejs +++ b/views/admin.ejs @@ -11,8 +11,8 @@ - <%- include partials/head %> +
diff --git a/views/embed/stream.ejs b/views/embed/stream.ejs index 50faaf5c2..2027f6069 100644 --- a/views/embed/stream.ejs +++ b/views/embed/stream.ejs @@ -2,9 +2,9 @@ + <%- include ../partials/head %> - <%- include ../partials/head %>
diff --git a/views/login.ejs b/views/login.ejs index 7af820a9c..c5a86c2fb 100644 --- a/views/login.ejs +++ b/views/login.ejs @@ -4,8 +4,8 @@ - <%- include partials/head %> +
From 493c4689c2d54eab43e98065f7d1ee3b64672b64 Mon Sep 17 00:00:00 2001 From: okbel Date: Mon, 23 Apr 2018 23:34:16 -0300 Subject: [PATCH 06/10] as InputField --- .../components/ChangePassword.js | 168 +++++++++--------- 1 file changed, 85 insertions(+), 83 deletions(-) diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js index fc190626d..ff6549a26 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js @@ -25,7 +25,11 @@ class ChangePassword extends React.Component { }), () => { this.fieldValidation(value, type, name); - this.equalityValidation('newPassword', 'confirmNewPassword'); + + // Perform equality validation if password fields have changed + if (name === 'newPassword' || name === 'confirmNewPassword') { + this.equalityValidation('newPassword', 'confirmNewPassword'); + } } ); }; @@ -49,7 +53,8 @@ class ChangePassword extends React.Component { }; onSave = () => { - console.log(this.state.errors); + // errors is empty + const { formData } = this.state; const validKeys = Object.keys(formData); @@ -104,8 +109,11 @@ class ChangePassword extends React.Component { }; render() { - const { formData, showErrors, editing, errors } = this.state; - + const { editing, errors } = this.state; + console.log( + Object.keys(this.state.formData).length, + Object.keys(this.state.errors).length + ); return (
Change Password {editing && (
    -
  • -
    -
    - - -
    -
    - {!this.hasError('oldPassword') && - formData.oldPassword.length ? ( - - ) : null} - {showErrors && - this.hasError('oldPassword') && ( - {errors['oldPassword']} - )} -
    -
    + Forgot your password? -
  • -
  • -
    -
    - - -
    -
    - {!this.hasError('newPassword') && - !this.hasError('matchPasswords') && - formData.newPassword.length ? ( - - ) : null} - {showErrors && - this.hasError('newPassword') && ( - {errors['newPassword']} - )} -
    -
    -
  • -
  • -
    -
    - - -
    -
    - {!this.hasError('confirmNewPassword') && - !this.hasError('confirmNewPassword') && - formData.confirmNewPassword.length ? ( - - ) : null} - {showErrors && - this.hasError('confirmNewPassword') && ( - - {errors['confirmNewPassword']} - - )} -
    -
    -
  • + + +
)} {editing ? ( @@ -201,10 +168,6 @@ class ChangePassword extends React.Component { className={cn(styles.button, styles.saveButton)} icon="save" onClick={this.onSave} - disabled={ - Object.keys(this.state.formData).length && - Object.keys(this.state.errors).length - } > Save @@ -228,6 +191,45 @@ ChangePassword.propTypes = { changePassword: PropTypes.func, }; +const InputField = ({ + id = '', + label = '', + type = 'text', + name = '', + onChange = () => {}, + value = '', + showError = true, + hasError = false, + errorMsg = '', + children, +}) => { + return ( +
  • +
    +
    + + +
    +
    + {!hasError && + value && } + {hasError && showError && {errorMsg}} +
    +
    + {children} +
  • + ); +}; + const ErrorMessage = ({ children }) => (
    From 1d2be0cef0932c07537f396e8bf4f43b34f3676e Mon Sep 17 00:00:00 2001 From: okbel Date: Mon, 23 Apr 2018 23:56:54 -0300 Subject: [PATCH 07/10] Validation finished --- .../components/ChangePassword.js | 51 +++++++------------ 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js index ff6549a26..dbb210d33 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js @@ -5,6 +5,7 @@ import styles from './ChangePassword.css'; import { Button, Icon } from 'plugin-api/beta/client/components/ui'; import validate from 'coral-framework/helpers/validate'; import errorMsj from 'coral-framework/helpers/error'; +import isEqual from 'lodash/isEqual'; class ChangePassword extends React.Component { state = { @@ -14,6 +15,8 @@ class ChangePassword extends React.Component { formData: {}, }; + validKeys = ['oldPassword', 'newPassword', 'confirmNewPassword']; + onChange = e => { const { name, value, type } = e.target; this.setState( @@ -45,38 +48,15 @@ class ChangePassword extends React.Component { }; fieldValidation = (value, type, name) => { - if (!validate[type](value)) { + if (!value.length) { + this.addError({ [name]: 'This field is required' }); + } else if (!validate[type](value)) { this.addError({ [name]: errorMsj[type] }); } else { this.removeError(name); } }; - onSave = () => { - // errors is empty - - const { formData } = this.state; - const validKeys = Object.keys(formData); - - // Required Validation - const validation = validKeys.filter(name => { - const cond = !formData[name].length; - if (cond) { - this.addError({ - [name]: 'This Field is required', - }); - } else { - this.removeError(name); - } - return cond; - }); - - if (validation.length) { - //error - return; - } - }; - hasError = err => { return Object.keys(this.state.errors).indexOf(err) !== -1; }; @@ -102,18 +82,20 @@ class ChangePassword extends React.Component { })); }; - disableEditing = () => { - this.setState(() => ({ - editing: false, - })); + isSubmitBlocked = () => { + const formHasErrors = !!Object.keys(this.state.errors).length; + const formIncomplete = !isEqual( + Object.keys(this.state.formData), + this.validKeys + ); + return formHasErrors || formIncomplete; }; + onSave = () => {}; + render() { const { editing, errors } = this.state; - console.log( - Object.keys(this.state.formData).length, - Object.keys(this.state.errors).length - ); + return (
    Save From 5e3fc2b22ad5bedc3c3571ad198afbb442aa3633 Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 24 Apr 2018 00:20:10 -0300 Subject: [PATCH 08/10] Adding translations, en, es, more --- .../components/ChangePassword.js | 90 ++++++++++++++----- .../talk-plugin-auth/client/translations.yml | 16 ++++ 2 files changed, 85 insertions(+), 21 deletions(-) diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js index dbb210d33..e6c69a11b 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js @@ -6,15 +6,17 @@ import { Button, Icon } from 'plugin-api/beta/client/components/ui'; import validate from 'coral-framework/helpers/validate'; import errorMsj from 'coral-framework/helpers/error'; import isEqual from 'lodash/isEqual'; +import { t } from 'plugin-api/beta/client/services'; + +const initialState = { + editing: false, + showErrors: true, + errors: {}, + formData: {}, +}; class ChangePassword extends React.Component { - state = { - editing: false, - showErrors: true, - errors: {}, - formData: {}, - }; - + state = initialState; validKeys = ['oldPassword', 'newPassword', 'confirmNewPassword']; onChange = e => { @@ -40,7 +42,9 @@ class ChangePassword extends React.Component { equalityValidation = (field, field2) => { const cond = this.state.formData[field] === this.state.formData[field2]; if (!cond) { - this.addError({ [field2]: 'Passwords don`t match' }); + this.addError({ + [field2]: t('talk-plugin-auth.change_password.passwords_dont_match'), + }); } else { this.removeError(field2); } @@ -49,7 +53,9 @@ class ChangePassword extends React.Component { fieldValidation = (value, type, name) => { if (!value.length) { - this.addError({ [name]: 'This field is required' }); + this.addError({ + [name]: t('talk-plugin-auth.change_password.required_field'), + }); } else if (!validate[type](value)) { this.addError({ [name]: errorMsj[type] }); } else { @@ -76,10 +82,10 @@ class ChangePassword extends React.Component { }); }; - toggleEditing = () => { - this.setState(({ editing }) => ({ - editing: !editing, - })); + enableEditing = () => { + this.setState({ + editing: true, + }); }; isSubmitBlocked = () => { @@ -91,7 +97,32 @@ class ChangePassword extends React.Component { return formHasErrors || formIncomplete; }; - onSave = () => {}; + clearForm() { + this.setState(initialState); + } + + onSave = async () => { + const { oldPassword, newPassword } = this.state.formData; + + await this.props.changePassword({ + oldPassword, + newPassword, + }); + + this.clearForm(); + this.disableEditing(); + }; + + disableEditing = () => { + this.setState({ + editing: false, + }); + }; + + cancel() { + this.clearForm(); + this.disableEditing(); + } render() { const { editing, errors } = this.state; @@ -102,7 +133,9 @@ class ChangePassword extends React.Component { [styles.editing]: editing, })} > -

    Change Password

    +

    + {t('talk-plugin-auth.change_password.change_password')} +

    {editing && (
    ) : (
    -
    )} @@ -213,6 +248,19 @@ const InputField = ({ ); }; +InputField.propTypes = { + id: PropTypes.string.isRequired, + label: PropTypes.string.isRequired, + type: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + onChange: PropTypes.func, + value: PropTypes.string, + showError: PropTypes.bool, + hasError: PropTypes.bool, + errorMsg: PropTypes.string, + children: PropTypes.node, +}; + const ErrorMessage = ({ children }) => (
    diff --git a/plugins/talk-plugin-auth/client/translations.yml b/plugins/talk-plugin-auth/client/translations.yml index 6d6f8a6d6..d08162066 100644 --- a/plugins/talk-plugin-auth/client/translations.yml +++ b/plugins/talk-plugin-auth/client/translations.yml @@ -131,6 +131,14 @@ en: username: Username write_your_username: "Edit your username" your_username: "Your username appears on every comment you post." + change_password: + change_password: "Change Password" + passwords_dont_match: "Passwords don`t match" + required_field: "This field is required" + forgot_password: "Forgot your password?" + save: "Save" + cancel: "Cancel" + edit: "Edit" de: talk-plugin-auth: login: @@ -222,6 +230,14 @@ es: username: Nombre write_your_username: "Edita tu nombre" your_username: "Tu nombre aparece en cada comentario que publiques." + change_password: + change_password: "Cambiar Contraseña" + passwords_dont_match: "Las contraseñas no coinciden" + required_field: "Este campo es requerido" + forgot_password: "Olvidaste tu contraseña?" + save: "Guardar" + cancel: "Cancelar" + edit: "Editar" fr: talk-plugin-auth: login: From eaf0df95732183dd693fe0c28f3833a8d9f739ef Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 24 Apr 2018 00:45:51 -0300 Subject: [PATCH 09/10] final refactor, done. --- .../components/ChangePassword.css | 73 +++-------------- .../components/ChangePassword.js | 79 +++---------------- .../components/ErrorMessage.css | 9 +++ .../components/ErrorMessage.js | 17 ++++ .../profile-settings/components/Form.css | 5 ++ .../profile-settings/components/Form.js | 16 ++++ .../components/InputField.css | 51 ++++++++++++ .../profile-settings/components/InputField.js | 60 ++++++++++++++ 8 files changed, 177 insertions(+), 133 deletions(-) create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.js create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/Form.css create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/Form.js create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/InputField.css create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/InputField.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css index 6b34d8112..e94247ac1 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css @@ -13,22 +13,6 @@ } } -.detailItemContent { - min-width: 280px; -} - -.detailItemMessage { - flex-grow: 1; - display: flex; - align-items: center; - padding-left: 2px; - padding-top: 16px; - - .warningIcon, .checkIcon { - font-size: 17px; - } -} - .actions { position: absolute; top: 10px; @@ -42,39 +26,6 @@ color: #202020; margin: 0 0 20px; } - -.detailList { - padding: 0; - margin: 0; - list-style: none; -} - -.detailLabel { - color: #4C4C4D; - font-size: 1em; - display: block; - margin-bottom: 4px; -} - -.detailValue { - padding: 6px 2px; - border: solid 1px #979797; - display: block; - font-size: 1.1em; - border-radius: 2px; - background-color: #ffffff; - color: #979797; - box-sizing: border-box; - width: 100%; -} - -.detailItem { - margin-bottom: 12px; -} - -.detailItemContainer { - display: flex; -} .detailBottomBox { display: block; @@ -92,20 +43,6 @@ } } -.checkIcon { - color: #00CD73; -} - -.warningIcon { - color: #FA4643; -} - -.errorMsg { - color: #FA4643; - padding-left: 4px; - font-size: 0.9em; -} - .button { border: 1px solid #787d80; background-color: transparent; @@ -127,6 +64,16 @@ background-color: #399ee2; color: white; } + + &:disabled { + border-color: #e0e0e0; + + &:hover { + background-color: #e0e0e0; + color: #4f5c67; + cursor: default; + } + } } .cancelButton { diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js index e6c69a11b..0e4e39641 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js @@ -2,11 +2,13 @@ import React from 'react'; import PropTypes from 'prop-types'; import cn from 'classnames'; import styles from './ChangePassword.css'; -import { Button, Icon } from 'plugin-api/beta/client/components/ui'; +import { Button } from 'plugin-api/beta/client/components/ui'; import validate from 'coral-framework/helpers/validate'; import errorMsj from 'coral-framework/helpers/error'; import isEqual from 'lodash/isEqual'; import { t } from 'plugin-api/beta/client/services'; +import Form from './Form'; +import InputField from './InputField'; const initialState = { editing: false, @@ -97,9 +99,9 @@ class ChangePassword extends React.Component { return formHasErrors || formIncomplete; }; - clearForm() { + clearForm = () => { this.setState(initialState); - } + }; onSave = async () => { const { oldPassword, newPassword } = this.state.formData; @@ -119,10 +121,10 @@ class ChangePassword extends React.Component { }); }; - cancel() { + cancel = () => { this.clearForm(); this.disableEditing(); - } + }; render() { const { editing, errors } = this.state; @@ -137,7 +139,7 @@ class ChangePassword extends React.Component { {t('talk-plugin-auth.change_password.change_password')} {editing && ( -
      +
      -
    + )} {editing ? (
    @@ -209,67 +211,4 @@ ChangePassword.propTypes = { changePassword: PropTypes.func, }; -const InputField = ({ - id = '', - label = '', - type = 'text', - name = '', - onChange = () => {}, - value = '', - showError = true, - hasError = false, - errorMsg = '', - children, -}) => { - return ( -
  • -
    -
    - - -
    -
    - {!hasError && - value && } - {hasError && showError && {errorMsg}} -
    -
    - {children} -
  • - ); -}; - -InputField.propTypes = { - id: PropTypes.string.isRequired, - label: PropTypes.string.isRequired, - type: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - onChange: PropTypes.func, - value: PropTypes.string, - showError: PropTypes.bool, - hasError: PropTypes.bool, - errorMsg: PropTypes.string, - children: PropTypes.node, -}; - -const ErrorMessage = ({ children }) => ( -
    - - {children} -
    -); - -ErrorMessage.propTypes = { - children: PropTypes.node, -}; - export default ChangePassword; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css b/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css new file mode 100644 index 000000000..d7a1b6d45 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css @@ -0,0 +1,9 @@ +.errorMsg { + color: #FA4643; + padding-left: 4px; + font-size: 0.9em; +} + +.warningIcon { + color: #FA4643; +} \ No newline at end of file diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.js b/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.js new file mode 100644 index 000000000..f39a8fc08 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.js @@ -0,0 +1,17 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styles from './ErrorMessage.css'; +import { Icon } from 'plugin-api/beta/client/components/ui'; + +const ErrorMessage = ({ children }) => ( +
    + + {children} +
    +); + +ErrorMessage.propTypes = { + children: PropTypes.node, +}; + +export default ErrorMessage; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/Form.css b/plugins/talk-plugin-auth/client/profile-settings/components/Form.css new file mode 100644 index 000000000..b7a2a21ee --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/Form.css @@ -0,0 +1,5 @@ +.detailList { + padding: 0; + margin: 0; + list-style: none; +} \ No newline at end of file diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/Form.js b/plugins/talk-plugin-auth/client/profile-settings/components/Form.js new file mode 100644 index 000000000..8a455e808 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/Form.js @@ -0,0 +1,16 @@ +import React from 'react'; +import styles from './Form.css'; +import PropTypes from 'prop-types'; + +const Form = ({ children, className = '' }) => ( +
    +
      {children}
    +
    +); + +Form.propTypes = { + className: PropTypes.string, + children: PropTypes.node, +}; + +export default Form; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css new file mode 100644 index 000000000..be25a44b9 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css @@ -0,0 +1,51 @@ + +.detailItem { + margin-bottom: 12px; +} + +.detailItemContainer { + display: flex; +} + +.detailItemContent { + min-width: 280px; +} + +.detailLabel { + color: #4C4C4D; + font-size: 1em; + display: block; + margin-bottom: 4px; +} + +.detailValue { + padding: 6px 2px; + border: solid 1px #979797; + display: block; + font-size: 1.1em; + border-radius: 2px; + background-color: #ffffff; + color: #979797; + box-sizing: border-box; + width: 100%; +} + +.detailItemMessage { + flex-grow: 1; + display: flex; + align-items: center; + padding-left: 2px; + padding-top: 16px; + + .warningIcon, .checkIcon { + font-size: 17px; + } +} + +.checkIcon { + color: #00CD73; +} + +.warningIcon { + color: #FA4643; +} diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js new file mode 100644 index 000000000..ed9c394ee --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js @@ -0,0 +1,60 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styles from './InputField.css'; +import ErrorMessage from './ErrorMessage'; +import { Icon } from 'plugin-api/beta/client/components/ui'; + +const InputField = ({ + id = '', + label = '', + type = 'text', + name = '', + onChange = () => {}, + value = '', + showError = true, + hasError = false, + errorMsg = '', + children, +}) => { + return ( +
  • +
    +
    + + +
    +
    + {!hasError && + value && } + {hasError && showError && {errorMsg}} +
    +
    + {children} +
  • + ); +}; + +InputField.propTypes = { + id: PropTypes.string.isRequired, + label: PropTypes.string.isRequired, + type: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + onChange: PropTypes.func, + value: PropTypes.string, + showError: PropTypes.bool, + hasError: PropTypes.bool, + errorMsg: PropTypes.string, + children: PropTypes.node, +}; + +export default InputField; From 37919a11ab36dcb991c5ec00f4ced014fe90d905 Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 24 Apr 2018 13:39:13 -0300 Subject: [PATCH 10/10] Adding a notification after saving --- .../components/ChangePassword.js | 20 ++++++++++++++----- .../containers/ChangePassword.js | 12 +++++++++-- .../talk-plugin-auth/client/translations.yml | 2 ++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js index 0e4e39641..3479b5dd9 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js @@ -9,6 +9,7 @@ import isEqual from 'lodash/isEqual'; import { t } from 'plugin-api/beta/client/services'; import Form from './Form'; import InputField from './InputField'; +import { getErrorMessages } from 'coral-framework/utils'; const initialState = { editing: false, @@ -106,10 +107,18 @@ class ChangePassword extends React.Component { onSave = async () => { const { oldPassword, newPassword } = this.state.formData; - await this.props.changePassword({ - oldPassword, - newPassword, - }); + try { + await this.props.changePassword({ + oldPassword, + newPassword, + }); + this.props.notify( + 'success', + t('talk-plugin-auth.change_password.changed_password_msg') + ); + } catch (err) { + this.props.notify('error', getErrorMessages(err)); + } this.clearForm(); this.disableEditing(); @@ -208,7 +217,8 @@ class ChangePassword extends React.Component { } ChangePassword.propTypes = { - changePassword: PropTypes.func, + changePassword: PropTypes.func.isRequired, + notify: PropTypes.func.isRequired, }; export default ChangePassword; diff --git a/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js index b4805c166..1322a2940 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js +++ b/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js @@ -1,4 +1,12 @@ -import { withChangePassword } from 'plugin-api/beta/client/hocs'; +import { compose } from 'react-apollo'; +import { bindActionCreators } from 'redux'; +import { connect } from 'plugin-api/beta/client/hocs'; import ChangePassword from '../components/ChangePassword'; +import { notify } from 'coral-framework/actions/notification'; +import { withChangePassword } from 'plugin-api/beta/client/hocs'; -export default withChangePassword(ChangePassword); +const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); + +export default compose(connect(null, mapDispatchToProps), withChangePassword)( + ChangePassword +); diff --git a/plugins/talk-plugin-auth/client/translations.yml b/plugins/talk-plugin-auth/client/translations.yml index d08162066..915aee1c7 100644 --- a/plugins/talk-plugin-auth/client/translations.yml +++ b/plugins/talk-plugin-auth/client/translations.yml @@ -139,6 +139,7 @@ en: save: "Save" cancel: "Cancel" edit: "Edit" + changed_password_msg: "Changed Password - Your password has been successfully changed" de: talk-plugin-auth: login: @@ -238,6 +239,7 @@ es: save: "Guardar" cancel: "Cancelar" edit: "Editar" + changed_password_msg: "Contraseña Actualizada - Tu contraseña ha sido exitosamente actualizada" fr: talk-plugin-auth: login: