| @@ -336,6 +336,11 @@ | |||||
| "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.2.4.tgz", | "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.2.4.tgz", | ||||
| "integrity": "sha512-jEpglcwMlwdXc/JgvJaJtCSkPMktnFeI0gAZxPrmbJxKVzMZJ2zM582NbW/r6M22pSdNWjcWeg1I2LRg3jQGQA==" | "integrity": "sha512-jEpglcwMlwdXc/JgvJaJtCSkPMktnFeI0gAZxPrmbJxKVzMZJ2zM582NbW/r6M22pSdNWjcWeg1I2LRg3jQGQA==" | ||||
| }, | }, | ||||
| "@ngrx/effects": { | |||||
| "version": "4.1.1", | |||||
| "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-4.1.1.tgz", | |||||
| "integrity": "sha1-y3WLhSeWSyWOpBlR9ZqhROPvn64=" | |||||
| }, | |||||
| "@ngrx/store": { | "@ngrx/store": { | ||||
| "version": "4.1.1", | "version": "4.1.1", | ||||
| "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-4.1.1.tgz", | "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-4.1.1.tgz", | ||||
| @@ -21,6 +21,7 @@ | |||||
| "@angular/platform-browser": "^5.0.0", | "@angular/platform-browser": "^5.0.0", | ||||
| "@angular/platform-browser-dynamic": "^5.0.0", | "@angular/platform-browser-dynamic": "^5.0.0", | ||||
| "@angular/router": "^5.0.0", | "@angular/router": "^5.0.0", | ||||
| "@ngrx/effects": "^4.1.1", | |||||
| "@ngrx/store": "^4.1.1", | "@ngrx/store": "^4.1.1", | ||||
| "bootstrap": "^3.3.7", | "bootstrap": "^3.3.7", | ||||
| "core-js": "^2.4.1", | "core-js": "^2.4.1", | ||||
| @@ -2,6 +2,7 @@ import { BrowserModule } from '@angular/platform-browser'; | |||||
| import { NgModule } from '@angular/core'; | import { NgModule } from '@angular/core'; | ||||
| import { HttpClientModule } from '@angular/common/http'; | import { HttpClientModule } from '@angular/common/http'; | ||||
| import { StoreModule } from '@ngrx/store'; | import { StoreModule } from '@ngrx/store'; | ||||
| import { EffectsModule } from '@ngrx/effects'; | |||||
| import { AppComponent } from './app.component'; | import { AppComponent } from './app.component'; | ||||
| import { AppRoutingModule } from './app-routing.module'; | import { AppRoutingModule } from './app-routing.module'; | ||||
| @@ -10,6 +11,7 @@ import { ShoppingListModule } from './shopping-list/shopping-list.module'; | |||||
| import { AuthModule } from './auth/auth.module'; | import { AuthModule } from './auth/auth.module'; | ||||
| import { CoreModule } from './core/core.module'; | import { CoreModule } from './core/core.module'; | ||||
| import { appReducers } from './ngrx/app.reducers'; | import { appReducers } from './ngrx/app.reducers'; | ||||
| import { AuthEffects } from './auth/ngrx/auth.effects'; | |||||
| @NgModule({ | @NgModule({ | ||||
| declarations: [ | declarations: [ | ||||
| @@ -23,7 +25,8 @@ import { appReducers } from './ngrx/app.reducers'; | |||||
| ShoppingListModule, | ShoppingListModule, | ||||
| AuthModule, | AuthModule, | ||||
| CoreModule, | CoreModule, | ||||
| StoreModule.forRoot(appReducers) | |||||
| StoreModule.forRoot(appReducers), | |||||
| EffectsModule.forRoot([AuthEffects]) | |||||
| ], | ], | ||||
| bootstrap: [AppComponent] | bootstrap: [AppComponent] | ||||
| }) | }) | ||||
| @@ -14,14 +14,14 @@ export class AuthService { | |||||
| firebase.auth().createUserWithEmailAndPassword(email, password) | firebase.auth().createUserWithEmailAndPassword(email, password) | ||||
| .then( | .then( | ||||
| user => { | user => { | ||||
| this.store.dispatch(new AuthActions.Signup()); | |||||
| firebase.auth().currentUser.getIdToken() | firebase.auth().currentUser.getIdToken() | ||||
| .then( | .then( | ||||
| (token: string) => { | (token: string) => { | ||||
| this.store.dispatch(new AuthActions.SetToken(token)); | this.store.dispatch(new AuthActions.SetToken(token)); | ||||
| } | } | ||||
| ); | ); | ||||
| this.store.dispatch(new AuthActions.Signup()); | |||||
| this.router.navigate(['/']); | |||||
| } | } | ||||
| ) | ) | ||||
| .catch( | .catch( | ||||
| @@ -33,14 +33,14 @@ export class AuthService { | |||||
| firebase.auth().signInWithEmailAndPassword(email, password) | firebase.auth().signInWithEmailAndPassword(email, password) | ||||
| .then( | .then( | ||||
| response => { | response => { | ||||
| this.store.dispatch(new AuthActions.Signin()); | |||||
| this.router.navigate(['/']); | |||||
| firebase.auth().currentUser.getIdToken() | firebase.auth().currentUser.getIdToken() | ||||
| .then( | .then( | ||||
| (token: string) => { | (token: string) => { | ||||
| this.store.dispatch(new AuthActions.SetToken(token)); | this.store.dispatch(new AuthActions.SetToken(token)); | ||||
| } | } | ||||
| ); | ); | ||||
| this.store.dispatch(new AuthActions.Signin()); | |||||
| this.router.navigate(['/']); | |||||
| } | } | ||||
| ) | ) | ||||
| .catch( | .catch( | ||||
| @@ -1,10 +1,17 @@ | |||||
| import { Action } from '@ngrx/store'; | import { Action } from '@ngrx/store'; | ||||
| export const TRY_SIGNUP = 'TRY_SIGNUP'; | |||||
| export const SIGNUP = 'SIGNUP'; | export const SIGNUP = 'SIGNUP'; | ||||
| export const SIGNIN = 'SIGNIN'; | export const SIGNIN = 'SIGNIN'; | ||||
| export const LOGOUT = 'LOGOUT'; | export const LOGOUT = 'LOGOUT'; | ||||
| export const SET_TOKEN = 'SET_TOKEN'; | export const SET_TOKEN = 'SET_TOKEN'; | ||||
| export class TrySignup implements Action { | |||||
| readonly type = TRY_SIGNUP; | |||||
| constructor(public payload: {username: string, password: string}) {} | |||||
| } | |||||
| export class Signup implements Action { | export class Signup implements Action { | ||||
| readonly type = SIGNUP; | readonly type = SIGNUP; | ||||
| } | } | ||||
| @@ -23,4 +30,4 @@ export class SetToken implements Action { | |||||
| constructor(public payload: string) {} | constructor(public payload: string) {} | ||||
| } | } | ||||
| export type AuthActions = Signup | Signin | Logout | SetToken; | |||||
| export type AuthActions = TrySignup | Signup | Signin | Logout | SetToken; | |||||
| @@ -0,0 +1,34 @@ | |||||
| import { Injectable } from '@angular/core'; | |||||
| import { Actions, Effect } from '@ngrx/effects'; | |||||
| import 'rxjs/add/operator/map'; | |||||
| import 'rxjs/add/operator/switchMap'; | |||||
| import 'rxjs/add/operator/mergeMap'; | |||||
| import { fromPromise } from 'rxjs/observable/fromPromise'; | |||||
| import * as firebase from 'firebase'; | |||||
| import * as AuthActions from './auth.actions'; | |||||
| import * as fromAuth from './auth.reducers'; | |||||
| @Injectable() | |||||
| export class AuthEffects { | |||||
| @Effect() | |||||
| authSignup = this.actions$.ofType(AuthActions.TRY_SIGNUP) | |||||
| .map((action: AuthActions.TrySignup) => { | |||||
| return action.payload; | |||||
| }) | |||||
| .switchMap((authData: {username: string, password: string}) => { | |||||
| return fromPromise(firebase.auth().createUserWithEmailAndPassword(authData.username, authData.password)); | |||||
| }) | |||||
| .switchMap(() => { | |||||
| return fromPromise(firebase.auth().currentUser.getIdToken()); | |||||
| }) | |||||
| .mergeMap((token: string) => { | |||||
| return [ | |||||
| { type: AuthActions.SIGNUP }, | |||||
| { type: AuthActions.SET_TOKEN, payload: token } | |||||
| ] | |||||
| }); | |||||
| // variable with dollar sign at the end marks an observable | |||||
| constructor(private actions$: Actions) {} | |||||
| } | |||||
| @@ -1,6 +1,9 @@ | |||||
| import { Component, OnInit } from '@angular/core'; | import { Component, OnInit } from '@angular/core'; | ||||
| import { NgForm } from '@angular/forms'; | import { NgForm } from '@angular/forms'; | ||||
| import { AuthService } from '../auth.service'; | |||||
| import { Store } from '@ngrx/store'; | |||||
| import * as fromApp from '../../ngrx/app.reducers'; | |||||
| import * as AuthActions from '../ngrx/auth.actions'; | |||||
| @Component({ | @Component({ | ||||
| selector: 'app-signup', | selector: 'app-signup', | ||||
| @@ -9,7 +12,7 @@ import { AuthService } from '../auth.service'; | |||||
| }) | }) | ||||
| export class SignupComponent implements OnInit { | export class SignupComponent implements OnInit { | ||||
| constructor(private authService: AuthService) { } | |||||
| constructor(private store: Store<fromApp.AppState>) { } | |||||
| ngOnInit() { | ngOnInit() { | ||||
| } | } | ||||
| @@ -17,7 +20,7 @@ export class SignupComponent implements OnInit { | |||||
| onSignup(form: NgForm) { | onSignup(form: NgForm) { | ||||
| const email = form.value.email; | const email = form.value.email; | ||||
| const password = form.value.password; | const password = form.value.password; | ||||
| this.authService.signupUser(email, password); | |||||
| this.store.dispatch(new AuthActions.TrySignup({username: email, password: password})); | |||||
| } | } | ||||
| } | } | ||||