mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 02:57:57 +00:00 
			
		
		
		
	feat: Add full name to the user signup form (#1534)
This commit is contained in:
		| @@ -2,7 +2,7 @@ | ||||
|  | ||||
| class AccountBuilder | ||||
|   include CustomExceptions::Account | ||||
|   pattr_initialize [:account_name!, :email!, :confirmed!, :user] | ||||
|   pattr_initialize [:account_name!, :email!, :confirmed!, :user, :user_full_name] | ||||
|  | ||||
|   def perform | ||||
|     if @user.nil? | ||||
| @@ -60,18 +60,13 @@ class AccountBuilder | ||||
|     ) | ||||
|   end | ||||
|  | ||||
|   def email_to_name(email) | ||||
|     name = email[/[^@]+/] | ||||
|     name.split('.').map(&:capitalize).join(' ') | ||||
|   end | ||||
|  | ||||
|   def create_user | ||||
|     password = SecureRandom.alphanumeric(12) | ||||
|  | ||||
|     @user = User.new(email: @email, | ||||
|                      password: password, | ||||
|                      password_confirmation: password, | ||||
|                      name: email_to_name(@email)) | ||||
|                      name: @user_full_name) | ||||
|     @user.confirm if @confirmed | ||||
|     @user.save! | ||||
|   end | ||||
|   | ||||
| @@ -16,6 +16,7 @@ class Api::V1::AccountsController < Api::BaseController | ||||
|   def create | ||||
|     @user, @account = AccountBuilder.new( | ||||
|       account_name: account_params[:account_name], | ||||
|       user_full_name: account_params[:user_full_name], | ||||
|       email: account_params[:email], | ||||
|       confirmed: confirmed?, | ||||
|       user: current_user | ||||
| @@ -54,7 +55,7 @@ class Api::V1::AccountsController < Api::BaseController | ||||
|   end | ||||
|  | ||||
|   def account_params | ||||
|     params.permit(:account_name, :email, :name, :locale, :domain, :support_email, :auto_resolve_duration) | ||||
|     params.permit(:account_name, :email, :name, :locale, :domain, :support_email, :auto_resolve_duration, :user_full_name) | ||||
|   end | ||||
|  | ||||
|   def check_signup_enabled | ||||
|   | ||||
| @@ -26,7 +26,8 @@ export default { | ||||
|     const fetchPromise = new Promise((resolve, reject) => { | ||||
|       axios | ||||
|         .post(urlData.url, { | ||||
|           account_name: creds.name, | ||||
|           account_name: creds.accountName.trim(), | ||||
|           user_full_name: creds.fullName.trim(), | ||||
|           email: creds.email, | ||||
|         }) | ||||
|         .then(response => { | ||||
|   | ||||
| @@ -23,7 +23,6 @@ | ||||
| @import 'views/settings/inbox'; | ||||
| @import 'views/settings/channel'; | ||||
| @import 'views/settings/integrations'; | ||||
| @import 'views/signup'; | ||||
|  | ||||
| @import 'plugins/multiselect'; | ||||
| @import 'plugins/dropdown'; | ||||
|   | ||||
| @@ -1,94 +0,0 @@ | ||||
| .signup { | ||||
|   // margin-top: $space-larger*1.2; | ||||
|  | ||||
|   .signup--hero { | ||||
|     margin-bottom: $space-larger * 1.5; | ||||
|  | ||||
|     .hero--logo { | ||||
|       width: 180px; | ||||
|     } | ||||
|  | ||||
|     .hero--title { | ||||
|       margin-top: $space-large; | ||||
|       font-weight: $font-weight-light; | ||||
|     } | ||||
|  | ||||
|     .hero--sub { | ||||
|       font-size: $font-size-medium; | ||||
|       color: $medium-gray; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .signup--features { | ||||
|     list-style-type: none; | ||||
|     font-size: $font-size-medium; | ||||
|  | ||||
|     > li { | ||||
|       padding: $space-slab; | ||||
|  | ||||
|       > i { | ||||
|         margin-right: $space-two; | ||||
|         font-size: $font-size-large; | ||||
|  | ||||
|         &.beer { | ||||
|           color: #dfb63b; | ||||
|         } | ||||
|  | ||||
|         &.report { | ||||
|           color: #2196f3; | ||||
|         } | ||||
|  | ||||
|         &.canned { | ||||
|           color: #1cad22; | ||||
|         } | ||||
|  | ||||
|         &.uptime { | ||||
|           color: #a753b5; | ||||
|         } | ||||
|  | ||||
|         &.secure { | ||||
|           color: #607d8b; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .signup--box { | ||||
|     @include elegant-card; | ||||
|     padding: $space-large; | ||||
|  | ||||
|     label { | ||||
|       font-size: $font-size-default; | ||||
|       color: $color-gray; | ||||
|  | ||||
|       input { | ||||
|         padding: $space-slab; | ||||
|         height: $space-larger; | ||||
|         font-size: $font-size-default; | ||||
|       } | ||||
|  | ||||
|       .error { | ||||
|         font-size: $font-size-small | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .sigin--footer { | ||||
|     padding: $space-medium; | ||||
|     font-size: $font-size-default; | ||||
|  | ||||
|     > a { | ||||
|       font-weight: $font-weight-bold; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .accept--terms { | ||||
|     font-size: $font-size-mini; | ||||
|     text-align: center; | ||||
|     @include margin($zero); | ||||
|  | ||||
|     a { | ||||
|       font-size: $font-size-mini; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -2,12 +2,13 @@ | ||||
|   #{$all-text-inputs}, | ||||
|   select, | ||||
|   .multiselect > .multiselect__tags { | ||||
|     @include thin-border(darken(get-color(alert), 25%)); | ||||
|     @include thin-border(var(--r-400)); | ||||
|   } | ||||
|  | ||||
|   .message { | ||||
|     color: darken(get-color(alert), 25%); | ||||
|     color: var(--r-400); | ||||
|     display: block; | ||||
|     font-size: var(--font-size-small); | ||||
|     font-weight: $font-weight-normal; | ||||
|     margin-bottom: $space-one; | ||||
|     margin-top: -$space-normal; | ||||
|   | ||||
| @@ -6,8 +6,12 @@ | ||||
|       :type="type" | ||||
|       :placeholder="placeholder" | ||||
|       @input="onChange" | ||||
|       @blur="onBlur" | ||||
|     /> | ||||
|     <p v-if="helpText" class="help-text"></p> | ||||
|     <span v-if="error" class="message"> | ||||
|       {{ error }} | ||||
|     </span> | ||||
|   </label> | ||||
| </template> | ||||
|  | ||||
| @@ -34,11 +38,18 @@ export default { | ||||
|       type: String, | ||||
|       default: '', | ||||
|     }, | ||||
|     error: { | ||||
|       type: String, | ||||
|       default: '', | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     onChange(e) { | ||||
|       this.$emit('input', e.target.value); | ||||
|     }, | ||||
|     onBlur(e) { | ||||
|       this.$emit('blur', e.target.value); | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
|   | ||||
| @@ -4,14 +4,19 @@ | ||||
|     "TITLE": "Register", | ||||
|     "TERMS_ACCEPT": "By signing up, you agree to our <a href=\"https://www.chatwoot.com/terms\">T & C</a> and <a href=\"https://www.chatwoot.com/privacy-policy\">Privacy policy</a>", | ||||
|     "ACCOUNT_NAME": { | ||||
|       "LABEL": "Account Name", | ||||
|       "PLACEHOLDER": "Wayne Enterprises", | ||||
|       "ERROR": "Account Name is too short" | ||||
|       "LABEL": "Account name", | ||||
|       "PLACEHOLDER": "Enter an account name. eg: Wayne Enterprises", | ||||
|       "ERROR": "Account name is too short" | ||||
|     }, | ||||
|     "FULL_NAME": { | ||||
|       "LABEL": "Full name", | ||||
|       "PLACEHOLDER": "Enter your full name. eg: Bruce Wayne", | ||||
|       "ERROR": "Full name is too short" | ||||
|     }, | ||||
|     "EMAIL": { | ||||
|       "LABEL": "Email", | ||||
|       "PLACEHOLDER": "bruce@wayne.enterprises", | ||||
|       "ERROR": "Email is invalid" | ||||
|       "LABEL": "Work email", | ||||
|       "PLACEHOLDER": "Enter your work email address. eg: bruce@wayne.enterprises", | ||||
|       "ERROR": "Email address is invalid" | ||||
|     }, | ||||
|     "PASSWORD": { | ||||
|       "LABEL": "Password", | ||||
| @@ -28,12 +33,6 @@ | ||||
|       "ERROR_MESSAGE": "Could not connect to Woot Server, Please try again later" | ||||
|     }, | ||||
|     "SUBMIT": "Submit", | ||||
|     "FEATURES": { | ||||
|       "UNLIMITED_INBOXES": "Unlimited inboxes", | ||||
|       "ROBUST_REPORTING": "Robust Reporting", | ||||
|       "CANNED_RESPONSES": "Canned Responses", | ||||
|       "AUTO_ASSIGNMENT": "Auto Assignment", | ||||
|       "SECURITY": "Enterprise level security" | ||||
|     } | ||||
|     "HAVE_AN_ACCOUNT": "Already have an account?" | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -11,73 +11,54 @@ | ||||
|       </h2> | ||||
|     </div> | ||||
|     <div class="row align-center"> | ||||
|       <div class="medium-5 column small-12"> | ||||
|         <ul class="signup--features"> | ||||
|           <li> | ||||
|             <i class="ion-beer beer"></i> | ||||
|             <span>{{ $t('REGISTER.FEATURES.UNLIMITED_INBOXES') }}</span> | ||||
|           </li> | ||||
|           <li> | ||||
|             <i class="ion-stats-bars report"></i> | ||||
|             <span>{{ $t('REGISTER.FEATURES.ROBUST_REPORTING') }}</span> | ||||
|           </li> | ||||
|           <li> | ||||
|             <i class="ion-chatbox-working canned"></i> | ||||
|             <span>{{ $t('REGISTER.FEATURES.CANNED_RESPONSES') }}</span> | ||||
|           </li> | ||||
|           <li> | ||||
|             <i class="ion-loop uptime"></i> | ||||
|             <span>{{ $t('REGISTER.FEATURES.AUTO_ASSIGNMENT') }}</span> | ||||
|           </li> | ||||
|           <li> | ||||
|             <i class="ion-locked secure"></i> | ||||
|             <span>{{ $t('REGISTER.FEATURES.SECURITY') }}</span> | ||||
|           </li> | ||||
|         </ul> | ||||
|       </div> | ||||
|       <div class="medium-5 column small-12"> | ||||
|         <form class="signup--box login-box " @submit.prevent="submit()"> | ||||
|           <div class="column log-in-form"> | ||||
|             <label :class="{ error: $v.credentials.name.$error }"> | ||||
|               {{ $t('REGISTER.ACCOUNT_NAME.LABEL') }} | ||||
|               <input | ||||
|                 v-model.trim="credentials.name" | ||||
|                 type="text" | ||||
|                 :placeholder="$t('REGISTER.ACCOUNT_NAME.PLACEHOLDER')" | ||||
|                 @input="$v.credentials.name.$touch" | ||||
|       <div class="small-12 medium-6 large-5 column"> | ||||
|         <form class="signup--box login-box" @submit.prevent="submit"> | ||||
|           <woot-input | ||||
|             v-model="credentials.fullName" | ||||
|             :class="{ error: $v.credentials.fullName.$error }" | ||||
|             :label="$t('REGISTER.FULL_NAME.LABEL')" | ||||
|             :placeholder="$t('REGISTER.FULL_NAME.PLACEHOLDER')" | ||||
|             :error=" | ||||
|               $v.credentials.fullName.$error | ||||
|                 ? $t('REGISTER.FULL_NAME.ERROR') | ||||
|                 : '' | ||||
|             " | ||||
|             @blur="$v.credentials.fullName.$touch" | ||||
|           /> | ||||
|               <span v-if="$v.credentials.name.$error" class="message"> | ||||
|                 {{ $t('REGISTER.ACCOUNT_NAME.ERROR') }} | ||||
|               </span> | ||||
|             </label> | ||||
|             <label :class="{ error: $v.credentials.email.$error }"> | ||||
|               {{ $t('REGISTER.EMAIL.LABEL') }} | ||||
|               <input | ||||
|           <woot-input | ||||
|             v-model="credentials.accountName" | ||||
|             :class="{ error: $v.credentials.accountName.$error }" | ||||
|             :label="$t('REGISTER.ACCOUNT_NAME.LABEL')" | ||||
|             :placeholder="$t('REGISTER.ACCOUNT_NAME.PLACEHOLDER')" | ||||
|             :error=" | ||||
|               $v.credentials.accountName.$error | ||||
|                 ? $t('REGISTER.ACCOUNT_NAME.ERROR') | ||||
|                 : '' | ||||
|             " | ||||
|             @blur="$v.credentials.accountName.$touch" | ||||
|           /> | ||||
|           <woot-input | ||||
|             v-model.trim="credentials.email" | ||||
|             type="email" | ||||
|             :class="{ error: $v.credentials.email.$error }" | ||||
|             :label="$t('REGISTER.EMAIL.LABEL')" | ||||
|             :placeholder="$t('REGISTER.EMAIL.PLACEHOLDER')" | ||||
|                 @input="$v.credentials.email.$touch" | ||||
|               /> | ||||
|               <span v-if="$v.credentials.email.$error" class="message"> | ||||
|                 {{ $t('REGISTER.EMAIL.ERROR') }} | ||||
|               </span> | ||||
|             </label> | ||||
|             <woot-submit-button | ||||
|               :disabled=" | ||||
|                 $v.credentials.name.$invalid || | ||||
|                   $v.credentials.email.$invalid || | ||||
|                   register.showLoading | ||||
|             :error=" | ||||
|               $v.credentials.email.$error ? $t('REGISTER.EMAIL.ERROR') : '' | ||||
|             " | ||||
|             @blur="$v.credentials.email.$touch" | ||||
|           /> | ||||
|           <woot-submit-button | ||||
|             :disabled="isSignupInProgress" | ||||
|             :button-text="$t('REGISTER.SUBMIT')" | ||||
|               :loading="register.showLoading" | ||||
|             :loading="isSignupInProgress" | ||||
|             button-class="large expanded" | ||||
|           > | ||||
|           </woot-submit-button> | ||||
|           <p class="accept--terms" v-html="termsLink"></p> | ||||
|           </div> | ||||
|         </form> | ||||
|         <div class="column text-center sigin--footer"> | ||||
|           <span>Already have an account?</span> | ||||
|           <span>{{ $t('REGISTER.HAVE_AN_ACCOUNT') }}</span> | ||||
|           <router-link to="/app/login"> | ||||
|             {{ | ||||
|               useInstallationName( | ||||
| @@ -97,27 +78,30 @@ import { required, minLength, email } from 'vuelidate/lib/validators'; | ||||
| import Auth from '../../api/auth'; | ||||
| import { mapGetters } from 'vuex'; | ||||
| import globalConfigMixin from 'shared/mixins/globalConfigMixin'; | ||||
| import alertMixin from 'shared/mixins/alertMixin'; | ||||
|  | ||||
| export default { | ||||
|   mixins: [globalConfigMixin], | ||||
|   mixins: [globalConfigMixin, alertMixin], | ||||
|   data() { | ||||
|     return { | ||||
|       credentials: { | ||||
|         name: '', | ||||
|         accountName: '', | ||||
|         fullName: '', | ||||
|         email: '', | ||||
|       }, | ||||
|       register: { | ||||
|         message: '', | ||||
|         showLoading: false, | ||||
|       }, | ||||
|       isSignupInProgress: false, | ||||
|       error: '', | ||||
|     }; | ||||
|   }, | ||||
|   validations: { | ||||
|     credentials: { | ||||
|       name: { | ||||
|       accountName: { | ||||
|         required, | ||||
|         minLength: minLength(4), | ||||
|         minLength: minLength(2), | ||||
|       }, | ||||
|       fullName: { | ||||
|         required, | ||||
|         minLength: minLength(2), | ||||
|       }, | ||||
|       email: { | ||||
|         required, | ||||
| @@ -139,27 +123,73 @@ export default { | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     showAlert(message) { | ||||
|       // Reset loading, current selected agent | ||||
|       this.register.showLoading = false; | ||||
|       bus.$emit('newToastMessage', message); | ||||
|     }, | ||||
|     submit() { | ||||
|       this.register.showLoading = true; | ||||
|       Auth.register(this.credentials) | ||||
|         .then(res => { | ||||
|           if (res.status === 200) { | ||||
|     async submit() { | ||||
|       this.$v.$touch(); | ||||
|       if (this.$v.$invalid) { | ||||
|         return; | ||||
|       } | ||||
|       this.isSignupInProgress = true; | ||||
|       try { | ||||
|         const response = await Auth.register(this.credentials); | ||||
|         if (response.status === 200) { | ||||
|           window.location = '/'; | ||||
|         } | ||||
|         }) | ||||
|         .catch(error => { | ||||
|       } catch (error) { | ||||
|         let errorMessage = this.$t('REGISTER.API.ERROR_MESSAGE'); | ||||
|         if (error.response && error.response.data.message) { | ||||
|           errorMessage = error.response.data.message; | ||||
|         } | ||||
|         this.showAlert(errorMessage); | ||||
|         }); | ||||
|       } finally { | ||||
|         this.isSignupInProgress = false; | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
| <style scoped lang="scss"> | ||||
| .signup { | ||||
|   .signup--hero { | ||||
|     margin-bottom: var(--space-larger); | ||||
|  | ||||
|     .hero--logo { | ||||
|       width: 180px; | ||||
|     } | ||||
|  | ||||
|     .hero--title { | ||||
|       margin-top: var(--space-large); | ||||
|       font-weight: var(--font-weight-light); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .signup--box { | ||||
|     padding: var(--space-large); | ||||
|  | ||||
|     label { | ||||
|       font-size: var(--font-size-default); | ||||
|       color: var(--b-600); | ||||
|  | ||||
|       input { | ||||
|         padding: var(--space-slab); | ||||
|         height: var(--space-larger); | ||||
|         font-size: var(--font-size-default); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .sigin--footer { | ||||
|     padding: var(--space-medium); | ||||
|     font-size: var(--font-size-default); | ||||
|  | ||||
|     > a { | ||||
|       font-weight: var(--font-weight-bold); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .accept--terms { | ||||
|     font-size: var(--font-size-small); | ||||
|     text-align: center; | ||||
|     margin: var(--space-normal) 0 0 0; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -3,11 +3,12 @@ require 'rails_helper' | ||||
| RSpec.describe 'Accounts API', type: :request do | ||||
|   describe 'POST /api/v1/accounts' do | ||||
|     let(:email) { Faker::Internet.email } | ||||
|     let(:user_full_name) { Faker::Name.name_with_middle } | ||||
|  | ||||
|     context 'when posting to accounts with correct parameters' do | ||||
|       let(:account_builder) { double } | ||||
|       let(:account) { create(:account) } | ||||
|       let(:user) { create(:user, email: email, account: account) } | ||||
|       let(:user) { create(:user, email: email, account: account, name: user_full_name) } | ||||
|  | ||||
|       before do | ||||
|         allow(AccountBuilder).to receive(:new).and_return(account_builder) | ||||
| @@ -17,7 +18,7 @@ RSpec.describe 'Accounts API', type: :request do | ||||
|       it 'calls account builder' do | ||||
|         allow(account_builder).to receive(:perform).and_return([user, account]) | ||||
|  | ||||
|         params = { account_name: 'test', email: email, user: nil } | ||||
|         params = { account_name: 'test', email: email, user: nil, user_full_name: user_full_name } | ||||
|  | ||||
|         post api_v1_accounts_url, | ||||
|              params: params, | ||||
| @@ -31,7 +32,7 @@ RSpec.describe 'Accounts API', type: :request do | ||||
|       it 'renders error response on invalid params' do | ||||
|         allow(account_builder).to receive(:perform).and_return(nil) | ||||
|  | ||||
|         params = { account_name: nil, email: nil, user: nil } | ||||
|         params = { account_name: nil, email: nil, user: nil, user_full_name: nil } | ||||
|  | ||||
|         post api_v1_accounts_url, | ||||
|              params: params, | ||||
| @@ -46,7 +47,7 @@ RSpec.describe 'Accounts API', type: :request do | ||||
|       it 'ignores confirmed param when called with out super admin token' do | ||||
|         allow(account_builder).to receive(:perform).and_return(nil) | ||||
|  | ||||
|         params = { account_name: 'test', email: email, confirmed: true, user: nil } | ||||
|         params = { account_name: 'test', email: email, confirmed: true, user: nil, user_full_name: user_full_name } | ||||
|  | ||||
|         post api_v1_accounts_url, | ||||
|              params: params, | ||||
| @@ -63,7 +64,7 @@ RSpec.describe 'Accounts API', type: :request do | ||||
|       let(:super_admin) { create(:super_admin) } | ||||
|  | ||||
|       it 'calls account builder with confirmed true when confirmed param is passed' do | ||||
|         params = { account_name: 'test', email: email, confirmed: true } | ||||
|         params = { account_name: 'test', email: email, confirmed: true, user_full_name: user_full_name } | ||||
|  | ||||
|         post api_v1_accounts_url, | ||||
|              params: params, | ||||
| @@ -79,7 +80,7 @@ RSpec.describe 'Accounts API', type: :request do | ||||
|  | ||||
|     context 'when ENABLE_ACCOUNT_SIGNUP env variable is set to false' do | ||||
|       it 'responds 404 on requests' do | ||||
|         params = { account_name: 'test', email: email } | ||||
|         params = { account_name: 'test', email: email, user_full_name: user_full_name } | ||||
|         ENV['ENABLE_ACCOUNT_SIGNUP'] = 'false' | ||||
|  | ||||
|         post api_v1_accounts_url, | ||||
| @@ -93,7 +94,7 @@ RSpec.describe 'Accounts API', type: :request do | ||||
|  | ||||
|     context 'when ENABLE_ACCOUNT_SIGNUP env variable is set to api_only' do | ||||
|       it 'does not respond 404 on requests' do | ||||
|         params = { account_name: 'test', email: email } | ||||
|         params = { account_name: 'test', email: email, user_full_name: user_full_name } | ||||
|         ENV['ENABLE_ACCOUNT_SIGNUP'] = 'api_only' | ||||
|  | ||||
|         post api_v1_accounts_url, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Pranav Raj S
					Pranav Raj S