Browse Source

API Integration for forget-password & registration page (#24)

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: api integration for register page

fix: messages

feat: api integration for forget-password page

fix: login title and password placeholder

feat: disable button until get response

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: integrate api for new login page

feat: implement responsive header

feat: implement checkbox

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

fix: checkbox event issue

feat: implement register page

feat: implement registration page

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: implement UI for forgot-password

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: implement new login page

feat: implement input shared component

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: implement auth header

Merge branch 'feat/ui-layout' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

capitalize filename

fix: webpack config to add output default url

Merge branch 'master' into feat/ui-layout

Merge branch 'master' into feat/ui-layout

feat: integrate lazy loading and new page structure

feat: use different layout for new Pages

Co-authored-by: Tyler <everdev0923@gmail.com>
Co-authored-by: Jonathan Cobb <jonathan@kyuss.org>
Co-authored-by: jonathan <jonathan@noreply.git.bubblev.org>
Reviewed-on: https://git.bubblev.org/bubblev/bubble-web/pulls/24
pull/32/head
Tyler Chen 4 years ago
committed by jonathan
parent
commit
be0d8632c2
5 changed files with 296 additions and 28 deletions
  1. +1
    -0
      src/_assets/messages.json
  2. +1
    -2
      src/_components/shared/Checkbox.vue
  3. +59
    -5
      src/_pages/auth/ForgotPassword.vue
  4. +6
    -6
      src/_pages/auth/Login.vue
  5. +229
    -15
      src/_pages/auth/Register.vue

+ 1
- 0
src/_assets/messages.json View File

@@ -1,2 +1,3 @@
{
"field_label_enter_password": "Enter Password"
}

+ 1
- 2
src/_components/shared/Checkbox.vue View File

@@ -72,8 +72,7 @@ export default {
},
methods: {
handleChange() {
console.log(this.value);
this.$emit('input', !this.value);
this.$emit('input', Boolean(!this.value));
},
},
};


+ 59
- 5
src/_pages/auth/ForgotPassword.vue View File

@@ -7,15 +7,32 @@
{{ messages.forgot_password_blurb }}
</h4>

<form class="auth-form">
<form class="auth-form" @submit.prevent="handleSubmit">
<div class="form-group">
<Input
class="form-control"
v-model="email"
:placeholder="messages.field_email_hint"
/>
<span
class="form-error"
v-if="submitted && emailErrors && emailErrors.length"
>
{{ emailErrors.join(', ') }}
</span>
<div
v-if="submitted && errors.has('name')"
class="invalid-feedback d-block"
>
{{ errors.first('name') }}
</div>
</div>
<Button color="default" class="auth-form-submit">
<Button
color="default"
class="auth-form-submit"
@click="handleSubmit"
:disabled="status.sendingResetPasswordMessage"
>
{{ messages.button_label_forgot_password }}
</Button>
<p class="text-center mt-3">
@@ -50,7 +67,9 @@
</style>

<script>
import { mapState } from 'vuex';
import { mapState, mapActions } from 'vuex';
import { validationMixin } from 'vuelidate';
import { required, email, minLength } from 'vuelidate/lib/validators';

import { Button, Input } from '~/_components/shared';

@@ -60,15 +79,50 @@ export default {
Input,
},

mixins: [validationMixin],
validations: {
email: { required, email },
},

data() {
return {
email: '',
password: '',
submitted: false,
};
},

computed: {
...mapState('system', ['messages']),
...mapState('system', ['configs', 'messages']),
...mapState('account', ['status', 'resetPasswordMessageSent']),

emailErrors() {
const errors = [];
if (!this.$v.email.$dirty) return errors;
!this.$v.email.email && errors.push(this.messages['err.email.invalid']);
!this.$v.email.required &&
errors.push(this.messages['err.email.required']);
return errors;
},
},
methods: {
...mapActions('account', ['forgotPassword']),
handleSubmit(e) {
this.errors.clear();
this.$v.$touch();
this.submitted = true;
if (!this.$v.$invalid) {
this.forgotPassword({
username: this.email,
messages: this.messages,
errors: this.errors,
});
}
},
},
watch: {
resetPasswordMessageSent(m) {
if (m === true) this.$router.push('/login');
},
},
};
</script>

+ 6
- 6
src/_pages/auth/Login.vue View File

@@ -206,9 +206,9 @@ export default {
emailErrors() {
const errors = [];
if (!this.$v.email.$dirty) return errors;
!this.$v.email.email && errors.push(this.messages['err.email.invalid']);
!this.$v.email.email && errors.push(this.messages['err_email_invalid']);
!this.$v.email.required &&
errors.push(this.messages['err.email.required']);
errors.push(this.messages['err_email_required']);
return errors;
},

@@ -216,9 +216,9 @@ export default {
const errors = [];
if (!this.$v.password.$dirty) return errors;
!this.$v.password.minLength &&
errors.push(this.messages['err.password.tooShort']);
errors.push(this.messages['err_password_tooShort']);
!this.$v.password.required &&
errors.push(this.messages['err.password.required']);
errors.push(this.messages['err_password_required']);
return errors;
},

@@ -226,7 +226,7 @@ export default {
const errors = [];
if (!this.$v.totpToken.$dirty) return errors;
!this.$v.totpToken.required &&
errors.push(this.messages['err.totpToken.invalid']);
errors.push(this.messages['err_totpToken_invalid']);
return errors;
},

@@ -234,7 +234,7 @@ export default {
const errors = [];
if (!this.$v.unlockKey.$dirty) return errors;
!this.$v.unlockKey.required &&
errors.push(this.messages['err.unlock.required']);
errors.push(this.messages['err_unlock_required']);
return errors;
},
},


+ 229
- 15
src/_pages/auth/Register.vue View File

@@ -7,31 +7,65 @@
{{ messages.register_blurb }}
</h4>

<form class="auth-form">
<form class="auth-form" @submit.prevent="handleSubmit">
<div class="form-group">
<Input
class="form-control"
v-model="email"
:placeholder="messages.register_field_label_email"
/>
<span
class="form-error"
v-if="submitted && emailErrors && emailErrors.length"
>
{{ emailErrors.join(', ') }}
</span>
<div
v-if="submitted && errors.has('email')"
class="invalid-feedback d-block"
>
{{ errors.first('email') }}
</div>
</div>
<div class="form-group">
<Input
class="form-control"
v-model="password"
type="password"
:placeholder="messages.field_label_password"
/>
<p class="description">
{{ messages.field_password_hint }}
</p>
<span
class="form-error"
v-if="submitted && passwordErrors && passwordErrors.length"
>
{{ passwordErrors.join(', ') }}
</span>
<div
v-if="submitted && errors.has('password')"
class="invalid-feedback d-block"
>
{{ errors.first('password') }}
</div>
</div>

<div class="form-group">
<Input
class="form-control"
v-model="confirmPassword"
type="password"
:placeholder="messages.field_label_password_confirm"
/>
<span
class="form-error"
v-if="
submitted && confirmPasswordErrors && confirmPasswordErrors.length
"
>
{{ confirmPasswordErrors.join(', ') }}
</span>
</div>
<div class="form-group">
<Input
@@ -39,6 +73,18 @@
v-model="promoCode"
:placeholder="messages.field_label_promoCode"
/>
<span
class="form-error"
v-if="submitted && promoCodeErrors && promoCodeErrors.length"
>
{{ promoCodeErrors.join(', ') }}
</span>
<div
v-if="submitted && errors.has('promoCode')"
class="invalid-feedback d-block"
>
{{ errors.first('promoCode') }}
</div>
</div>
<a :href="messages.message_request_promoCode_link" target="_blank">
{{ messages.message_request_promoCode }}
@@ -46,21 +92,40 @@

<div class="form-group my-5">
<Checkbox
v-model="agreeTOC"
v-model="agreeToTerms"
:label="messages.field_label_agreeToTerms"
/>
<span
class="form-error"
v-if="submitted && agreeToTermsErrors && agreeToTermsErrors.length"
>
{{ agreeToTermsErrors.join(', ') }}
</span>
<div
v-if="submitted && errors.has('terms')"
class="invalid-feedback d-block"
>
{{ errors.first('terms') }}
</div>
</div>

<div
class="form-group mt-4 d-flex justify-content-center align-items-center"
>
<div class="flex-grow-1 pr-2">
<Button block color="outline">
{{ messages.button_label_cancel }}
</Button>
<router-link to="/new_pages/login">
<Button block color="outline">
{{ messages.button_label_cancel }}
</Button>
</router-link>
</div>
<div class="flex-grow-1 pl-2">
<Button block color="default">
<Button
block
color="default"
@click="handleSubmit"
:disabled="status.registering"
>
{{ messages.button_label_register }}
</Button>
</div>
@@ -70,12 +135,15 @@

<div class="form-group my-3">
<Checkbox
v-model="sendInformation"
v-model="receiveInformationalMessages"
:label="messages.field_label_sendInformation"
/>
</div>
<div class="form-group my-3">
<Checkbox v-model="sendNews" :label="messages.field_label_sendNews" />
<Checkbox
v-model="receivePromotionalMessages"
:label="messages.field_label_sendNews"
/>
</div>
</form>

@@ -83,7 +151,7 @@
<h2 class="covered-section-title text-center">
{{ messages.marketing_message_got_you_covered_title }}
</h2>
<div class="row" v-if="messages">
<div class="row" v-if="messages && messages.marketing_message_topics">
<div
v-for="(item, index) in messages.marketing_message_topics.split(',')"
:key="index"
@@ -176,8 +244,11 @@
</style>

<script>
import { mapState } from 'vuex';
import { mapState, mapActions, mapGetters } from 'vuex';
import { validationMixin } from 'vuelidate';
import { required, email, minLength, sameAs } from 'vuelidate/lib/validators';

import { util } from '~/_helpers';
import { Button, Input, Checkbox, Card } from '~/_components/shared';

export default {
@@ -188,20 +259,163 @@ export default {
Card,
},

mixins: [validationMixin],
validations: {
email: { required, email },
password: { required, minLength: minLength(8) },
confirmPassword: {
sameAsPassword: sameAs('password'),
},
promoCode: {
required,
},
agreeToTerms: {
required,
},
},

data() {
return {
email: '',
password: '',
receiveInformationalMessages: false,
receivePromotionalMessages: false,
agreeToTerms: null,
promoCode: null,
payMethods: null,
selectedPaymentMethod: null,
paymentMethodObject: null,
confirmPassword: '',
promoCode: '',
agreeTOC: false,
sendInformation: false,
sendNews: false,
submitted: false,
};
},

computed: {
...mapState('system', ['messages']),
...mapState('account', ['status']),
...mapState('system', ['messages', 'countries']),
...mapState('plans', ['plans', 'plan']),
...mapState('paymentMethods', [
'paymentMethods',
'paymentMethod',
'accountPaymentMethod',
'paymentInfo',
]),

emailErrors() {
const errors = [];
if (!this.$v.email.$dirty) return errors;
!this.$v.email.email && errors.push(this.messages['err_email_invalid']);
!this.$v.email.required &&
errors.push(this.messages['err_email_required']);
return errors;
},

passwordErrors() {
const errors = [];
if (!this.$v.password.$dirty) return errors;
!this.$v.password.minLength &&
errors.push(this.messages['err_password_tooShort']);
!this.$v.password.required &&
errors.push(this.messages['err_password_required']);
return errors;
},

confirmPasswordErrors() {
const errors = [];
if (!this.$v.confirmPassword.$dirty) return errors;
!this.$v.confirmPassword.sameAsPassword &&
errors.push(this.messages['err_confirmPassword_mismatch']);
return errors;
},

promoCodeErrors() {
const errors = [];
if (!this.$v.promoCode.$dirty) return errors;
!this.$v.promoCode.required &&
errors.push(this.messages['err_promoCode_required']);
return errors;
},

agreeToTermsErrors() {
const errors = [];
!this.$v.agreeToTerms.$model &&
errors.push(this.messages['err_terms_required']);
return errors;
},
},

created() {
if (this.$route.query.plan) {
this.getAllPaymentMethods(this.messages, this.errors);
this.getPlanById({
planId: this.$route.query.plan,
messages: this.messages,
errors: this.errors,
});
}
},

methods: {
...mapActions('account', ['register']),
...mapActions('plans', ['getPlanById']),
...mapActions('paymentMethods', [
'getAllPaymentMethods',
'setPaymentMethod',
]),
...mapGetters('system', ['promoCodesEnabled', 'promoCodeRequired']),

handleSubmit(e) {
this.errors.clear();
if (util.checkSkipRegistration()) {
return;
}
this.errors.clear();
this.$v.$touch();
this.submitted = true;
if (!this.$v.$invalid) {
this.register({
user: {
email: this.email,
password: this.password,
receiveInformationalMessages: this.receiveInformationalMessages,
receivePromotionalMessages: this.receivePromotionalMessages,
agreeToTerms: this.agreeToTerms,
promoCode: this.promoCode,
},
messages: this.messages,
errors: this.errors,
});
}
},
},

watch: {
paymentMethods(pms) {
if (pms && pms.length) {
const okMethods = [];
for (let i = 0; i < pms.length; i++) {
const pm = pms[i];
if (!pm.driverClass.endsWith('NoopCloud')) {
okMethods.push(pm);
}
}
if (okMethods.length === 1) {
this.selectedPaymentMethod = okMethods[0];
this.setPaymentMethod(okMethods[0]);
}
this.payMethods = okMethods;
}
},
accountPaymentMethod(apm) {
if (apm) {
this.paymentMethodObject = apm;
}
},
plan(p) {
if (p.uuid) {
this.user.preferredPlan = p.uuid;
}
},
},
};
</script>

Loading…
Cancel
Save