Skip to content

Commit 9f0653f

Browse files
committed
feature: emai/pass auth
1 parent e7095ab commit 9f0653f

File tree

9 files changed

+237
-45
lines changed

9 files changed

+237
-45
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ FireStarter is designed to handle the basic features most Angular+Firebase apps
88
- Realtime Database CRUD Demo
99
- File Uploads to Firebase Storage Demo
1010
- SASS + Bootstrap 4 + FontAwesome
11+
- Reactive Form Validation
1112

1213
## Usage
1314

src/app/app.module.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { BrowserModule } from '@angular/platform-browser';
22
import { NgModule } from '@angular/core';
3-
import { FormsModule } from '@angular/forms';
3+
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
44
import { HttpModule } from '@angular/http';
55
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
66

@@ -16,6 +16,9 @@ import { AuthService } from './core/auth.service';
1616
import { AuthGuard} from './core/auth.guard';
1717
import { UserLoginComponent } from './users/user-login/user-login.component';
1818
import { UserProfileComponent } from './users/user-profile/user-profile.component';
19+
import { UserFormComponent } from './users/user-form/user-form.component';
20+
21+
1922

2023
// FireStarter Items
2124
import { ItemService } from './items/shared/item.service';
@@ -52,11 +55,13 @@ export const firebaseConfig = environment.firebaseConfig;
5255
UploadsListComponent,
5356
UploadDetailComponent,
5457
TopNavComponent,
55-
FooterNavComponent
58+
FooterNavComponent,
59+
UserFormComponent
5660
],
5761
imports: [
5862
BrowserModule,
5963
FormsModule,
64+
ReactiveFormsModule,
6065
HttpModule,
6166
AppRoutingModule,
6267
AngularFireModule.initializeApp(firebaseConfig),

src/app/core/auth.service.ts

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { Injectable } from '@angular/core';
22
import { AngularFireAuth, AngularFireDatabase, FirebaseAuthState, AuthProviders, AuthMethods, AngularFire } from "angularfire2";
33
import { Router } from "@angular/router";
4+
import * as firebase from 'firebase';
5+
6+
export class EmailPasswordCredentials {
7+
email: string;
8+
password: string;
9+
}
410

511

612
@Injectable()
@@ -39,11 +45,11 @@ export class AuthService {
3945

4046
// Returns current user display name or Guest
4147
get currentUserDisplayName(): string {
42-
if (!this.authenticated) { return 'GUEST' }
48+
if (!this.authenticated) { return 'Guest' }
4349

44-
else if (this.currentUserAnonymous) { return 'ANONYMOUS' }
50+
else if (this.currentUserAnonymous) { return 'Anonymous' }
4551

46-
else { return this.authState.auth.displayName || 'OAUTH USER' }
52+
else { return this.authState.auth.displayName || 'User without a Name' }
4753

4854
}
4955

@@ -83,20 +89,46 @@ export class AuthService {
8389
.catch(error => console.log(error));
8490
}
8591

86-
//// Email/Password Auth ////
87-
88-
// emailSignUp(email: string, password: string): firebase.Promise<FirebaseAuthState> {
89-
// return this.af.auth.createUser({ email, password })
90-
// .then(() => this.writeUserData())
91-
// .catch(error => console.log(error));
92-
// }
92+
// anonymousUpgrade(): firebase.Promise<FirebaseAuthState> {
93+
//
94+
// let anonId = this.currentUserId
9395
//
94-
// emailLogin(email: string, password: string): firebase.Promise<FirebaseAuthState> {
95-
// return this.af.auth.login({email, password})
96-
// .then(() => this.writeUserData())
97-
// .catch(error => console.log(error));
96+
// // Login with google
97+
// return this.googleLogin().then( () => {
98+
// // get the data snapshot from anonymous account account
99+
// this.db.object(anonId).subscribe(snapshot => {
100+
// // map the anonymous user data to the new account.
101+
// this.db.object(this.currentUserId).update(snapshot)
102+
// })
103+
// });
98104
// }
99105

106+
//// Email/Password Auth ////
107+
108+
emailSignUp(credentials: EmailPasswordCredentials): firebase.Promise<FirebaseAuthState> {
109+
return this.af.auth.createUser(credentials)
110+
.then(() => this.updateUserData())
111+
.catch(error => console.log(error));
112+
}
113+
114+
emailLogin(credentials: EmailPasswordCredentials): firebase.Promise<FirebaseAuthState> {
115+
return this.af.auth.login(credentials,
116+
{ provider: AuthProviders.Password,
117+
method: AuthMethods.Password
118+
})
119+
.then(() => this.updateUserData())
120+
.catch(error => console.log(error));
121+
}
122+
123+
// Sends email allowing user to reset password
124+
resetPassword(email: string) {
125+
var auth = firebase.auth();
126+
127+
return auth.sendPasswordResetEmail(email)
128+
.then(() => console.log("email sent"))
129+
.catch((error) => console.log(error))
130+
}
131+
100132

101133
//// Sign Out ////
102134

src/app/uploads/upload-form/upload-form.component.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ export class UploadFormComponent implements OnInit {
2222
this.selectedFiles = event.target.files;
2323
}
2424

25-
// upload() {
26-
// let file = this.selectedFiles.item(0)
27-
// this.upSvc.singleUpload(file)
28-
// }
29-
3025
uploadSingle() {
3126
let file = this.selectedFiles.item(0)
3227
this.currentUpload = new Upload(file);
@@ -43,11 +38,5 @@ export class UploadFormComponent implements OnInit {
4338
}
4439

4540

46-
// uploadMulti() {
47-
// let files = this.selectedFiles
48-
// this.upSvc.multiUpload(files);
49-
// }
50-
51-
5241

5342
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
2+
<form [formGroup]="userForm" *ngIf="newUser" (ngSubmit)="signup()">
3+
4+
<h3>New User Signup</h3>
5+
<p class="btn btn-sm btn-secondary" (click)="toggleForm()">Already Registered?</p>
6+
<hr>
7+
8+
<label for="email">Email</label>
9+
<input type="email" id="email" class="form-control"
10+
formControlName="email" required >
11+
12+
<div *ngIf="formErrors.email" class="alert alert-danger">
13+
{{ formErrors.email }}
14+
</div>
15+
16+
<label for="password">Password</label>
17+
<input type="password" id="password" class="form-control"
18+
formControlName="password" required >
19+
20+
<div *ngIf="formErrors.password" class="alert alert-danger">
21+
{{ formErrors.password }}
22+
</div>
23+
24+
<button type="submit" class="btn btn-block btn-primary" [disabled]="!userForm.valid">Submit</button>
25+
26+
<span *ngIf="userForm.valid" class="text-success">Form is valid</span>
27+
28+
29+
</form>
30+
31+
32+
<form [formGroup]="userForm" *ngIf="!newUser" (ngSubmit)="login()">
33+
34+
<h3>Existing User Login</h3>
35+
<p class="btn btn-sm btn-secondary" (click)="toggleForm()">New User?</p>
36+
<hr>
37+
38+
<label for="email">Email</label>
39+
<input type="email" id="email" class="form-control"
40+
formControlName="email" required >
41+
42+
<div *ngIf="formErrors.email" class="alert alert-danger">
43+
{{ formErrors.email }}
44+
</div>
45+
46+
<label for="password">Password</label>
47+
<input type="password" id="password" class="form-control"
48+
formControlName="password" required >
49+
50+
<div *ngIf="formErrors.password" class="alert alert-danger">
51+
{{ formErrors.password }}
52+
</div>
53+
54+
<button type="submit" class="btn btn-block btn-primary" [disabled]="!userForm.valid">Submit</button>
55+
56+
<span *ngIf="userForm.valid" class="text-success">Form Looks Valid</span>
57+
58+
<p *ngIf="!passReset && userForm.controls.email.valid" class="btn btn-sm btn-secondary" (click)="resetPassword()">Reset Password for {{userForm.value.email}}?</p>
59+
<p *ngIf="passReset" class="text-warning">Reset requested. Check your email instructions.</p>
60+
61+
62+
</form>

src/app/users/user-form/user-form.component.scss

Whitespace-only changes.
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { Component, OnInit } from '@angular/core';
2+
import { AuthService } from "../../core/auth.service";
3+
import { ReactiveFormsModule, FormGroup, FormBuilder, Validators } from '@angular/forms';
4+
5+
@Component({
6+
selector: 'user-form',
7+
templateUrl: './user-form.component.html',
8+
styleUrls: ['./user-form.component.scss']
9+
})
10+
export class UserFormComponent implements OnInit {
11+
12+
userForm: FormGroup;
13+
newUser: boolean = true; // to toggle login or signup form
14+
passReset: boolean = false; // set to true when password reset is triggered
15+
16+
constructor(private fb: FormBuilder, private auth: AuthService) {}
17+
18+
ngOnInit(): void {
19+
this.buildForm();
20+
}
21+
22+
toggleForm() {
23+
this.newUser = !this.newUser;
24+
}
25+
26+
signup(): void {
27+
this.auth.emailSignUp(this.userForm.value)
28+
}
29+
30+
login(): void {
31+
this.auth.emailLogin(this.userForm.value)
32+
}
33+
34+
resetPassword() {
35+
this.auth.resetPassword(this.userForm.value['email'])
36+
.then(() => this.passReset = true)
37+
}
38+
39+
buildForm(): void {
40+
this.userForm = this.fb.group({
41+
'email': ['', [
42+
Validators.required,
43+
Validators.email
44+
]
45+
],
46+
'password': ['', [
47+
Validators.pattern('^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)$'),
48+
Validators.minLength(6),
49+
Validators.maxLength(25)
50+
]
51+
],
52+
});
53+
54+
this.userForm.valueChanges.subscribe(data => this.onValueChanged(data));
55+
this.onValueChanged(); // reset validation messages
56+
}
57+
58+
// Updates validation state on form changes.
59+
onValueChanged(data?: any) {
60+
if (!this.userForm) { return; }
61+
const form = this.userForm;
62+
for (const field in this.formErrors) {
63+
// clear previous error message (if any)
64+
this.formErrors[field] = '';
65+
const control = form.get(field);
66+
if (control && control.dirty && !control.valid) {
67+
const messages = this.validationMessages[field];
68+
for (const key in control.errors) {
69+
this.formErrors[field] += messages[key] + ' ';
70+
}
71+
}
72+
}
73+
}
74+
75+
formErrors = {
76+
'email': '',
77+
'password': ''
78+
};
79+
80+
validationMessages = {
81+
'email': {
82+
'required': 'Email is required.',
83+
'email': 'Email must be a valid email'
84+
},
85+
'password': {
86+
'required': 'Password is required.',
87+
'pattern': 'Password must be include at one letter and one number.',
88+
'minlength': 'Password must be at least 4 characters long.',
89+
'maxlength': 'Password cannot be more than 40 characters long.',
90+
}
91+
};
92+
93+
}

src/app/users/user-login/user-login.component.html

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,42 @@
11
<div *ngIf="!auth.currentUser; else alreadyLoggedIn">
22

3-
<h3>Anonymous Login</h3>
3+
<h3>Social Login</h3>
44

5-
<button (click)="signInAnonymously()" class="btn btn-block btn-secondary">
6-
<i class="fa fa-user-secret fa-lg"></i> Connect Anonymously
7-
</button>
85

9-
<hr>
6+
<button (click)="signInWithGoogle()" class="btn btn-social btn-block btn-google">
7+
<i class="fa fa-google-plus fa-lg"></i> Connect Google
8+
</button>
109

11-
<h3>Social Login</h3>
10+
<button (click)="signInWithGithub()" class="btn btn-social btn-block btn-github" disabled>
11+
<i class="fa fa-github fa-lg"></i> Connect GitHub
12+
</button>
1213

14+
<button (click)="signInWithFacebook()" class="btn btn-social btn-block btn-facebook" disabled>
15+
<i class="fa fa-facebook fa-lg"></i> Connect Facebook
16+
</button>
1317

14-
<button (click)="signInWithGoogle()" class="btn btn-social btn-block btn-google">
15-
<i class="fa fa-google-plus fa-lg"></i> Connect Google
16-
</button>
18+
<button (click)="signInWithTwitter()" class="btn btn-social btn-block btn-twitter" disabled>
19+
<i class="fa fa-twitter fa-lg"></i> Connect Twitter
20+
</button>
1721

18-
<button (click)="signInWithGithub()" class="btn btn-social btn-block btn-github" disabled>
19-
<i class="fa fa-github fa-lg"></i> Connect GitHub
20-
</button>
22+
<hr>
2123

22-
<button (click)="signInWithFacebook()" class="btn btn-social btn-block btn-facebook" disabled>
23-
<i class="fa fa-facebook fa-lg"></i> Connect Facebook
24-
</button>
24+
<h3>Anonymous Login</h3>
2525

26-
<button (click)="signInWithTwitter()" class="btn btn-social btn-block btn-twitter" disabled>
27-
<i class="fa fa-twitter fa-lg"></i> Connect Twitter
28-
</button>
26+
<button (click)="signInAnonymously()" class="btn btn-block btn-secondary">
27+
<i class="fa fa-user-secret fa-lg"></i> Connect Anonymously
28+
</button>
29+
30+
<hr>
31+
32+
33+
<user-form></user-form>
2934

3035
</div>
3136

37+
38+
39+
3240
<ng-template #alreadyLoggedIn>
3341
<p class="text-success">
3442
Already logged in!

src/app/users/user-login/user-login.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { Component, OnInit } from '@angular/core';
22
import { Router } from "@angular/router";
33
import { AuthService } from "../../core/auth.service";
44

5+
import { ReactiveFormsModule } from '@angular/forms';
6+
57

68
@Component({
79
selector: 'user-login',

0 commit comments

Comments
 (0)