This commit is contained in:
geek 2018-05-30 16:44:21 +09:00
parent 1cdd48d873
commit 5c52d679db
16 changed files with 163 additions and 45 deletions

View File

@ -1,4 +1,4 @@
<div class="ui-g"> <div class="ui-g" *ngIf="!member">
<div class="ui-g-12"> <div class="ui-g-12">
<form [formGroup]="modifyPasswordForm" (ngSubmit)="modifyPasswordFormSubmit()"> <form [formGroup]="modifyPasswordForm" (ngSubmit)="modifyPasswordFormSubmit()">
<table class="login-table"> <table class="login-table">
@ -14,31 +14,34 @@
<input type="password" <input type="password"
id="pw" id="pw"
autocomplete="off" placeholder="password" autocomplete="off" placeholder="password"
formControlName="pw" formControlName="password"
required class="ui-inputtext ui-corner-all ui-state-default ui-widget"> required class="ui-inputtext ui-corner-all ui-state-default ui-widget">
</span> </span>
<div *ngIf="formErrors.pw" class="help is-danger"> <div *ngIf="password.touched && !password.valid" class="ui-message ui-messages-error ui-corner-all">
{{ formErrors.pw }} Invalid password
</div> </div>
</div> </div>
<div class="ui-g-12"> <div class="ui-g-12">
<span class="md-inputfield"> <span class="md-inputfield">
<input type="password" <input type="password"
id="confirmPw" id="pwConfirm"
autocomplete="off" placeholder="confirm password" autocomplete="off" placeholder="confirm password"
formControlName="confirmPw" formControlName="pwConfirm"
required class="ui-inputtext ui-corner-all ui-state-default ui-widget"> required class="ui-inputtext ui-corner-all ui-state-default ui-widget">
</span> </span>
<div *ngIf="formErrors.confirmPw" class="help is-danger"> <div *ngIf="pwConfirm.touched && !pwConfirm.valid" class="ui-message ui-messages-error ui-corner-all">
{{ formErrors.confirmPw }} Not matched password
</div> </div>
</div> </div>
<div class="ui-g-12"> <div class="ui-g-12">
<button type="submit" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-left"> <button
[disabled]="!modifyPasswordForm.valid"
type="submit"
class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-left">
<span class="ui-button-icon-left ui-c fa fa-fw ui-icon-person"></span> <span class="ui-button-icon-left ui-c fa fa-fw ui-icon-person"></span>
<span class="ui-button-text ui-c">Confirm</span> <span class="ui-button-text ui-c">Confirm</span>
</button> </button>
<a href="javascript:void(0)" (click)="signin.emit()">Signin</a> <a style="cursor: pointer" (click)="onSignin()">Signin</a>
</div> </div>
</div> </div>
</div> </div>
@ -48,3 +51,7 @@
</form> </form>
</div> </div>
</div> </div>
<div class="ui-g" *ngIf="!member">
Password Modify Complete
</div>

View File

@ -1,5 +1,6 @@
import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core'; import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms'; import {FormGroup, FormBuilder, Validators, FormControl, ValidationErrors, AbstractControl} from '@angular/forms';
import {Member} from '@overflow/commons-typescript/model/member';
@Component({ @Component({
selector: 'of-member-modify-password', selector: 'of-member-modify-password',
@ -7,14 +8,14 @@ import { FormGroup, FormBuilder, Validators } from '@angular/forms';
}) })
export class MemberModifyPasswordComponent implements OnInit { export class MemberModifyPasswordComponent implements OnInit {
@Input() token: string; @Input() token: string;
@Input() member: Member;
@Output() modifyPassword = new EventEmitter<{token: string, password: string, confirmPassword: string}>(); @Output() modifyPassword = new EventEmitter<{token: string, password: string, confirmPassword: string}>();
@Output() signin = new EventEmitter(); @Output() signin = new EventEmitter();
modifyPasswordForm: FormGroup; modifyPasswordForm: FormGroup;
formErrors = { password: AbstractControl;
'pw': '', pwConfirm: AbstractControl;
'confirmPw': ''
};
constructor( constructor(
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
@ -26,26 +27,46 @@ export class MemberModifyPasswordComponent implements OnInit {
initForm() { initForm() {
this.modifyPasswordForm = this.formBuilder.group({ this.modifyPasswordForm = this.formBuilder.group({
'pw': [ 'password': [
'', '',
[ [
// Validators.required, Validators.required,
Validators.pattern('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{6,}$'),
Validators.minLength(6),
Validators.maxLength(25),
] ]
], ],
'confirmPw': [ 'pwConfirm': [
'', '',
[ [
// Validators.pattern('^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)$'), Validators.compose([
// Validators.minLength(6), Validators.required, this.pwMatchValidator
// Validators.maxLength(25) ])
] ]
], ]
}); });
this.password = this.modifyPasswordForm.controls['password'];
this.pwConfirm = this.modifyPasswordForm.controls['pwConfirm'];
}
pwMatchValidator(control: FormControl): ValidationErrors {
let pw;
if (control.parent) {
pw = control.parent.controls['password'].value;
}
if (control.value !== pw) {
return { notMatched: true };
}
return null;
} }
modifyPasswordFormSubmit() { modifyPasswordFormSubmit() {
const formValue = Object.assign({}, this.modifyPasswordForm.value); const formValue = Object.assign({}, this.modifyPasswordForm.value);
this.modifyPassword.emit({token: this.token, password: formValue.pw, confirmPassword: formValue.confirmPw}); this.modifyPassword.emit({token: this.token, password: formValue.pw, confirmPassword: formValue.confirmPw});
} }
onSignin() {
this.signin.emit();
}
} }

View File

@ -1,6 +1,6 @@
<div class="ui-g"> <div class="ui-g" *ngIf="!member">
<div class="ui-g-12"> <div class="ui-g-12">
<form [formGroup]="resetPasswordForm" (ngSubmit)="resetPasswordFormSubmit()"> <form [formGroup]="resetPasswordForm" (ngSubmit)="resetPasswordSubmit()">
<table class="login-table"> <table class="login-table">
<tr> <tr>
<td> <td>
@ -20,14 +20,16 @@
</div> </div>
<div class="ui-g-12"> <div class="ui-g-12">
<button type="submit" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-left"> <button
[disabled]="!resetPasswordForm.valid"
type="submit" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-left">
<span class="ui-button-icon-left ui-c fa fa-fw ui-icon-cached"></span> <span class="ui-button-icon-left ui-c fa fa-fw ui-icon-cached"></span>
<span class="ui-button-text ui-c">Reset Password</span> <span class="ui-button-text ui-c">Reset Password</span>
</button> </button>
<a href="/auth/signin" >Sign In</a> <a style="cursor: pointer" (click)="onSignin()">Sign In</a>
| |
<a href="/auth/signup" >Sign Up</a> <a style="cursor: pointer" (click)="onSignup()">Sign Up</a>
</div> </div>
</div> </div>
</div> </div>
@ -38,3 +40,6 @@
</div> </div>
</div> </div>
<div class="ui-g" *ngIf="member">
I sent an authentication mail to the mail address you registered. Please check and change your password.
</div>

View File

@ -1,5 +1,16 @@
import { Component, OnInit, Output, EventEmitter } from '@angular/core'; import {
import {FormGroup, FormBuilder, Validators, AbstractControl} from '@angular/forms'; Component,
OnInit,
Output,
EventEmitter, Input
} from '@angular/core';
import {
FormGroup,
FormBuilder,
Validators,
AbstractControl
} from '@angular/forms';
import {Member} from '@overflow/commons-typescript/model/member';
@Component({ @Component({
selector: 'of-member-reset-password', selector: 'of-member-reset-password',
@ -7,6 +18,10 @@ import {FormGroup, FormBuilder, Validators, AbstractControl} from '@angular/form
}) })
export class MemberResetPasswordComponent implements OnInit { export class MemberResetPasswordComponent implements OnInit {
@Output() resetPassword = new EventEmitter<string>(); @Output() resetPassword = new EventEmitter<string>();
@Output() signin = new EventEmitter();
@Output() signup = new EventEmitter();
@Input() member: Member;
resetPasswordForm: FormGroup; resetPasswordForm: FormGroup;
email: AbstractControl; email: AbstractControl;
@ -28,8 +43,16 @@ export class MemberResetPasswordComponent implements OnInit {
this.email = this.resetPasswordForm.controls['email']; this.email = this.resetPasswordForm.controls['email'];
} }
resetPasswordFormSubmit() { resetPasswordSubmit() {
const formValue = Object.assign({}, this.resetPasswordForm.value); const formValue = Object.assign({}, this.resetPasswordForm.value);
this.resetPassword.emit(formValue.email); this.resetPassword.emit(formValue.email);
} }
onSignin() {
this.signin.emit();
}
onSignup() {
this.signup.emit();
}
} }

View File

@ -1,6 +1,7 @@
<of-member-modify-password <of-member-modify-password
[token]="token" [token]="token"
(modifyPassword)="modifyPassword($event)" (modifyPassword)="modifyPassword($event)"
(signin)="signin" (signin)="onSignin()"
[member]="member$ | async"
> >
</of-member-modify-password> </of-member-modify-password>

View File

@ -1,10 +1,10 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router'; import {select, Store} from '@ngrx/store';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { select, Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import * as MemberEntityStore from '../store/entity/member'; import * as MemberEntityStore from '../store/entity/member';
import { MemberModifyPasswordContainerSelector } from '../store';
import { Observable } from 'rxjs';
import { Member } from '@overflow/commons-typescript/model/member';
@Component({ @Component({
selector: 'of-member-modify-password-container', selector: 'of-member-modify-password-container',
@ -14,15 +14,25 @@ export class MemberModifyPasswordContainerComponent implements OnInit {
@Input() token: string; @Input() token: string;
@Output() signin = new EventEmitter(); @Output() signin = new EventEmitter();
member$: Observable<Member>;
pending$: Observable<boolean>;
error$: Observable<any>;
constructor( constructor(
private store: Store<any>, private store: Store<any>,
) { } ) { }
ngOnInit() { ngOnInit() {
this.member$ = this.store.pipe(select(MemberModifyPasswordContainerSelector.selectMember));
this.pending$ = this.store.pipe(select(MemberModifyPasswordContainerSelector.selectPending));
this.error$ = this.store.pipe(select(MemberModifyPasswordContainerSelector.selectError));
} }
modifyPassword(info: {token: string, password: string, confirmPassword: string}) { modifyPassword(info: {token: string, password: string, confirmPassword: string}) {
this.store.dispatch(new MemberEntityStore.ModifyPassword(info)); this.store.dispatch(new MemberEntityStore.ModifyPassword(info));
} }
onSignin() {
this.signin.emit();
}
} }

View File

@ -1,4 +1,7 @@
<of-member-reset-password <of-member-reset-password
(resetPassword)="resetPassword($event)" (resetPassword)="resetPassword($event)"
(signin)="onSignin()"
(signup)="onSignup()"
[member]="member$ | async"
> >
</of-member-reset-password> </of-member-reset-password>

View File

@ -1,24 +1,46 @@
import { Component, OnInit } from '@angular/core'; import {
import { Router } from '@angular/router'; Component, EventEmitter,
import { FormGroup, FormBuilder, Validators } from '@angular/forms'; OnInit,
Output
} from '@angular/core';
import {select, Store} from '@ngrx/store'; import {select, Store} from '@ngrx/store';
import {RPCClientError} from '@loafer/ng-rpc';
import * as MemberEntityStore from '../store/entity/member'; import * as MemberEntityStore from '../store/entity/member';
import { Observable } from 'rxjs';
import { Member } from '@overflow/commons-typescript/model/member';
import { MemberResetPasswordContainerSelector } from '../store';
@Component({ @Component({
selector: 'of-member-reset-password-container', selector: 'of-member-reset-password-container',
templateUrl: './member-reset-password-container.component.html', templateUrl: './member-reset-password-container.component.html',
}) })
export class MemberResetPasswordContainerComponent implements OnInit { export class MemberResetPasswordContainerComponent implements OnInit {
@Output() signin = new EventEmitter();
@Output() signup = new EventEmitter();
member$: Observable<Member>;
pending$: Observable<boolean>;
error$: Observable<any>;
constructor( constructor(
private store: Store<any>, private store: Store<any>,
) { } ) { }
ngOnInit() { ngOnInit() {
this.member$ = this.store.pipe(select(MemberResetPasswordContainerSelector.selectMember));
this.pending$ = this.store.pipe(select(MemberResetPasswordContainerSelector.selectPending));
this.error$ = this.store.pipe(select(MemberResetPasswordContainerSelector.selectError));
} }
resetPassword(email: string) { resetPassword(email: string) {
this.store.dispatch(new MemberEntityStore.ResetPassword(email)); this.store.dispatch(new MemberEntityStore.ResetPassword(email));
} }
onSignin() {
this.signin.emit();
}
onSignup() {
this.signup.emit();
}
} }

View File

@ -12,6 +12,7 @@ export function reducer(state = initialState, action: Actions): State {
switch (action.type) { switch (action.type) {
case ActionType.ModifyPassword: { case ActionType.ModifyPassword: {
return { return {
member: null,
pending: true, pending: true,
error: null, error: null,
}; };
@ -19,6 +20,7 @@ export function reducer(state = initialState, action: Actions): State {
case ActionType.ModifyPasswordSuccess: { case ActionType.ModifyPasswordSuccess: {
return { return {
member: action.payload,
pending: false, pending: false,
error: null, error: null,
}; };
@ -26,6 +28,7 @@ export function reducer(state = initialState, action: Actions): State {
case ActionType.ModifyPasswordFailure: { case ActionType.ModifyPasswordFailure: {
return { return {
member: null,
pending: false, pending: false,
error: action.payload, error: action.payload,
}; };

View File

@ -5,11 +5,13 @@ import { RESTClientError } from '@loafer/ng-rest';
import { Member } from '@overflow/commons-typescript/model/member'; import { Member } from '@overflow/commons-typescript/model/member';
export interface State { export interface State {
member: Member;
pending: boolean; pending: boolean;
error: RESTClientError; error: RESTClientError;
} }
export const initialState: State = { export const initialState: State = {
member: null,
pending: false, pending: false,
error: null, error: null,
}; };
@ -17,6 +19,7 @@ export const initialState: State = {
export function getSelectors(selector: Selector<any, State>) { export function getSelectors(selector: Selector<any, State>) {
return { return {
selectMember: createSelector(selector, (state: State) => state.member),
selectPending: createSelector(selector, (state: State) => state.pending), selectPending: createSelector(selector, (state: State) => state.pending),
selectError: createSelector(selector, (state: State) => state.error), selectError: createSelector(selector, (state: State) => state.error),
}; };

View File

@ -12,6 +12,7 @@ export function reducer(state = initialState, action: Actions): State {
switch (action.type) { switch (action.type) {
case ActionType.ResetPassword: { case ActionType.ResetPassword: {
return { return {
member: null,
pending: true, pending: true,
error: null, error: null,
}; };
@ -19,6 +20,7 @@ export function reducer(state = initialState, action: Actions): State {
case ActionType.ResetPasswordSuccess: { case ActionType.ResetPasswordSuccess: {
return { return {
member: action.payload,
pending: false, pending: false,
error: null, error: null,
}; };
@ -26,6 +28,7 @@ export function reducer(state = initialState, action: Actions): State {
case ActionType.ResetPasswordFailure: { case ActionType.ResetPasswordFailure: {
return { return {
member: null,
pending: false, pending: false,
error: action.payload, error: action.payload,
}; };

View File

@ -5,11 +5,13 @@ import { RESTClientError } from '@loafer/ng-rest';
import { Member } from '@overflow/commons-typescript/model/member'; import { Member } from '@overflow/commons-typescript/model/member';
export interface State { export interface State {
member: Member;
pending: boolean; pending: boolean;
error: RESTClientError; error: RESTClientError;
} }
export const initialState: State = { export const initialState: State = {
member: null,
pending: false, pending: false,
error: null, error: null,
}; };
@ -17,6 +19,7 @@ export const initialState: State = {
export function getSelectors(selector: Selector<any, State>) { export function getSelectors(selector: Selector<any, State>) {
return { return {
selectMember: createSelector(selector, (state: State) => state.member),
selectPending: createSelector(selector, (state: State) => state.pending), selectPending: createSelector(selector, (state: State) => state.pending),
selectError: createSelector(selector, (state: State) => state.error), selectError: createSelector(selector, (state: State) => state.error),
}; };

View File

@ -1,6 +1,6 @@
<div class="ui-g"> <div class="ui-g">
<div class="ui-g-12 ui-md-9 ui-lg-7"> <div class="ui-g-12 ui-md-9 ui-lg-7">
<of-member-modify-password-container></of-member-modify-password-container> <of-member-modify-password-container (signin)="onSignin()"></of-member-modify-password-container>
</div> </div>
<div class="ui-g-12 ui-md-3 ui-lg-5 login-descript"> <div class="ui-g-12 ui-md-3 ui-lg-5 login-descript">
<table class="login-table"> <table class="login-table">
@ -24,4 +24,4 @@
</tr> </tr>
</table> </table>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import {ActivatedRoute, Router} from '@angular/router';
@Component({ @Component({
selector: 'of-pages-modify-password', selector: 'of-pages-modify-password',
@ -9,6 +9,7 @@ export class ModifyPasswordPageComponent implements OnInit {
toenURL: string; toenURL: string;
constructor( constructor(
private router: Router,
private activatedRoute: ActivatedRoute, private activatedRoute: ActivatedRoute,
) { } ) { }
@ -16,4 +17,7 @@ export class ModifyPasswordPageComponent implements OnInit {
this.toenURL = this.activatedRoute.snapshot.queryParams['token']; this.toenURL = this.activatedRoute.snapshot.queryParams['token'];
} }
onSignin() {
this.router.navigate(['auth/signin']);
}
} }

View File

@ -1,6 +1,6 @@
<div class="ui-g"> <div class="ui-g">
<div class="ui-g-12 ui-md-9 ui-lg-7"> <div class="ui-g-12 ui-md-9 ui-lg-7">
<of-member-reset-password-container></of-member-reset-password-container> <of-member-reset-password-container (signin)="onSignin()" (signup)="onSignup()"></of-member-reset-password-container>
</div> </div>
<div class="ui-g-12 ui-md-3 ui-lg-5 login-descript"> <div class="ui-g-12 ui-md-3 ui-lg-5 login-descript">
<table class="login-table"> <table class="login-table">
@ -24,4 +24,4 @@
</tr> </tr>
</table> </table>
</div> </div>
</div> </div>

View File

@ -1,4 +1,5 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import {Router} from '@angular/router';
@Component({ @Component({
selector: 'of-pages-auth-reset-password', selector: 'of-pages-auth-reset-password',
@ -6,9 +7,18 @@ import { Component, OnInit } from '@angular/core';
}) })
export class ResetPasswordPageComponent implements OnInit { export class ResetPasswordPageComponent implements OnInit {
constructor() { } constructor(
private router: Router
) { }
ngOnInit() { ngOnInit() {
} }
onSignin() {
this.router.navigate(['auth/signin']);
}
onSignup() {
this.router.navigate(['auth/signup']);
}
} }