added the login-implementation from the article
authorKai Moritz <kai@juplo.de>
Sun, 29 Jun 2025 11:51:49 +0000 (13:51 +0200)
committerKai Moritz <kai@juplo.de>
Sat, 6 Sep 2025 10:30:14 +0000 (12:30 +0200)
link: https://medium.com/@tranan.aptech/building-a-secure-login-system-with-angular-and-ngrx-a-step-by-step-guide-b1987cdd5626[article
src/app/store/login.actions.ts [new file with mode: 0644]
src/app/store/login.effects.ts [new file with mode: 0644]
src/app/store/login.reducers.ts [new file with mode: 0644]
src/app/store/login.selectors.ts [new file with mode: 0644]

diff --git a/src/app/store/login.actions.ts b/src/app/store/login.actions.ts
new file mode 100644 (file)
index 0000000..784df9c
--- /dev/null
@@ -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 (file)
index 0000000..7ceb864
--- /dev/null
@@ -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 (file)
index 0000000..903c45a
--- /dev/null
@@ -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 (file)
index 0000000..1ebe7e3
--- /dev/null
@@ -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
+);