From: Kai Moritz Date: Sun, 29 Jun 2025 11:51:49 +0000 (+0200) Subject: added the login-implementation from the article X-Git-Url: http://juplo.de/gitweb/?a=commitdiff_plain;h=9f406d35956c71ef8de9d5721616199d1eab72de;p=demos%2Fangular%2Fstored-login added the login-implementation from the article See the link: https://medium.com/@tranan.aptech/building-a-secure-login-system-with-angular-and-ngrx-a-step-by-step-guide-b1987cdd5626[article on medium.com] --- diff --git a/src/app/store/login.actions.ts b/src/app/store/login.actions.ts new file mode 100644 index 0000000..784df9c --- /dev/null +++ b/src/app/store/login.actions.ts @@ -0,0 +1,16 @@ +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 }>() +); diff --git a/src/app/store/login.effects.ts b/src/app/store/login.effects.ts new file mode 100644 index 0000000..7ceb864 --- /dev/null +++ b/src/app/store/login.effects.ts @@ -0,0 +1,23 @@ +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) {} +} diff --git a/src/app/store/login.reducers.ts b/src/app/store/login.reducers.ts new file mode 100644 index 0000000..903c45a --- /dev/null +++ b/src/app/store/login.reducers.ts @@ -0,0 +1,20 @@ +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 })) +); diff --git a/src/app/store/login.selectors.ts b/src/app/store/login.selectors.ts new file mode 100644 index 0000000..1ebe7e3 --- /dev/null +++ b/src/app/store/login.selectors.ts @@ -0,0 +1,18 @@ +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 +);