--- /dev/null
+import { createAction, props } from '@ngrx/store';
+
+export const login = createAction(
+ '[Login] User Login',
+ props<{ username: string, password: string }>()
+);
+
+export const loginSuccess = createAction(
+ '[Login] Login Success',
+ props<{ token: string }>()
+);
+
+export const loginFailure = createAction(
+ '[Login] Login Failure',
+ props<{ error: string }>()
+);
--- /dev/null
+import { Injectable } from '@angular/core';
+import { Actions, createEffect, ofType } from '@ngrx/effects';
+import { map, catchError, switchMap } from 'rxjs/operators';
+import { of } from 'rxjs';
+import { loginSuccess, loginFailure } from './login.actions';
+import { AuthService } from '../services/auth.service';
+
+@Injectable()
+export class LoginEffects {
+ login$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType('[Login] User Login'),
+ switchMap(({ username, password }) =>
+ this.authService.login(username, password).pipe(
+ map(token => loginSuccess({ token })),
+ catchError(error => of(loginFailure({ error })))
+ )
+ )
+ )
+ );
+
+ constructor(private actions$: Actions, private authService: AuthService) {}
+}
--- /dev/null
+import { createReducer, on } from '@ngrx/store';
+import { login, loginSuccess, loginFailure } from './login.actions';
+
+export interface State {
+ token: string;
+ error: string;
+ isLoading: boolean;
+}
+
+const initialState: State = {
+ token: null,
+ error: null,
+ isLoading: false
+};
+
+export const loginReducers = createReducer(initialState,
+ on(login, state => ({ ...state, isLoading: true })),
+ on(loginSuccess, (state, { token }) => ({ ...state, token, isLoading: false })),
+ on(loginFailure, (state, { error }) => ({ ...state, error, isLoading: false }))
+);
--- /dev/null
+import { createSelector } from '@ngrx/store';
+
+const selectLogin = (state: any) => state.login;
+
+export const selectToken = createSelector(
+ selectLogin,
+ (state) => state.token
+);
+
+export const selectError = createSelector(
+ selectLogin,
+ (state) => state.error
+);
+
+export const selectIsLoading = createSelector(
+ selectLogin,
+ (state) => state.isLoading
+);