Add "forgot" page
This commit is contained in:
parent
b3876468b2
commit
131540e3f1
117
resources/assets/src/components/auth/Forgot.vue
Normal file
117
resources/assets/src/components/auth/Forgot.vue
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
<template>
|
||||
<form>
|
||||
<div class="form-group has-feedback">
|
||||
<input
|
||||
v-model="email"
|
||||
type="email"
|
||||
class="form-control"
|
||||
:placeholder="$t('auth.email')"
|
||||
ref="email"
|
||||
>
|
||||
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-8">
|
||||
<div class="form-group has-feedback">
|
||||
<input
|
||||
v-model="captcha"
|
||||
type="text"
|
||||
class="form-control"
|
||||
:placeholder="$t('auth.captcha')"
|
||||
ref="captcha"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-4">
|
||||
<img
|
||||
class="pull-right captcha"
|
||||
:src="`${baseUrl}/auth/captcha?v=${time}`"
|
||||
@click="refreshCaptcha"
|
||||
alt="CAPTCHA"
|
||||
:title="$t('auth.change-captcha')"
|
||||
data-placement="top"
|
||||
data-toggle="tooltip"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="callout callout-success" :class="{ hide: !successMsg }">{{ successMsg }}</div>
|
||||
<div class="callout callout-info" :class="{ hide: !infoMsg }">{{ infoMsg }}</div>
|
||||
<div class="callout callout-warning" :class="{ hide: !warningMsg }">{{ warningMsg }}</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-8">
|
||||
<a :href="`${baseUrl}/auth/login`" class="text-center" v-t="'auth.forgot.login-link'"></a>
|
||||
</div>
|
||||
<div class="col-xs-4">
|
||||
<button v-if="pending" disabled class="btn btn-primary btn-block btn-flat">
|
||||
<i class="fa fa-spinner fa-spin"></i> {{ $t('auth.sending') }}
|
||||
</button>
|
||||
<button v-else @click.prevent="submit" class="btn btn-primary btn-block btn-flat">{{ $t('auth.forgot.button') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Forgot',
|
||||
props: {
|
||||
baseUrl: {
|
||||
default: blessing.base_url
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
email: '',
|
||||
captcha: '',
|
||||
time: Date.now(),
|
||||
successMsg: '',
|
||||
infoMsg: '',
|
||||
warningMsg: '',
|
||||
pending: false
|
||||
}),
|
||||
methods: {
|
||||
async submit() {
|
||||
const { email, captcha } = this;
|
||||
|
||||
if (!email) {
|
||||
this.infoMsg = this.$t('auth.emptyEmail');
|
||||
this.$refs.email.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!/\S+@\S+\.\S+/.test(email)) {
|
||||
this.infoMsg = this.$t('auth.invalidEmail');
|
||||
this.$refs.email.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!captcha) {
|
||||
this.infoMsg = this.$t('auth.emptyCaptcha');
|
||||
this.$refs.captcha.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
this.pending = true;
|
||||
const { errno, msg } = await this.$http.post(
|
||||
'/auth/forgot',
|
||||
{ email, captcha }
|
||||
);
|
||||
if (errno === 0) {
|
||||
this.infoMsg = this.warningMsg = '';
|
||||
this.successMsg = msg;
|
||||
this.pending = false;
|
||||
} else {
|
||||
this.infoMsg = '';
|
||||
this.warningMsg = msg;
|
||||
this.refreshCaptcha();
|
||||
this.pending = false;
|
||||
}
|
||||
},
|
||||
refreshCaptcha() {
|
||||
this.time = Date.now();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
@ -44,4 +44,9 @@ export default [
|
|||
component: () => import('./auth/Register'),
|
||||
el: 'form'
|
||||
},
|
||||
{
|
||||
path: 'auth/forgot',
|
||||
component: () => import('./auth/Forgot'),
|
||||
el: 'form'
|
||||
},
|
||||
];
|
||||
|
|
|
|||
50
resources/assets/tests/components/auth/Forgot.test.js
Normal file
50
resources/assets/tests/components/auth/Forgot.test.js
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import Vue from 'vue';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import Forgot from '@/components/auth/Forgot';
|
||||
|
||||
test('click to refresh captcha', () => {
|
||||
jest.spyOn(Date, 'now');
|
||||
const wrapper = mount(Forgot);
|
||||
wrapper.find('img').trigger('click');
|
||||
expect(Date.now).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
test('submit forgot form', async () => {
|
||||
jest.spyOn(Date, 'now');
|
||||
Vue.prototype.$http.post
|
||||
.mockResolvedValueOnce({ errno: 1, msg: 'fail' })
|
||||
.mockResolvedValueOnce({ errno: 0, msg: 'ok' });
|
||||
const wrapper = mount(Forgot);
|
||||
const button = wrapper.find('button');
|
||||
const info = wrapper.find('.callout-info');
|
||||
const warning = wrapper.find('.callout-warning');
|
||||
const success = wrapper.find('.callout-success');
|
||||
|
||||
button.trigger('click');
|
||||
expect(Vue.prototype.$http.post).not.toBeCalled();
|
||||
expect(info.text()).toBe('auth.emptyEmail');
|
||||
|
||||
wrapper.find('[type="email"]').setValue('a');
|
||||
button.trigger('click');
|
||||
expect(Vue.prototype.$http.post).not.toBeCalled();
|
||||
expect(info.text()).toBe('auth.invalidEmail');
|
||||
|
||||
wrapper.find('[type="email"]').setValue('a@b.c');
|
||||
button.trigger('click');
|
||||
expect(Vue.prototype.$http.post).not.toBeCalled();
|
||||
expect(info.text()).toBe('auth.emptyCaptcha');
|
||||
|
||||
wrapper.find('[type="text"]').setValue('captcha');
|
||||
button.trigger('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(Vue.prototype.$http.post).toBeCalledWith(
|
||||
'/auth/forgot',
|
||||
{ email: 'a@b.c', captcha: 'captcha' }
|
||||
);
|
||||
expect(warning.text()).toBe('fail');
|
||||
expect(Date.now).toHaveBeenCalledTimes(2);
|
||||
|
||||
button.trigger('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(success.text()).toBe('ok');
|
||||
});
|
||||
|
|
@ -29,6 +29,9 @@ auth:
|
|||
repeat-pwd: Repeat your password
|
||||
nickname-intro: Whatever you like expect special characters
|
||||
register-button: Register
|
||||
forgot:
|
||||
login-link: I do remember it
|
||||
button: Send
|
||||
|
||||
skinlib:
|
||||
addToCloset: Add to closet
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ auth:
|
|||
repeat-pwd: 重复密码
|
||||
nickname-intro: 昵称可使用汉字,不可包含特殊字符
|
||||
register-button: 注册
|
||||
forgot:
|
||||
login-link: 我又想起来了
|
||||
button: 发送
|
||||
|
||||
skinlib:
|
||||
addToCloset: 添加至衣柜
|
||||
|
|
|
|||
|
|
@ -16,38 +16,7 @@
|
|||
<div class="callout callout-warning">{{ Session::pull('msg') }}</div>
|
||||
@endif
|
||||
|
||||
<form id="login-form">
|
||||
<div class="form-group has-feedback">
|
||||
<input id="email" type="email" class="form-control" placeholder="@lang('auth.email')">
|
||||
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
|
||||
</div>
|
||||
|
||||
<div class="row" id="captcha-form">
|
||||
<div class="col-xs-8">
|
||||
<div class="form-group has-feedback">
|
||||
<input id="captcha" type="text" class="form-control" placeholder="@lang('auth.captcha')">
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
<div class="col-xs-4">
|
||||
<img class="pull-right captcha" src="{{ url('auth/captcha') }}" alt="CAPTCHA" title="@lang('auth.change-captcha')" data-placement="top" data-toggle="tooltip">
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
</div>
|
||||
|
||||
<div id="msg" class="callout hide"></div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-8">
|
||||
<a href="{{ url('auth/login') }}" class="text-center">@lang('auth.forgot.login-link')</a>
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
<div class="col-xs-4">
|
||||
<button id="forgot-button" class="btn btn-primary btn-block btn-flat">@lang('auth.forgot.button')</button>
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
</div>
|
||||
</form>
|
||||
<form></form>
|
||||
|
||||
</div>
|
||||
<!-- /.login-box-body -->
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user