Skip to content

Commit 5f14792

Browse files
authored
Merge pull request #2 from renantee/course-project
Course Project: Recipe Book (Updated)
2 parents 9c15d75 + 288fbc0 commit 5f14792

39 files changed

+954
-136
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
6.842b3bf97b65ca10b890.js,1598668129923,01956e12a3074ee7bfe13b636e6d816f8a9b915c3fb7d1d07702d856a1ffead4
2+
3rdpartylicenses.txt,1598668129921,ecfd4dbc50b8e1660a03bf47bc01adf479f451fca856d9109b34d26dbaf54b6b
3+
5.8a46da93dfa60f216d36.js,1598668129951,2b402db2bfcbb6abc469d7e7ecac3a76a06fedb87b895209f7859a1c4165d0f6
4+
7.a4808eed4000423ea7d7.js,1598668129951,066fd95c71988bb323398bf688a8a60cbb6cd9517fc46e46b2bd1531bb3b9381
5+
favicon.ico,1598424675100,2c19690e9587bae12f419b34d2edeecc76808099540a9c9f4ea6194116cfc8f7
6+
1.e475b76bf92aeae6d161.js,1598668129922,a0495470c61c974b1ac44c6de518dd350a88c4c3403fefa552b10fabbafdb659
7+
index.html,1598668130098,d2ce8d1a3facf4272067d812598068a400369606989c580b970a687ce70671b5
8+
runtime.08dd40863cb992ce317e.js,1598668129922,002d8295c789ea73bfaa5f7b8c6b44c57ee30fb85007f62f7a5b99863d57cd03
9+
polyfills.df8df8924122ea727a19.js,1598668129923,94ff262d2f420b31324a4a1c798734ec25b27a36e6efba615dffdfb6411bd923
10+
glyphicons-halflings-regular.5be1347c682810f199c7.eot,1598668129922,ea8dc7fb0dcea3d5190acd81e18d27789cae28d533458579658427c519c314fb
11+
glyphicons-halflings-regular.82b1212e45a2bc35dd73.woff,1598668129922,5545c2bc0e53a582f6817f523b385ccf917c6ff12d5c55bcd9c2ca52666315a6
12+
glyphicons-halflings-regular.be810be3a3e14c682a25.woff2,1598668129922,0561bd0dc33b73a085698d914614f7320f434be3640303c56e344af35e1842c5
13+
glyphicons-halflings-regular.4692b9ec53fd5972caa2.ttf,1598668129922,6e0bd43454180016d5d1f4fc274618fc343593cfa33892858caf5057e3364707
14+
styles.90d2ed0d07e4802478e3.css,1598668129923,92a6d88c69e34af30485fec6f8b2e5edccb8ba163a8803e5ac4851eaed9c2228
15+
glyphicons-halflings-regular.060b2710bdbbe3dfe48b.svg,1598668129922,7d3e7f391c6375ce5e896afb31db29910558d35a469411c21331b6c571826184
16+
main.f2e37ae91ae9035d2a97.js,1598668129923,05f6fe83149ca688f0deeb803ed3fd993dde52b8627b9d3627269e00b915a09c

course-project/.firebaserc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"projects": {
3+
"default": "ng-course-recipe-book-4ce87"
4+
}
5+
}

course-project/firebase.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"hosting": {
3+
"public": "dist/course-project",
4+
"ignore": [
5+
"firebase.json",
6+
"**/.*",
7+
"**/node_modules/**"
8+
],
9+
"rewrites": [
10+
{
11+
"source": "**",
12+
"destination": "/index.html"
13+
}
14+
]
15+
}
16+
}
Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
11
import { NgModule } from '@angular/core';
2-
import { Routes, RouterModule } from '@angular/router';
3-
4-
import { RecipesComponent } from './recipes/recipes.component';
5-
import { ShoppingListComponent } from './shopping-list/shopping-list.component';
6-
import { RecipeStartComponent } from './recipes/recipe-start/recipe-start.component';
7-
import { RecipeDetailComponent } from './recipes/recipe-detail/recipe-detail.component';
8-
import { RecipeEditComponent } from './recipes/recipe-edit/recipe-edit.component';
2+
import { Routes, RouterModule, PreloadAllModules } from '@angular/router';
93

104
const appRoutes: Routes = [
115
{ path: '', redirectTo: '/recipes', pathMatch: 'full' },
12-
{ path: 'recipes', component: RecipesComponent, children: [
13-
{ path: '', component: RecipeStartComponent },
14-
{ path: 'new', component: RecipeEditComponent },
15-
{ path: ':id', component: RecipeDetailComponent },
16-
{ path: ':id/edit', component: RecipeEditComponent },
17-
] },
18-
{ path: 'shopping-list', component: ShoppingListComponent },
6+
{
7+
path: 'auth',
8+
loadChildren: () => import('./auth/auth.module').then(m => m.AuthModule)
9+
},
10+
{
11+
path: 'recipes',
12+
loadChildren: () => import('./recipes/recipes.module').then(m => m.RecipesModule)
13+
},
14+
{
15+
path: 'shopping-list',
16+
loadChildren: () => import('./shopping-list/shopping-list.module').then(m => m.ShoppingListModule)
17+
}
1918
];
2019

2120
@NgModule({
22-
imports: [RouterModule.forRoot(appRoutes)],
21+
imports: [
22+
RouterModule.forRoot(appRoutes, { preloadingStrategy: PreloadAllModules })
23+
],
2324
exports: [RouterModule]
2425
})
25-
export class AppRoutingModule {
26-
27-
}
26+
export class AppRoutingModule {}

course-project/src/app/app.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<app-header (featureSelected)="onNavigate($event)"></app-header>
1+
<app-header></app-header>
22
<div class="container">
33
<div class="row">
44
<div class="col-md-12">
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
1-
import { Component } from '@angular/core';
1+
import { Component, OnInit } from '@angular/core';
2+
3+
import { AuthService } from './auth/auth.service';
4+
import { LoggingService } from './logging.service';
25

36
@Component({
47
selector: 'app-root',
58
templateUrl: './app.component.html',
69
styleUrls: ['./app.component.css']
710
})
8-
export class AppComponent {
9-
loadedFeature = 'recipe';
11+
export class AppComponent implements OnInit {
12+
constructor(
13+
private authService: AuthService,
14+
private loggingService: LoggingService
15+
) {}
1016

11-
onNavigate(feature: string) {
12-
this.loadedFeature = feature;
17+
ngOnInit() {
18+
this.authService.autoLogin();
19+
this.loggingService.printLog('Hello from AppComponent ngOnInit');
1320
}
1421
}

course-project/src/app/app.module.ts

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,24 @@
11
import { BrowserModule } from '@angular/platform-browser';
22
import { NgModule } from '@angular/core';
3-
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
4-
3+
import { HttpClientModule } from '@angular/common/http';
54

65
import { AppComponent } from './app.component';
76
import { HeaderComponent } from './header/header.component';
8-
import { RecipesComponent } from './recipes/recipes.component';
9-
import { RecipeListComponent } from './recipes/recipe-list/recipe-list.component';
10-
import { RecipeDetailComponent } from './recipes/recipe-detail/recipe-detail.component';
11-
import { RecipeItemComponent } from './recipes/recipe-list/recipe-item/recipe-item.component';
12-
import { ShoppingListComponent } from './shopping-list/shopping-list.component';
13-
import { ShoppingEditComponent } from './shopping-list/shopping-edit/shopping-edit.component';
14-
import { DropdownDirective } from './shared/dropdown.directive';
15-
import { ShoppingListService } from './shopping-list/shopping-list.service';
167
import { AppRoutingModule } from './app-routing.module';
17-
import { RecipeStartComponent } from './recipes/recipe-start/recipe-start.component';
18-
import { RecipeEditComponent } from './recipes/recipe-edit/recipe-edit.component';
19-
import { RecipeService } from './recipes/recipe.service';
8+
import { SharedModule } from './shared/shared.module';
9+
import { CoreModule } from './core.module';
10+
import { LoggingService } from './logging.service';
2011

2112
@NgModule({
22-
declarations: [
23-
AppComponent,
24-
HeaderComponent,
25-
RecipesComponent,
26-
RecipeListComponent,
27-
RecipeDetailComponent,
28-
RecipeItemComponent,
29-
ShoppingListComponent,
30-
ShoppingEditComponent,
31-
DropdownDirective,
32-
RecipeStartComponent,
33-
RecipeEditComponent
34-
],
13+
declarations: [AppComponent, HeaderComponent],
3514
imports: [
3615
BrowserModule,
37-
FormsModule,
38-
ReactiveFormsModule,
39-
AppRoutingModule
16+
HttpClientModule,
17+
AppRoutingModule,
18+
SharedModule,
19+
CoreModule
4020
],
41-
providers: [ShoppingListService, RecipeService],
42-
bootstrap: [AppComponent]
21+
bootstrap: [AppComponent],
22+
// providers: [LoggingService]
4323
})
44-
export class AppModule { }
24+
export class AppModule {}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Injectable } from '@angular/core';
2+
import {
3+
HttpInterceptor,
4+
HttpRequest,
5+
HttpHandler,
6+
HttpParams
7+
} from '@angular/common/http';
8+
import { take, exhaustMap } from 'rxjs/operators';
9+
10+
import { AuthService } from './auth.service';
11+
12+
@Injectable()
13+
export class AuthInterceptorService implements HttpInterceptor {
14+
constructor(private authService: AuthService) {}
15+
16+
intercept(req: HttpRequest<any>, next: HttpHandler) {
17+
return this.authService.user.pipe(
18+
take(1),
19+
exhaustMap(user => {
20+
if (!user) {
21+
return next.handle(req);
22+
}
23+
const modifiedReq = req.clone({
24+
params: new HttpParams().set('auth', user.token)
25+
});
26+
return next.handle(modifiedReq);
27+
})
28+
);
29+
}
30+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<ng-template appPlaceholder></ng-template>
2+
<div class="row">
3+
<div class="col-xs-12 col-md-6 col-md-offset-3">
4+
<!-- <div class="alert alert-danger" *ngIf="error">
5+
<p>{{ error }}</p>
6+
</div> -->
7+
<!-- <app-alert
8+
[message]="error"
9+
*ngIf="error"
10+
(close)="onHandleError()"
11+
></app-alert> -->
12+
<div *ngIf="isLoading" style="text-align: center;">
13+
<app-loading-spinner></app-loading-spinner>
14+
</div>
15+
<form #authForm="ngForm" (ngSubmit)="onSubmit(authForm)" *ngIf="!isLoading">
16+
<div class="form-group">
17+
<label for="email">E-Mail</label>
18+
<input
19+
type="email"
20+
id="email"
21+
class="form-control"
22+
ngModel
23+
name="email"
24+
required
25+
email
26+
/>
27+
</div>
28+
<div class="form-group">
29+
<label for="password">Password</label>
30+
<input
31+
type="password"
32+
id="password"
33+
class="form-control"
34+
ngModel
35+
name="password"
36+
required
37+
minlength="6"
38+
/>
39+
</div>
40+
<div>
41+
<button
42+
class="btn btn-primary"
43+
type="submit"
44+
[disabled]="!authForm.valid"
45+
>
46+
{{ isLoginMode ? 'Login' : 'Sign Up' }}
47+
</button>
48+
|
49+
<button class="btn btn-primary" (click)="onSwitchMode()" type="button">
50+
Switch to {{ isLoginMode ? 'Sign Up' : 'Login' }}
51+
</button>
52+
</div>
53+
</form>
54+
</div>
55+
</div>
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import {
2+
Component,
3+
ComponentFactoryResolver,
4+
ViewChild,
5+
OnDestroy
6+
} from '@angular/core';
7+
import { NgForm } from '@angular/forms';
8+
import { Router } from '@angular/router';
9+
import { Observable, Subscription } from 'rxjs';
10+
11+
import { AuthService, AuthResponseData } from './auth.service';
12+
import { AlertComponent } from '../shared/alert/alert.component';
13+
import { PlaceholderDirective } from '../shared/placeholder/placeholder.directive';
14+
15+
@Component({
16+
selector: 'app-auth',
17+
templateUrl: './auth.component.html'
18+
})
19+
export class AuthComponent implements OnDestroy {
20+
isLoginMode = true;
21+
isLoading = false;
22+
error: string = null;
23+
@ViewChild(PlaceholderDirective, { static: false }) alertHost: PlaceholderDirective;
24+
25+
private closeSub: Subscription;
26+
27+
constructor(
28+
private authService: AuthService,
29+
private router: Router,
30+
private componentFactoryResolver: ComponentFactoryResolver
31+
) {}
32+
33+
onSwitchMode() {
34+
this.isLoginMode = !this.isLoginMode;
35+
}
36+
37+
onSubmit(form: NgForm) {
38+
if (!form.valid) {
39+
return;
40+
}
41+
const email = form.value.email;
42+
const password = form.value.password;
43+
44+
let authObs: Observable<AuthResponseData>;
45+
46+
this.isLoading = true;
47+
48+
if (this.isLoginMode) {
49+
authObs = this.authService.login(email, password);
50+
} else {
51+
authObs = this.authService.signup(email, password);
52+
}
53+
54+
authObs.subscribe(
55+
resData => {
56+
console.log(resData);
57+
this.isLoading = false;
58+
this.router.navigate(['/recipes']);
59+
},
60+
errorMessage => {
61+
console.log(errorMessage);
62+
this.error = errorMessage;
63+
this.showErrorAlert(errorMessage);
64+
this.isLoading = false;
65+
}
66+
);
67+
68+
form.reset();
69+
}
70+
71+
onHandleError() {
72+
this.error = null;
73+
}
74+
75+
ngOnDestroy() {
76+
if (this.closeSub) {
77+
this.closeSub.unsubscribe();
78+
}
79+
}
80+
81+
private showErrorAlert(message: string) {
82+
// const alertCmp = new AlertComponent();
83+
const alertCmpFactory = this.componentFactoryResolver.resolveComponentFactory(
84+
AlertComponent
85+
);
86+
const hostViewContainerRef = this.alertHost.viewContainerRef;
87+
hostViewContainerRef.clear();
88+
89+
const componentRef = hostViewContainerRef.createComponent(alertCmpFactory);
90+
91+
componentRef.instance.message = message;
92+
this.closeSub = componentRef.instance.close.subscribe(() => {
93+
this.closeSub.unsubscribe();
94+
hostViewContainerRef.clear();
95+
});
96+
}
97+
}

0 commit comments

Comments
 (0)