Skip to content

Commit

Permalink
Merge pull request #2 from renantee/course-project
Browse files Browse the repository at this point in the history
Course Project: Recipe Book (Updated)
  • Loading branch information
renantee authored Aug 29, 2020
2 parents 9c15d75 + 288fbc0 commit 5f14792
Show file tree
Hide file tree
Showing 39 changed files with 954 additions and 136 deletions.
16 changes: 16 additions & 0 deletions course-project/.firebase/hosting.ZGlzdFxjb3Vyc2UtcHJvamVjdA.cache
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
6.842b3bf97b65ca10b890.js,1598668129923,01956e12a3074ee7bfe13b636e6d816f8a9b915c3fb7d1d07702d856a1ffead4
3rdpartylicenses.txt,1598668129921,ecfd4dbc50b8e1660a03bf47bc01adf479f451fca856d9109b34d26dbaf54b6b
5.8a46da93dfa60f216d36.js,1598668129951,2b402db2bfcbb6abc469d7e7ecac3a76a06fedb87b895209f7859a1c4165d0f6
7.a4808eed4000423ea7d7.js,1598668129951,066fd95c71988bb323398bf688a8a60cbb6cd9517fc46e46b2bd1531bb3b9381
favicon.ico,1598424675100,2c19690e9587bae12f419b34d2edeecc76808099540a9c9f4ea6194116cfc8f7
1.e475b76bf92aeae6d161.js,1598668129922,a0495470c61c974b1ac44c6de518dd350a88c4c3403fefa552b10fabbafdb659
index.html,1598668130098,d2ce8d1a3facf4272067d812598068a400369606989c580b970a687ce70671b5
runtime.08dd40863cb992ce317e.js,1598668129922,002d8295c789ea73bfaa5f7b8c6b44c57ee30fb85007f62f7a5b99863d57cd03
polyfills.df8df8924122ea727a19.js,1598668129923,94ff262d2f420b31324a4a1c798734ec25b27a36e6efba615dffdfb6411bd923
glyphicons-halflings-regular.5be1347c682810f199c7.eot,1598668129922,ea8dc7fb0dcea3d5190acd81e18d27789cae28d533458579658427c519c314fb
glyphicons-halflings-regular.82b1212e45a2bc35dd73.woff,1598668129922,5545c2bc0e53a582f6817f523b385ccf917c6ff12d5c55bcd9c2ca52666315a6
glyphicons-halflings-regular.be810be3a3e14c682a25.woff2,1598668129922,0561bd0dc33b73a085698d914614f7320f434be3640303c56e344af35e1842c5
glyphicons-halflings-regular.4692b9ec53fd5972caa2.ttf,1598668129922,6e0bd43454180016d5d1f4fc274618fc343593cfa33892858caf5057e3364707
styles.90d2ed0d07e4802478e3.css,1598668129923,92a6d88c69e34af30485fec6f8b2e5edccb8ba163a8803e5ac4851eaed9c2228
glyphicons-halflings-regular.060b2710bdbbe3dfe48b.svg,1598668129922,7d3e7f391c6375ce5e896afb31db29910558d35a469411c21331b6c571826184
main.f2e37ae91ae9035d2a97.js,1598668129923,05f6fe83149ca688f0deeb803ed3fd993dde52b8627b9d3627269e00b915a09c
5 changes: 5 additions & 0 deletions course-project/.firebaserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"projects": {
"default": "ng-course-recipe-book-4ce87"
}
}
16 changes: 16 additions & 0 deletions course-project/firebase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"hosting": {
"public": "dist/course-project",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}
35 changes: 17 additions & 18 deletions course-project/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { RecipesComponent } from './recipes/recipes.component';
import { ShoppingListComponent } from './shopping-list/shopping-list.component';
import { RecipeStartComponent } from './recipes/recipe-start/recipe-start.component';
import { RecipeDetailComponent } from './recipes/recipe-detail/recipe-detail.component';
import { RecipeEditComponent } from './recipes/recipe-edit/recipe-edit.component';
import { Routes, RouterModule, PreloadAllModules } from '@angular/router';

const appRoutes: Routes = [
{ path: '', redirectTo: '/recipes', pathMatch: 'full' },
{ path: 'recipes', component: RecipesComponent, children: [
{ path: '', component: RecipeStartComponent },
{ path: 'new', component: RecipeEditComponent },
{ path: ':id', component: RecipeDetailComponent },
{ path: ':id/edit', component: RecipeEditComponent },
] },
{ path: 'shopping-list', component: ShoppingListComponent },
{
path: 'auth',
loadChildren: () => import('./auth/auth.module').then(m => m.AuthModule)
},
{
path: 'recipes',
loadChildren: () => import('./recipes/recipes.module').then(m => m.RecipesModule)
},
{
path: 'shopping-list',
loadChildren: () => import('./shopping-list/shopping-list.module').then(m => m.ShoppingListModule)
}
];

@NgModule({
imports: [RouterModule.forRoot(appRoutes)],
imports: [
RouterModule.forRoot(appRoutes, { preloadingStrategy: PreloadAllModules })
],
exports: [RouterModule]
})
export class AppRoutingModule {

}
export class AppRoutingModule {}
2 changes: 1 addition & 1 deletion course-project/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<app-header (featureSelected)="onNavigate($event)"></app-header>
<app-header></app-header>
<div class="container">
<div class="row">
<div class="col-md-12">
Expand Down
17 changes: 12 additions & 5 deletions course-project/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import { Component } from '@angular/core';
import { Component, OnInit } from '@angular/core';

import { AuthService } from './auth/auth.service';
import { LoggingService } from './logging.service';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
loadedFeature = 'recipe';
export class AppComponent implements OnInit {
constructor(
private authService: AuthService,
private loggingService: LoggingService
) {}

onNavigate(feature: string) {
this.loadedFeature = feature;
ngOnInit() {
this.authService.autoLogin();
this.loggingService.printLog('Hello from AppComponent ngOnInit');
}
}
44 changes: 12 additions & 32 deletions course-project/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,24 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';
import { HeaderComponent } from './header/header.component';
import { RecipesComponent } from './recipes/recipes.component';
import { RecipeListComponent } from './recipes/recipe-list/recipe-list.component';
import { RecipeDetailComponent } from './recipes/recipe-detail/recipe-detail.component';
import { RecipeItemComponent } from './recipes/recipe-list/recipe-item/recipe-item.component';
import { ShoppingListComponent } from './shopping-list/shopping-list.component';
import { ShoppingEditComponent } from './shopping-list/shopping-edit/shopping-edit.component';
import { DropdownDirective } from './shared/dropdown.directive';
import { ShoppingListService } from './shopping-list/shopping-list.service';
import { AppRoutingModule } from './app-routing.module';
import { RecipeStartComponent } from './recipes/recipe-start/recipe-start.component';
import { RecipeEditComponent } from './recipes/recipe-edit/recipe-edit.component';
import { RecipeService } from './recipes/recipe.service';
import { SharedModule } from './shared/shared.module';
import { CoreModule } from './core.module';
import { LoggingService } from './logging.service';

@NgModule({
declarations: [
AppComponent,
HeaderComponent,
RecipesComponent,
RecipeListComponent,
RecipeDetailComponent,
RecipeItemComponent,
ShoppingListComponent,
ShoppingEditComponent,
DropdownDirective,
RecipeStartComponent,
RecipeEditComponent
],
declarations: [AppComponent, HeaderComponent],
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule,
AppRoutingModule
HttpClientModule,
AppRoutingModule,
SharedModule,
CoreModule
],
providers: [ShoppingListService, RecipeService],
bootstrap: [AppComponent]
bootstrap: [AppComponent],
// providers: [LoggingService]
})
export class AppModule { }
export class AppModule {}
30 changes: 30 additions & 0 deletions course-project/src/app/auth/auth-interceptor.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Injectable } from '@angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpParams
} from '@angular/common/http';
import { take, exhaustMap } from 'rxjs/operators';

import { AuthService } from './auth.service';

@Injectable()
export class AuthInterceptorService implements HttpInterceptor {
constructor(private authService: AuthService) {}

intercept(req: HttpRequest<any>, next: HttpHandler) {
return this.authService.user.pipe(
take(1),
exhaustMap(user => {
if (!user) {
return next.handle(req);
}
const modifiedReq = req.clone({
params: new HttpParams().set('auth', user.token)
});
return next.handle(modifiedReq);
})
);
}
}
55 changes: 55 additions & 0 deletions course-project/src/app/auth/auth.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<ng-template appPlaceholder></ng-template>
<div class="row">
<div class="col-xs-12 col-md-6 col-md-offset-3">
<!-- <div class="alert alert-danger" *ngIf="error">
<p>{{ error }}</p>
</div> -->
<!-- <app-alert
[message]="error"
*ngIf="error"
(close)="onHandleError()"
></app-alert> -->
<div *ngIf="isLoading" style="text-align: center;">
<app-loading-spinner></app-loading-spinner>
</div>
<form #authForm="ngForm" (ngSubmit)="onSubmit(authForm)" *ngIf="!isLoading">
<div class="form-group">
<label for="email">E-Mail</label>
<input
type="email"
id="email"
class="form-control"
ngModel
name="email"
required
email
/>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
type="password"
id="password"
class="form-control"
ngModel
name="password"
required
minlength="6"
/>
</div>
<div>
<button
class="btn btn-primary"
type="submit"
[disabled]="!authForm.valid"
>
{{ isLoginMode ? 'Login' : 'Sign Up' }}
</button>
|
<button class="btn btn-primary" (click)="onSwitchMode()" type="button">
Switch to {{ isLoginMode ? 'Sign Up' : 'Login' }}
</button>
</div>
</form>
</div>
</div>
97 changes: 97 additions & 0 deletions course-project/src/app/auth/auth.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import {
Component,
ComponentFactoryResolver,
ViewChild,
OnDestroy
} from '@angular/core';
import { NgForm } from '@angular/forms';
import { Router } from '@angular/router';
import { Observable, Subscription } from 'rxjs';

import { AuthService, AuthResponseData } from './auth.service';
import { AlertComponent } from '../shared/alert/alert.component';
import { PlaceholderDirective } from '../shared/placeholder/placeholder.directive';

@Component({
selector: 'app-auth',
templateUrl: './auth.component.html'
})
export class AuthComponent implements OnDestroy {
isLoginMode = true;
isLoading = false;
error: string = null;
@ViewChild(PlaceholderDirective, { static: false }) alertHost: PlaceholderDirective;

private closeSub: Subscription;

constructor(
private authService: AuthService,
private router: Router,
private componentFactoryResolver: ComponentFactoryResolver
) {}

onSwitchMode() {
this.isLoginMode = !this.isLoginMode;
}

onSubmit(form: NgForm) {
if (!form.valid) {
return;
}
const email = form.value.email;
const password = form.value.password;

let authObs: Observable<AuthResponseData>;

this.isLoading = true;

if (this.isLoginMode) {
authObs = this.authService.login(email, password);
} else {
authObs = this.authService.signup(email, password);
}

authObs.subscribe(
resData => {
console.log(resData);
this.isLoading = false;
this.router.navigate(['/recipes']);
},
errorMessage => {
console.log(errorMessage);
this.error = errorMessage;
this.showErrorAlert(errorMessage);
this.isLoading = false;
}
);

form.reset();
}

onHandleError() {
this.error = null;
}

ngOnDestroy() {
if (this.closeSub) {
this.closeSub.unsubscribe();
}
}

private showErrorAlert(message: string) {
// const alertCmp = new AlertComponent();
const alertCmpFactory = this.componentFactoryResolver.resolveComponentFactory(
AlertComponent
);
const hostViewContainerRef = this.alertHost.viewContainerRef;
hostViewContainerRef.clear();

const componentRef = hostViewContainerRef.createComponent(alertCmpFactory);

componentRef.instance.message = message;
this.closeSub = componentRef.instance.close.subscribe(() => {
this.closeSub.unsubscribe();
hostViewContainerRef.clear();
});
}
}
Loading

0 comments on commit 5f14792

Please sign in to comment.