Added admin page
This commit is contained in:
		
							
								
								
									
										58
									
								
								src/app/admin/admin.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/app/admin/admin.component.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| <div class="w-100"> | ||||
|     <div class="container d-flex align-items-center" style="height: 300px"> | ||||
|         <div class="w-100 text-center"> | ||||
|             <typewriter text="Admin Panel" [delay]="500"></typewriter> | ||||
|         </div> | ||||
|     </div> | ||||
|     <div class="container mb-md-5 p-0 bg-white"> | ||||
|         <div class="p-4"> | ||||
|             <h3>Users</h3> | ||||
|             <table class="table mt-3"> | ||||
|                 <thead> | ||||
|                 <tr> | ||||
|                     <th>First Name</th> | ||||
|                     <th>Last Name</th> | ||||
|                     <th>Email</th> | ||||
|                     <th class="text-center">Admin</th> | ||||
|                 </tr> | ||||
|                 </thead> | ||||
|                 <tbody> | ||||
|                 <tr *ngFor="let user of adminService.users | async"> | ||||
|                     <td>{{user.firstName}}</td> | ||||
|                     <td>{{user.lastName}}</td> | ||||
|                     <td>{{user.email}}</td> | ||||
|                     <td class="text-center"> | ||||
|                         <div class="form-check"> | ||||
|                             <input class="form-check-input" type="checkbox" id="adminCheck" [checked]="user.admin" | ||||
|                                    disabled> | ||||
|                         </div> | ||||
|                     </td> | ||||
|                 </tr> | ||||
|                 </tbody> | ||||
|             </table> | ||||
|         </div> | ||||
|         <div class="p-4"> | ||||
|             <h3>Quotes</h3> | ||||
|             <table class="table mt-3"> | ||||
|                 <thead> | ||||
|                 <tr> | ||||
|                     <th>Quote</th> | ||||
|                 </tr> | ||||
|                 </thead> | ||||
|                 <tbody> | ||||
|                 <tr *ngFor="let quote of store.quotes | async"> | ||||
|                     <td>{{quote.text}}</td> | ||||
|                 </tr> | ||||
|                 <tr> | ||||
|                     <td> | ||||
|                         <a routerLink="">+ Add Quote</a> | ||||
|                     </td> | ||||
|                 </tr> | ||||
|                 </tbody> | ||||
|             </table> | ||||
|         </div> | ||||
|         <footer class="p-1 bg-dark text-center" style="color: grey"> | ||||
|             © 2019 ZaksCode | ||||
|         </footer> | ||||
|     </div> | ||||
| </div> | ||||
							
								
								
									
										11
									
								
								src/app/admin/admin.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/app/admin/admin.component.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| import {Component} from '@angular/core'; | ||||
| import {AdminService} from './admin.service'; | ||||
| import {AppStore} from '../app.store'; | ||||
|  | ||||
| @Component({ | ||||
|     selector: 'admin', | ||||
|     templateUrl: 'admin.component.html' | ||||
| }) | ||||
| export class AdminComponent { | ||||
|     constructor(public adminService: AdminService, public store: AppStore) {} | ||||
| } | ||||
							
								
								
									
										15
									
								
								src/app/admin/admin.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/app/admin/admin.service.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| import {Observable} from 'rxjs'; | ||||
| import {DbUser} from '../models/dbUser'; | ||||
| import {AngularFirestore} from '@angular/fire/firestore'; | ||||
| import {Injectable} from '@angular/core'; | ||||
|  | ||||
| @Injectable({ | ||||
|     providedIn: 'root' | ||||
| }) | ||||
| export class AdminService { | ||||
|     users: Observable<DbUser[]>; | ||||
|  | ||||
|     constructor(private firestore: AngularFirestore) { | ||||
|         this.users = this.firestore.collection<DbUser>('users').valueChanges(); | ||||
|     } | ||||
| } | ||||
| @@ -1 +1,10 @@ | ||||
| <div style="position: absolute; top: 1em; right: 1em"> | ||||
|     <div *ngIf="loggedIn"> | ||||
|         <a routerLink="/admin" class="mr-3">Admin Panel</a> | ||||
|         <a routerLink="" (click)="authService.logout()">Logout</a> | ||||
|     </div> | ||||
|     <div *ngIf="!loggedIn"> | ||||
|         <a routerLink="" (click)="authService.googleLogin()">Login</a> | ||||
|     </div> | ||||
| </div> | ||||
| <router-outlet></router-outlet> | ||||
|   | ||||
| @@ -1,11 +1,20 @@ | ||||
| import {Component} from '@angular/core'; | ||||
| import {AuthService} from './auth.service'; | ||||
| import {ActivatedRoute} from '@angular/router'; | ||||
|  | ||||
| @Component({ | ||||
|     selector: 'app-root', | ||||
|     templateUrl: 'app.component.html' | ||||
| }) | ||||
| export class AppComponent { | ||||
|     loggedIn = false; | ||||
|  | ||||
|     set title(title: string) { | ||||
|         document.getElementsByTagName('title')[0].innerHTML = `Zaks Code${title ? ` - ${title}` : ''}`; | ||||
|     } | ||||
|  | ||||
|     constructor(private route: ActivatedRoute, public authService: AuthService) { | ||||
|         this.route.url.subscribe(() => this.title = ''); // Clear the title on nav event | ||||
|         this.authService.user.subscribe(user => this.loggedIn = !!user); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -12,15 +12,19 @@ import {SlideShowComponent} from './components/slideShow/slideShow.component'; | ||||
| import {environment} from '../environments/environment'; | ||||
| import {AppComponent} from './app.component'; | ||||
| import {AppRouting} from './app.routing'; | ||||
| import {AdminComponent} from './admin/admin.component'; | ||||
| import {AngularFireAuthModule} from '@angular/fire/auth'; | ||||
|  | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|         AdminComponent, | ||||
|         AppComponent, | ||||
|         HomeComponent, | ||||
|         SlideShowComponent, | ||||
|         TypewriterComponent | ||||
|     ], | ||||
|     imports: [ | ||||
|         AngularFireAuthModule, | ||||
|         AngularFireModule.initializeApp(environment.firebase), | ||||
|         AngularFirestoreModule, | ||||
|         AppRouting, | ||||
|   | ||||
| @@ -1,11 +1,14 @@ | ||||
| import {NgModule} from '@angular/core'; | ||||
| import {RouterModule} from '@angular/router'; | ||||
| import {HomeComponent} from './home/home.component'; | ||||
| import {AdminComponent} from './admin/admin.component'; | ||||
| import {AuthService} from './auth.service'; | ||||
|  | ||||
| @NgModule({ | ||||
|     imports: [ | ||||
|         RouterModule.forRoot([ | ||||
|             {path: '', component: HomeComponent}, | ||||
|             {path: 'admin', component: AdminComponent, canActivate: [AuthService]}, | ||||
|             {path: '**', redirectTo: ''} | ||||
|         ]) | ||||
|     ], | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| import {Injectable} from '@angular/core'; | ||||
| import {Observable} from 'rxjs'; | ||||
| import {BehaviorSubject, Observable} from 'rxjs'; | ||||
| import {AngularFirestore} from '@angular/fire/firestore'; | ||||
| import {Quote} from './models/quote'; | ||||
| import {DbUser} from './models/dbUser'; | ||||
|  | ||||
| @Injectable({ | ||||
|     providedIn: 'root' | ||||
| @@ -12,4 +13,13 @@ export class AppStore { | ||||
|     constructor(private firestore: AngularFirestore) { | ||||
|         this.quotes = this.firestore.collection<Quote>('quotes').valueChanges(); | ||||
|     } | ||||
|  | ||||
|     addQuote(text: string) { | ||||
|         return this.firestore.collection<Quote>('quotes').add({text: text}); | ||||
|     } | ||||
|  | ||||
|     async getUser(uid: string) { | ||||
|         let user = await this.firestore.collection<DbUser>('users').doc(uid).get().toPromise(); | ||||
|         return user.data(); | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										41
									
								
								src/app/auth.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/app/auth.service.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| import {Injectable} from '@angular/core'; | ||||
| import {AngularFireAuth} from '@angular/fire/auth'; | ||||
| import {CanActivate, Router} from '@angular/router'; | ||||
| import {BehaviorSubject, Observable} from 'rxjs'; | ||||
| import { auth } from 'firebase'; | ||||
|  | ||||
| import {map} from 'rxjs/operators'; | ||||
| import {User} from './models/user'; | ||||
| import {AppStore} from './app.store'; | ||||
| import {tap} from 'rxjs/internal/operators/tap'; | ||||
| import {filter} from 'rxjs/internal/operators/filter'; | ||||
|  | ||||
| @Injectable({ | ||||
|     providedIn: 'root' | ||||
| }) | ||||
| export class AuthService implements CanActivate { | ||||
|     user = new BehaviorSubject<User>(null); | ||||
|  | ||||
|     constructor(private store: AppStore, private afAuth: AngularFireAuth, private router: Router) { | ||||
|         this.afAuth.user.subscribe(async user => { | ||||
|             this.user.next(user ? <User>Object.assign(await this.store.getUser(user.uid), user): null); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     canActivate(): Observable<boolean> { | ||||
|         return this.user.pipe( | ||||
|             filter(user => !!user), | ||||
|             map(user => !user.isAnonymous), | ||||
|             tap(user => user ? null : this.googleLogin()) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     googleLogin() { | ||||
|         return this.afAuth.auth.signInWithPopup(new auth.GoogleAuthProvider()); | ||||
|     } | ||||
|  | ||||
|     async logout() { | ||||
|         await this.afAuth.auth.signOut(); | ||||
|         this.router.navigate(['/']); | ||||
|     } | ||||
| } | ||||
| @@ -9,8 +9,8 @@ import {filter, map} from 'rxjs/operators'; | ||||
|     styleUrls: ['typewriter.component.scss'] | ||||
| }) | ||||
| export class TypewriterComponent { | ||||
|     readonly delay = 1500; | ||||
|     readonly speed = 100; | ||||
|     @Input() delay = 1500; | ||||
|     @Input() speed = 100; | ||||
|  | ||||
|     @Input() | ||||
|     set text(text: string) { | ||||
|   | ||||
| @@ -18,8 +18,7 @@ | ||||
|                             <div><i class="mr-2 fa fa-map-marker-alt"></i> London Ontario, Canada</div> | ||||
|                             <div><i class="mr-2 fa fa-envelope"></i> <a href="mailto:zaktimson@gmail.com">zaktimson@gmail.com</a> | ||||
|                             </div> | ||||
|                             <div><i class="mr-2 fab fa-github"></i> <a href="https://github.com/ztimson" | ||||
|                                                                        target="_blank">github.com/ztimson</a></div> | ||||
|                             <div><i class="mr-2 fab fa-github"></i> <a href="https://github.com/ztimson" target="_blank">github.com/ztimson</a></div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </mat-card-content> | ||||
|   | ||||
							
								
								
									
										6
									
								
								src/app/models/dbUser.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/app/models/dbUser.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| export interface DbUser { | ||||
|     admin: boolean; | ||||
|     email: string; | ||||
|     firstName: string; | ||||
|     lastName: string; | ||||
| } | ||||
							
								
								
									
										4
									
								
								src/app/models/user.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/app/models/user.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| import {User as FirebaseUser} from 'firebase'; | ||||
| import {DbUser} from './dbUser'; | ||||
|  | ||||
| export interface User extends FirebaseUser, DbUser { } | ||||
		Reference in New Issue
	
	Block a user