Added admin page
This commit is contained in:
parent
876fdab031
commit
72303335a1
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>
|
<router-outlet></router-outlet>
|
||||||
|
@ -1,11 +1,20 @@
|
|||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
|
import {AuthService} from './auth.service';
|
||||||
|
import {ActivatedRoute} from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: 'app.component.html'
|
templateUrl: 'app.component.html'
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
|
loggedIn = false;
|
||||||
|
|
||||||
set title(title: string) {
|
set title(title: string) {
|
||||||
document.getElementsByTagName('title')[0].innerHTML = `Zaks Code${title ? ` - ${title}` : ''}`;
|
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 {environment} from '../environments/environment';
|
||||||
import {AppComponent} from './app.component';
|
import {AppComponent} from './app.component';
|
||||||
import {AppRouting} from './app.routing';
|
import {AppRouting} from './app.routing';
|
||||||
|
import {AdminComponent} from './admin/admin.component';
|
||||||
|
import {AngularFireAuthModule} from '@angular/fire/auth';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
AdminComponent,
|
||||||
AppComponent,
|
AppComponent,
|
||||||
HomeComponent,
|
HomeComponent,
|
||||||
SlideShowComponent,
|
SlideShowComponent,
|
||||||
TypewriterComponent
|
TypewriterComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
|
AngularFireAuthModule,
|
||||||
AngularFireModule.initializeApp(environment.firebase),
|
AngularFireModule.initializeApp(environment.firebase),
|
||||||
AngularFirestoreModule,
|
AngularFirestoreModule,
|
||||||
AppRouting,
|
AppRouting,
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {RouterModule} from '@angular/router';
|
import {RouterModule} from '@angular/router';
|
||||||
import {HomeComponent} from './home/home.component';
|
import {HomeComponent} from './home/home.component';
|
||||||
|
import {AdminComponent} from './admin/admin.component';
|
||||||
|
import {AuthService} from './auth.service';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forRoot([
|
RouterModule.forRoot([
|
||||||
{path: '', component: HomeComponent},
|
{path: '', component: HomeComponent},
|
||||||
|
{path: 'admin', component: AdminComponent, canActivate: [AuthService]},
|
||||||
{path: '**', redirectTo: ''}
|
{path: '**', redirectTo: ''}
|
||||||
])
|
])
|
||||||
],
|
],
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {Observable} from 'rxjs';
|
import {BehaviorSubject, Observable} from 'rxjs';
|
||||||
import {AngularFirestore} from '@angular/fire/firestore';
|
import {AngularFirestore} from '@angular/fire/firestore';
|
||||||
import {Quote} from './models/quote';
|
import {Quote} from './models/quote';
|
||||||
|
import {DbUser} from './models/dbUser';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@ -12,4 +13,13 @@ export class AppStore {
|
|||||||
constructor(private firestore: AngularFirestore) {
|
constructor(private firestore: AngularFirestore) {
|
||||||
this.quotes = this.firestore.collection<Quote>('quotes').valueChanges();
|
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']
|
styleUrls: ['typewriter.component.scss']
|
||||||
})
|
})
|
||||||
export class TypewriterComponent {
|
export class TypewriterComponent {
|
||||||
readonly delay = 1500;
|
@Input() delay = 1500;
|
||||||
readonly speed = 100;
|
@Input() speed = 100;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set text(text: string) {
|
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-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><i class="mr-2 fa fa-envelope"></i> <a href="mailto:zaktimson@gmail.com">zaktimson@gmail.com</a>
|
||||||
</div>
|
</div>
|
||||||
<div><i class="mr-2 fab fa-github"></i> <a href="https://github.com/ztimson"
|
<div><i class="mr-2 fab fa-github"></i> <a href="https://github.com/ztimson" target="_blank">github.com/ztimson</a></div>
|
||||||
target="_blank">github.com/ztimson</a></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</mat-card-content>
|
</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 { }
|
Loading…
Reference in New Issue
Block a user