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