Skip to content
Snippets Groups Projects
Commit ef4ee074 authored by OZGCloud's avatar OZGCloud
Browse files

OZG-2626 OZG-2886 setUserSettings() implementieren (WIP)

Bei Effects und Reducer gehts weiter..
parent 2ebdb904
No related branches found
No related tags found
No related merge requests found
Showing
with 174 additions and 23 deletions
export enum UserProfileListLinkRel { export enum UserProfileListLinkRel {
USER_PROFILE_LIST = 'userProfileList' USER_PROFILE_LIST = 'userProfileList'
} }
export enum UserProfileLinkRel {
SETTINGS = 'settings'
}
\ No newline at end of file
...@@ -2,7 +2,7 @@ import { ApiError } from '@goofy-client/tech-shared'; ...@@ -2,7 +2,7 @@ import { ApiError } from '@goofy-client/tech-shared';
import { UserProfileResource } from '@goofy-client/user-profile-shared'; import { UserProfileResource } from '@goofy-client/user-profile-shared';
import { ActionCreator, createAction, props } from '@ngrx/store'; import { ActionCreator, createAction, props } from '@ngrx/store';
import { TypedAction } from '@ngrx/store/src/models'; import { TypedAction } from '@ngrx/store/src/models';
import { UserSettingsResource } from '../user-settings.model'; import { UserSettings, UserSettingsResource } from '../user-settings.model';
//TODO centralize ActionCreate //TODO centralize ActionCreate
export interface UserSettingsActionCreator<T> extends ActionCreator<string, (props: T) => T & TypedAction<string>> { } export interface UserSettingsActionCreator<T> extends ActionCreator<string, (props: T) => T & TypedAction<string>> { }
...@@ -12,10 +12,14 @@ export interface UserProfileAction { ...@@ -12,10 +12,14 @@ export interface UserProfileAction {
currentUser: UserProfileResource currentUser: UserProfileResource
} }
export interface UserSettingsAction { export interface LoadUserSettingsAction {
userSettings: UserSettingsResource userSettings: UserSettingsResource
} }
export interface SetUserSettingsAction {
userSettings: UserSettings
}
export interface ApiErrorAction { export interface ApiErrorAction {
apiError: ApiError apiError: ApiError
} }
...@@ -25,7 +29,7 @@ export const loadUserSettings: UserSettingsActionCreator<UserProfileAction> = cr ...@@ -25,7 +29,7 @@ export const loadUserSettings: UserSettingsActionCreator<UserProfileAction> = cr
props<{ currentUser: UserProfileResource }>() props<{ currentUser: UserProfileResource }>()
); );
export const loadUserSettingsSuccess: UserSettingsActionCreator<UserSettingsAction> = createAction( export const loadUserSettingsSuccess: UserSettingsActionCreator<LoadUserSettingsAction> = createAction(
'[UserSettings/API] Load UserSettings Success', '[UserSettings/API] Load UserSettings Success',
props<{ userSettings: UserSettingsResource }>() props<{ userSettings: UserSettingsResource }>()
); );
...@@ -34,3 +38,18 @@ export const loadUserSettingsFailure: UserSettingsActionCreator<ApiErrorAction> ...@@ -34,3 +38,18 @@ export const loadUserSettingsFailure: UserSettingsActionCreator<ApiErrorAction>
'[UserSettings/API] Load UserSettings Failure', '[UserSettings/API] Load UserSettings Failure',
props<ApiErrorAction>() props<ApiErrorAction>()
); );
export const setUserSettings: UserSettingsActionCreator<SetUserSettingsAction> = createAction(
'[UserSettings] Set UserSettings',
props<{ userSettings: UserSettings }>()
);
export const setUserSettingsSuccess: UserSettingsActionCreator<LoadUserSettingsAction> = createAction(
'[UserSettings/API] Set UserSettings Success',
props<{ userSettings: UserSettingsResource }>()
);
export const setUserSettingsFailure: UserSettingsActionCreator<ApiErrorAction> = createAction(
'[UserSettings/API] Set UserSettings Failure',
props<ApiErrorAction>()
);
...@@ -6,7 +6,7 @@ import { provideMockStore } from '@ngrx/store/testing'; ...@@ -6,7 +6,7 @@ import { provideMockStore } from '@ngrx/store/testing';
import { NxModule } from '@nrwl/angular'; import { NxModule } from '@nrwl/angular';
import { cold, hot } from 'jest-marbles'; import { cold, hot } from 'jest-marbles';
import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile'; import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile';
import { createUserSettingsResource } from 'libs/user-settings-shared/test/user-settings'; import { createUserSettings, createUserSettingsResource } from 'libs/user-settings-shared/test/user-settings';
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
import { UserSettingsResource } from '../user-settings.model'; import { UserSettingsResource } from '../user-settings.model';
import { UserSettingsRepository } from '../user-settings.repository'; import { UserSettingsRepository } from '../user-settings.repository';
...@@ -56,5 +56,38 @@ describe('UserSettingsEffects', () => { ...@@ -56,5 +56,38 @@ describe('UserSettingsEffects', () => {
const expected = cold('-b', { b: UserSettingsActions.loadUserSettingsSuccess({ userSettings }) }); const expected = cold('-b', { b: UserSettingsActions.loadUserSettingsSuccess({ userSettings }) });
}) })
it('should dispatch error action', () => {
})
})
describe('set user settings', () => {
const userSettingsResource: UserSettingsResource = createUserSettingsResource();
const userSettings = createUserSettings();
const action = UserSettingsActions.setUserSettings({ userSettings });
it('should call repository', () => {
actions = of(action);
effects.setUserSettings$.subscribe();
expect(userSettingsRepository.setUserSettings).toHaveBeenCalledWith(userSettings);
})
it('should dispatch success action', () => {
userSettingsRepository.setUserSettings.mockReturnValue(of(userSettingsResource));
actions = hot('-a', { a: action });
const expected = cold('-b', { b: UserSettingsActions.setUserSettingsSuccess({ userSettings: userSettingsResource })});
expect(effects.setUserSettings$).toBeObservable(expected);
})
it('should dispatch error action', () => {
})
}) })
}); });
...@@ -18,4 +18,13 @@ export class UserSettingsEffects { ...@@ -18,4 +18,13 @@ export class UserSettingsEffects {
)) ))
) )
) )
setUserSettings$ = createEffect(() =>
this.actions$.pipe(
ofType(UserSettingsActions.setUserSettings),
switchMap((action) => this.repository.setUserSettings(action.userSettings).pipe(
map(userSettings => UserSettingsActions.setUserSettingsSuccess({ userSettings }))
))
)
)
} }
...@@ -3,9 +3,9 @@ import { Mock, mock, useFromMock } from '@goofy-client/test-utils'; ...@@ -3,9 +3,9 @@ import { Mock, mock, useFromMock } from '@goofy-client/test-utils';
import { UserProfileResource } from '@goofy-client/user-profile-shared'; import { UserProfileResource } from '@goofy-client/user-profile-shared';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile'; import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile';
import { createUserSettingsResource } from 'libs/user-settings-shared/test/user-settings'; import { createUserSettings, createUserSettingsResource } from 'libs/user-settings-shared/test/user-settings';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { UserSettingsResource } from '../user-settings.model'; import { UserSettings, UserSettingsResource } from '../user-settings.model';
import * as UserSettingsActions from './user-settings.actions'; import * as UserSettingsActions from './user-settings.actions';
import { UserSettingsFacade } from './user-settings.facade'; import { UserSettingsFacade } from './user-settings.facade';
import { UserSettingsState } from './user-settings.reducer'; import { UserSettingsState } from './user-settings.reducer';
...@@ -27,7 +27,7 @@ describe('UserSettingsFacade', () => { ...@@ -27,7 +27,7 @@ describe('UserSettingsFacade', () => {
}); });
describe('loadUserSettings', () => { describe('loadUserSettings', () => {
it("should dispatch 'loadUserSettings'", () => { it('should dispatch "loadUserSettings"', () => {
const currentUser: UserProfileResource = createUserProfileResource(); const currentUser: UserProfileResource = createUserProfileResource();
facade.loadUserSettings(currentUser); facade.loadUserSettings(currentUser);
...@@ -48,4 +48,14 @@ describe('UserSettingsFacade', () => { ...@@ -48,4 +48,14 @@ describe('UserSettingsFacade', () => {
userSettingsSubj.next(expected); userSettingsSubj.next(expected);
}) })
}) })
describe('setUserSettings', () => {
it('should dispatch "setUserSettings"', () => {
const userSettings: UserSettings = createUserSettings();
facade.setUserSettings(userSettings);
expect(store.dispatch).toHaveBeenCalledWith(UserSettingsActions.setUserSettings({ userSettings }));
})
})
}); });
...@@ -3,7 +3,7 @@ import { StateResource } from '@goofy-client/tech-shared'; ...@@ -3,7 +3,7 @@ import { StateResource } from '@goofy-client/tech-shared';
import { UserProfileResource } from '@goofy-client/user-profile-shared'; import { UserProfileResource } from '@goofy-client/user-profile-shared';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { UserSettingsResource } from '../user-settings.model'; import { UserSettings, UserSettingsResource } from '../user-settings.model';
import * as UserSettingsAction from './user-settings.actions'; import * as UserSettingsAction from './user-settings.actions';
import * as UserSettingsSelectors from './user-settings.selectors'; import * as UserSettingsSelectors from './user-settings.selectors';
...@@ -19,4 +19,8 @@ export class UserSettingsFacade { ...@@ -19,4 +19,8 @@ export class UserSettingsFacade {
public getUserSettings(): Observable<StateResource<UserSettingsResource>> { public getUserSettings(): Observable<StateResource<UserSettingsResource>> {
return this.store.select(UserSettingsSelectors.userSettings) return this.store.select(UserSettingsSelectors.userSettings)
} }
public setUserSettings(userSettings: UserSettings): void {
this.store.dispatch(UserSettingsAction.setUserSettings({ userSettings }))
}
} }
...@@ -58,4 +58,28 @@ describe('User Settings Reducer', () => { ...@@ -58,4 +58,28 @@ describe('User Settings Reducer', () => {
expect(state.userSettings.error).toStrictEqual(apiError); expect(state.userSettings.error).toStrictEqual(apiError);
}) })
}) })
describe('setUserSettings', () => {
describe('on "setUserSettings" action', () => {
it('should set state resource to loading', () => {
})
})
describe('on "setUserSettingsSuccess" action', () => {
it('should set loaded resource', () => {
})
it('should has property "notificationsSendFor"', () => {
})
})
describe('on "setUserSettingsFailure" action', () => {
it('should set API Error', () => {
})
})
})
}) })
\ No newline at end of file
...@@ -3,7 +3,7 @@ import { createEntityAdapter, EntityAdapter } from '@ngrx/entity'; ...@@ -3,7 +3,7 @@ import { createEntityAdapter, EntityAdapter } from '@ngrx/entity';
import { Action, createReducer, on } from '@ngrx/store'; import { Action, createReducer, on } from '@ngrx/store';
import { UserSettingsResource } from '../user-settings.model'; import { UserSettingsResource } from '../user-settings.model';
import * as UserSettingsActions from './user-settings.actions'; import * as UserSettingsActions from './user-settings.actions';
import { ApiErrorAction, UserSettingsAction } from './user-settings.actions'; import { ApiErrorAction, LoadUserSettingsAction, SetUserSettingsAction } from './user-settings.actions';
import { UserSettingsEntity } from './user-settings.models'; import { UserSettingsEntity } from './user-settings.models';
...@@ -29,7 +29,7 @@ const reducer = createReducer( ...@@ -29,7 +29,7 @@ const reducer = createReducer(
...state, ...state,
userSettings: { ...state.userSettings, loading: true } userSettings: { ...state.userSettings, loading: true }
})), })),
on(UserSettingsActions.loadUserSettingsSuccess, (state: UserSettingsState, action: UserSettingsAction) => ({ on(UserSettingsActions.loadUserSettingsSuccess, (state: UserSettingsState, action: LoadUserSettingsAction) => ({
...state, ...state,
userSettings: createStateResource<UserSettingsResource>(action.userSettings) userSettings: createStateResource<UserSettingsResource>(action.userSettings)
})), })),
...@@ -37,6 +37,18 @@ const reducer = createReducer( ...@@ -37,6 +37,18 @@ const reducer = createReducer(
...state, ...state,
userSettings: createErrorStateResource<UserSettingsResource>(action.apiError) userSettings: createErrorStateResource<UserSettingsResource>(action.apiError)
})), })),
on(UserSettingsActions.setUserSettings, (state: UserSettingsState): UserSettingsState => ({
...state,
userSettings: { ...state.userSettings, loading: true }
})),
on(UserSettingsActions.setUserSettingsSuccess, (state: UserSettingsState, action: SetUserSettingsAction) => ({
...state,
userSettings: { ...state.userSettings, loading: true }
})),
on(UserSettingsActions.setUserSettingsFailure, (state: UserSettingsState, action: ApiErrorAction) => ({
...state,
userSettings: createErrorStateResource<UserSettingsResource>(action.apiError)
})),
); );
export function settingsReducer( export function settingsReducer(
......
describe('UserSettingsRepository', () => { describe('UserSettingsRepository', () => {
it.skip('Get user settings of current user', () => {}) it('Get user settings of current user', () => {
})
it('set settings of current user', () => {
})
}) })
\ No newline at end of file
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { UserProfileResource } from '@goofy-client/user-profile-shared'; import { UserProfileLinkRel, UserProfileResource } from '@goofy-client/user-profile-shared';
import { ResourceFactory } from '@ngxp/rest'; import { ResourceFactory } from '@ngxp/rest';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { UserSettingsResource } from './user-settings.model'; import { UserSettings, UserSettingsResource } from './user-settings.model';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class UserSettingsRepository { export class UserSettingsRepository {
...@@ -10,6 +10,10 @@ export class UserSettingsRepository { ...@@ -10,6 +10,10 @@ export class UserSettingsRepository {
constructor(private resourceFactory: ResourceFactory) { } constructor(private resourceFactory: ResourceFactory) { }
public getUserSettings(userProfileResource: UserProfileResource): Observable<UserSettingsResource> { public getUserSettings(userProfileResource: UserProfileResource): Observable<UserSettingsResource> {
return this.resourceFactory.from(userProfileResource).get(); return this.resourceFactory.from(userProfileResource).get(UserProfileLinkRel.SETTINGS);
}
public setUserSettings(userSettings: UserSettings): Observable<UserSettingsResource> {
return null;
} }
} }
\ No newline at end of file
...@@ -3,8 +3,9 @@ import { mock, Mock, useFromMock } from '@goofy-client/test-utils'; ...@@ -3,8 +3,9 @@ import { mock, Mock, useFromMock } from '@goofy-client/test-utils';
import { UserProfileResource, UserProfileService } from '@goofy-client/user-profile-shared'; import { UserProfileResource, UserProfileService } from '@goofy-client/user-profile-shared';
import { cold, hot } from 'jest-marbles'; import { cold, hot } from 'jest-marbles';
import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile'; import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile';
import { createUserSettingsResource } from 'libs/user-settings-shared/test/user-settings'; import { createUserSettings, createUserSettingsResource } from 'libs/user-settings-shared/test/user-settings';
import { UserSettingsFacade } from './+state/user-settings.facade'; import { UserSettingsFacade } from './+state/user-settings.facade';
import { UserSettings } from './user-settings.model';
import { UserSettingsService } from './user-settings.service'; import { UserSettingsService } from './user-settings.service';
describe('UserSettingsService', () => { describe('UserSettingsService', () => {
...@@ -57,9 +58,13 @@ describe('UserSettingsService', () => { ...@@ -57,9 +58,13 @@ describe('UserSettingsService', () => {
}) })
describe('set UserSettings.notificationsSendFor', () => { describe('set UserSettings', () => {
it('should call patch method in facade', () => { it('should call set method in facade', () => {
// Naming an die Implementierung anpassen/spezifizieren const userSettings: UserSettings = createUserSettings();
service.setUserSettings(userSettings);
expect(facade.setUserSettings).toHaveBeenCalledWith(userSettings);
}) })
}) })
}); });
...@@ -4,7 +4,7 @@ import { UserProfileService } from '@goofy-client/user-profile-shared'; ...@@ -4,7 +4,7 @@ import { UserProfileService } from '@goofy-client/user-profile-shared';
import { combineLatest, Observable } from 'rxjs'; import { combineLatest, Observable } from 'rxjs';
import { map, startWith, tap } from 'rxjs/operators'; import { map, startWith, tap } from 'rxjs/operators';
import { UserSettingsFacade } from './+state/user-settings.facade'; import { UserSettingsFacade } from './+state/user-settings.facade';
import { UserSettingsResource } from './user-settings.model'; import { UserSettings, UserSettingsResource } from './user-settings.model';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
}) })
...@@ -21,10 +21,16 @@ export class UserSettingsService { ...@@ -21,10 +21,16 @@ export class UserSettingsService {
return combineLatest([userProfile$, userSetting$]).pipe( return combineLatest([userProfile$, userSetting$]).pipe(
tap(([userProfile, userSettings]) => doIfLoadingRequired(userSettings, () => { tap(([userProfile, userSettings]) => doIfLoadingRequired(userSettings, () => {
this.userSettingsFacade.loadUserSettings(userProfile.resource) if (userProfile.resource) {
this.userSettingsFacade.loadUserSettings(userProfile.resource);
}
})), })),
map(([, userSettings]) => userSettings), map(([, userSettings]) => userSettings),
startWith(createEmptyStateResource<UserSettingsResource>(true)) startWith(createEmptyStateResource<UserSettingsResource>(true))
); );
} }
setUserSettings(userSettings: UserSettings): void {
this.userSettingsFacade.setUserSettings(userSettings);
}
} }
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatMenuModule } from '@angular/material/menu';
import { AppService } from '@goofy-client/app-shared'; import { AppService } from '@goofy-client/app-shared';
import { mock } from '@goofy-client/test-utils'; import { mock } from '@goofy-client/test-utils';
import { UiModule } from '@goofy-client/ui'; import { IconButtonWithSpinnerComponent } from '@goofy-client/ui';
import { UserSettingsService } from '@goofy-client/user-settings-shared';
import { MockComponent } from 'ng-mocks';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
import { UserSettingsContainerComponent } from './user-settings-container.component'; import { UserSettingsContainerComponent } from './user-settings-container.component';
import { UserSettingsDarkmodeComponent } from './user-settings-darkmode/user-settings-darkmode.component';
import { UserSettingsEmailBenachrichtigungComponent } from './user-settings-email-benachrichtigung/user-settings-email-benachrichtigung.component';
const darkModeSubj: BehaviorSubject<boolean> = new BehaviorSubject(false); const darkModeSubj: BehaviorSubject<boolean> = new BehaviorSubject(false);
const appService = { ...mock(AppService), getDarkMode: () => darkModeSubj }; const appService = { ...mock(AppService), getDarkMode: () => darkModeSubj };
const userSettingsService = mock(UserSettingsService);
describe('UserSettingsContainerComponent', () => { describe('UserSettingsContainerComponent', () => {
let component: UserSettingsContainerComponent; let component: UserSettingsContainerComponent;
...@@ -14,13 +20,22 @@ describe('UserSettingsContainerComponent', () => { ...@@ -14,13 +20,22 @@ describe('UserSettingsContainerComponent', () => {
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [UiModule], imports: [MatMenuModule],
declarations: [UserSettingsContainerComponent], declarations: [
UserSettingsContainerComponent,
MockComponent(UserSettingsDarkmodeComponent),
MockComponent(UserSettingsEmailBenachrichtigungComponent),
MockComponent(IconButtonWithSpinnerComponent)
],
providers: [ providers: [
{ {
provide: AppService, provide: AppService,
useValue: appService, useValue: appService,
}, },
{
provide: UserSettingsService,
useValue: userSettingsService
}
], ],
}).compileComponents(); }).compileComponents();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment