This Contain code of the important files that is needed to build a great website using Angular 7 and Firebase. This mini project was especially build to provide a platform to share blogs and views.
Webconn\src\app\core\auth.guard.spec.ts
import { TestBed, async, inject } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AuthGuard } from './auth.guard';
import { AuthService } from './auth.service';
import { NotifyService } from './notify.service';
import { AngularFireAuthModule } from '@angular/fire/auth';
xdescribe('AuthGuard', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
AngularFireAuthModule
],
providers: [
AuthGuard,
{ provide: AuthService, useValue: { afAuth: { } } },
{ provide: NotifyService, useValue: { } }
]
});
});
it('should ...', inject([AuthGuard], (guard: AuthGuard) => {
}));
});
Webconn\src\app\core\auth.guard.spec.ts:
import { Injectable } from '@angular/core';
import {
CanActivate,
ActivatedRouteSnapshot,
RouterStateSnapshot,
Router
} from '@angular/router';
import { Observable } from 'rxjs';
import { map, take, tap } from 'rxjs/operators';
import { AngularFireAuth } from '@angular/fire/auth';
import { AuthService } from './auth.service';
import { NotifyService } from './notify.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(
private auth: AuthService,
private router: Router,
private notify: NotifyService
) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
return this.auth.user.pipe(
take(1),
map(user => !!user),
tap(loggedIn => {
if (!loggedIn) {
console.log('access denied');
this.notify.update('You must be logged in!', 'error');
this.router.navigate(['/login']);
}
})
);
}
}
Webconn\src\app\core\auth.service.spec.ts:
import { TestBed, inject } from '@angular/core/testing';
import { AuthService } from './auth.service';
xdescribe('AuthService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [AuthService]
});
});
it('should be created', inject([AuthService], (service: AuthService) => {
}));
});
Webconn\src\app\core\auth.guard.spec.ts
import { TestBed, async, inject } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AuthGuard } from './auth.guard';
import { AuthService } from './auth.service';
import { NotifyService } from './notify.service';
import { AngularFireAuthModule } from '@angular/fire/auth';
xdescribe('AuthGuard', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
AngularFireAuthModule
],
providers: [
AuthGuard,
{ provide: AuthService, useValue: { afAuth: { } } },
{ provide: NotifyService, useValue: { } }
]
});
});
it('should ...', inject([AuthGuard], (guard: AuthGuard) => {
}));
});
Webconn\src\app\core\auth.guard.spec.ts:
import { Injectable } from '@angular/core';
import {
CanActivate,
ActivatedRouteSnapshot,
RouterStateSnapshot,
Router
} from '@angular/router';
import { Observable } from 'rxjs';
import { map, take, tap } from 'rxjs/operators';
import { AngularFireAuth } from '@angular/fire/auth';
import { AuthService } from './auth.service';
import { NotifyService } from './notify.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(
private auth: AuthService,
private router: Router,
private notify: NotifyService
) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
return this.auth.user.pipe(
take(1),
map(user => !!user),
tap(loggedIn => {
if (!loggedIn) {
console.log('access denied');
this.notify.update('You must be logged in!', 'error');
this.router.navigate(['/login']);
}
})
);
}
}
Webconn\src\app\core\auth.service.spec.ts:
import { TestBed, inject } from '@angular/core/testing';
import { AuthService } from './auth.service';
xdescribe('AuthService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [AuthService]
});
});
it('should be created', inject([AuthService], (service: AuthService) => {
}));
});
Webconn\src\app\core\auth.service.ts:
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { firebase } from '@firebase/app';
import { auth } from 'firebase';
import { AngularFireAuth } from '@angular/fire/auth';
import {
AngularFirestore,
AngularFirestoreDocument
} from '@angular/fire/firestore';
import { NotifyService } from './notify.service';
import { Observable, of } from 'rxjs';
import { switchMap, startWith, tap, filter } from 'rxjs/operators';
interface User {
uid: string;
email?: string | null;
photoURL?: string;
displayName?: string;
}
@Injectable()
export class AuthService {
user: Observable<User | null>;
constructor(
private afAuth: AngularFireAuth,
private afs: AngularFirestore,
private router: Router,
private notify: NotifyService
) {
this.user = this.afAuth.authState.pipe(
switchMap(user => {
if (user) {
return this.afs.doc<User>(`users/${user.uid}`).valueChanges();
} else {
return of(null);
}
})
// tap(user => localStorage.setItem('user', JSON.stringify(user))),
// startWith(JSON.parse(localStorage.getItem('user')))
);
}
////// OAuth Methods /////
googleLogin() {
const provider = new auth.GoogleAuthProvider();
return this.oAuthLogin(provider);
}
githubLogin() {
const provider = new auth.GithubAuthProvider();
return this.oAuthLogin(provider);
}
facebookLogin() {
const provider = new auth.FacebookAuthProvider();
return this.oAuthLogin(provider);
}
twitterLogin() {
const provider = new auth.TwitterAuthProvider();
return this.oAuthLogin(provider);
}
private oAuthLogin(provider: any) {
return this.afAuth.auth
.signInWithPopup(provider)
.then(credential => {
this.notify.update('Welcome to WebConn!!!' , 'success');
return this.updateUserData(credential.user);
})
.catch(error => this.handleError(error));
}
//// Anonymous Auth ////
anonymousLogin() {
return this.afAuth.auth
.signInAnonymously()
.then(credential => {
this.notify.update('Welcome to WebConn!!!', 'success');
return this.updateUserData(credential.user); // if using firestore
})
.catch(error => {
this.handleError(error);
});
}
//// Email/Password Auth ////
emailSignUp(email: string, password: string) {
return this.afAuth.auth
.createUserWithEmailAndPassword(email, password)
.then(credential => {
this.notify.update('Welcome new user to WebConn!!!', 'success');
return this.updateUserData(credential.user); // if using firestore
})
.catch(error => this.handleError(error));
}
emailLogin(email: string, password: string) {
return this.afAuth.auth
.signInWithEmailAndPassword(email, password)
.then(credential => {
this.notify.update('Welcome back!', 'success');
return this.updateUserData(credential.user);
})
.catch(error => this.handleError(error));
}
// Sends email allowing user to reset password
resetPassword(email: string) {
const fbAuth = auth();
return fbAuth
.sendPasswordResetEmail(email)
.then(() => this.notify.update('Password update email sent', 'info'))
.catch(error => this.handleError(error));
}
signOut() {
this.afAuth.auth.signOut().then(() => {
this.router.navigate(['/']);
});
}
// If error, console log and notify user
private handleError(error: Error) {
console.error(error);
this.notify.update(error.message, 'error');
}
// Sets user data to firestore after succesful login
private updateUserData(user: User) {
const userRef: AngularFirestoreDocument<User> = this.afs.doc(
`users/${user.uid}`
);
const data: User = {
uid: user.uid,
email: user.email || null,
displayName: user.displayName || 'nameless user',
photoURL: user.photoURL || 'https://goo.gl/Fz9nrQ'
};
return userRef.set(data);
}
}
Webconn\src\app\core\core.module.spec.ts
import { CoreModule } from './core.module';
describe('CoreModule', () => {
let coreModule: CoreModule;
beforeEach(() => {
coreModule = new CoreModule();
});
it('should create an instance', () => {
expect(coreModule).toBeTruthy();
});
});
Webconn\src\app\core\core.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AuthService } from './auth.service';
import { AuthGuard } from './auth.guard';
import { NotifyService } from './notify.service';
@NgModule({
providers: [AuthService, AuthGuard, NotifyService]
})
export class CoreModule { }
Webconn\src\app\core\notify.service.spec.ts
import { TestBed, inject } from '@angular/core/testing';
import { NotifyService } from './notify.service';
describe('NotifyService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [NotifyService]
});
});
it('should be created', inject([NotifyService], (service: NotifyService) => {
expect(service).toBeTruthy();
}));
});
Webconn\src\app\core\notify.service.spec.ts
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
/// Notify users about errors and other helpful stuff
export interface Msg {
content: string;
style: string;
}
@Injectable()
export class NotifyService {
private _msgSource = new Subject<Msg | null>();
msg = this._msgSource.asObservable();
update(content: string, style: 'error' | 'info' | 'success') {
const msg: Msg = { content, style };
this._msgSource.next(msg);
}
clear() {
this._msgSource.next(null);
}
}
Webconn\src\app\notes\note-detail\note-detail.component.html
<div class="basic-note">
<h3>{{ note.content }}</h3>
<span class="button is-small is-info" (click)='addHeartToNote(note.hearts)'>
Heart <i class="fa fa-heart" style="margin-left: 5px;"></i>
</span>
<span class="button is-small is-danger" (click)='deleteNote(note?.id)'>Delete</span>
<p>This blog has been hearted {{ note.hearts || 0 }} times.</p>
</div>
Webconn\src\app\notes\note-detail\note-detail.component.spec.ts
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NoteDetailComponent } from './note-detail.component';
import { NotesService } from '../notes.service';
import { FormsModule } from '@angular/forms';
xdescribe('NoteDetailComponent', () => {
let component: NoteDetailComponent;
let fixture: ComponentFixture<NoteDetailComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ NoteDetailComponent ],
providers: [ { provide: NotesService, useValue: { }}]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(NoteDetailComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Webconn\src\app\notes\notes-list\notes-list.component.html
<h1>WebConn Blogs</h1>
<hr>
<input [(ngModel)]="content" placeholder="Add your own blog..." class="input" name="note">
<button class="button is-success" (click)="clickHandler()" [disabled]="content?.length < 2 || content?.length > 200">
Add Blog
</button>
<hr>
<div *ngFor="let note of notes | async">
<note-detail [note]="note"></note-detail>
</div>
Webconn\src\app\notes\notes-list\notes-list.component.spec.ts
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NotesListComponent } from './notes-list.component';
xdescribe('NotesListComponent', () => {
let component: NotesListComponent;
let fixture: ComponentFixture<NotesListComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ NotesListComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(NotesListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Webconn\src\app\ui\home-page\home-page.component.html
<h1>Welcome to WebConn</h1>
<p>I am a Progressive Web App (PWA) built with Angular and Firebase.</p>
<h2>About</h2>
<p>
WebConn...A personalised blog creater site is meant for a perpose of connecting the thought of thousands brains
and bringing their ideas under one roof.
<br>
An Angular framework based , Single Page Web-Application connected with non-SQL database Firebase helps us to access and save your data and information in the securest way.
<br>
For the best blogging experience...its always...
<br>
</p>
<h2>
<b>
WebConn
</b>
</h2>
Webconn\src\app\ui\home-page\home-page.component.spec.ts
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HomePageComponent } from './home-page.component';
describe('HomePageComponent', () => {
let component: HomePageComponent;
let fixture: ComponentFixture<HomePageComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HomePageComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HomePageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Webconn\src\app\ui\loading-spinner\loading-spinner.component.html
<div class="spinner">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
Webconn\src\app\ui\loading-spinner\loading-spinner.component.spec.ts
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { LoadingSpinnerComponent } from './loading-spinner.component';
describe('LoadingSpinnerComponent', () => {
let component: LoadingSpinnerComponent;
let fixture: ComponentFixture<LoadingSpinnerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ LoadingSpinnerComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LoadingSpinnerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Webconn\src\app\ui\main-nav\main-nav.component.html
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" routerLink="/">
<img src="assets/images/webconn.png" width="30px" alt="WebConn" /> WebConn
</a>
<a id="navToggle" role="button" class="navbar-burger" (click)="toggleCollapse()" [ngClass]="{'is-active': show}">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div class="navbar-menu" [ngClass]="{'is-active': show}">
<div class="navbar-end">
<a class="navbar-item" routerLink="/login">
Login
</a>
<a class="navbar-item" routerLink="/ssr">
Universal Blogs
</a>
<a class="navbar-item" routerLink="/notes">
Your Blog
</a>
<a class="navbar-item" routerLink="/uploads">
File Uploads
</a>
</div>
</div>
</nav>
Comments
Post a Comment