diff --git a/goofy-client/libs/user-profile-shared/src/lib/user-profile.linkrel.ts b/goofy-client/libs/user-profile-shared/src/lib/user-profile.linkrel.ts index 4104372b1212e0fdc02175fe2ed998e8515afd02..73fa1ade46d27383297e8da2b2c3f1a8144cd841 100644 --- a/goofy-client/libs/user-profile-shared/src/lib/user-profile.linkrel.ts +++ b/goofy-client/libs/user-profile-shared/src/lib/user-profile.linkrel.ts @@ -1,3 +1,7 @@ export enum UserProfileListLinkRel { USER_PROFILE_LIST = 'userProfileList' +} + +export enum UserProfileLinkRel { + SETTINGS = 'settings' } \ No newline at end of file diff --git a/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.actions.ts b/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.actions.ts index d2fc5ac15f7e453a36e716e206f934f8921c3d4d..1cdac743abedf7c184be64990a508022b4b3146c 100644 --- a/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.actions.ts +++ b/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.actions.ts @@ -2,7 +2,7 @@ import { ApiError } from '@goofy-client/tech-shared'; import { UserProfileResource } from '@goofy-client/user-profile-shared'; import { ActionCreator, createAction, props } from '@ngrx/store'; import { TypedAction } from '@ngrx/store/src/models'; -import { UserSettingsResource } from '../user-settings.model'; +import { UserSettings, UserSettingsResource } from '../user-settings.model'; //TODO centralize ActionCreate export interface UserSettingsActionCreator<T> extends ActionCreator<string, (props: T) => T & TypedAction<string>> { } @@ -12,10 +12,14 @@ export interface UserProfileAction { currentUser: UserProfileResource } -export interface UserSettingsAction { +export interface LoadUserSettingsAction { userSettings: UserSettingsResource } +export interface SetUserSettingsAction { + userSettings: UserSettings +} + export interface ApiErrorAction { apiError: ApiError } @@ -25,7 +29,7 @@ export const loadUserSettings: UserSettingsActionCreator<UserProfileAction> = cr props<{ currentUser: UserProfileResource }>() ); -export const loadUserSettingsSuccess: UserSettingsActionCreator<UserSettingsAction> = createAction( +export const loadUserSettingsSuccess: UserSettingsActionCreator<LoadUserSettingsAction> = createAction( '[UserSettings/API] Load UserSettings Success', props<{ userSettings: UserSettingsResource }>() ); @@ -34,3 +38,18 @@ export const loadUserSettingsFailure: UserSettingsActionCreator<ApiErrorAction> '[UserSettings/API] Load UserSettings Failure', 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>() +); diff --git a/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.effects.spec.ts b/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.effects.spec.ts index f602d47be70cf997e80aeef86d48116e79934025..42d593703a66d06dcc7a98a56f18d417ac914ace 100644 --- a/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.effects.spec.ts +++ b/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.effects.spec.ts @@ -6,7 +6,7 @@ import { provideMockStore } from '@ngrx/store/testing'; import { NxModule } from '@nrwl/angular'; import { cold, hot } from 'jest-marbles'; 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 { UserSettingsResource } from '../user-settings.model'; import { UserSettingsRepository } from '../user-settings.repository'; @@ -56,5 +56,38 @@ describe('UserSettingsEffects', () => { 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', () => { + + }) }) }); diff --git a/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.effects.ts b/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.effects.ts index a66066ff18dd0af4bdc1f191d8cebe65eee580ca..c375089e75c2931dfba89802db1fbd467b6f62fe 100644 --- a/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.effects.ts +++ b/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.effects.ts @@ -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 })) + )) + ) + ) } diff --git a/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.facade.spec.ts b/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.facade.spec.ts index 502963805b58a64f04e6e97c32a99756dcae9336..d1e0f80f2be8f5d66c262ce53f6cf041f9ac0cac 100644 --- a/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.facade.spec.ts +++ b/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.facade.spec.ts @@ -3,9 +3,9 @@ import { Mock, mock, useFromMock } from '@goofy-client/test-utils'; import { UserProfileResource } from '@goofy-client/user-profile-shared'; import { Store } from '@ngrx/store'; 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 { UserSettingsResource } from '../user-settings.model'; +import { UserSettings, UserSettingsResource } from '../user-settings.model'; import * as UserSettingsActions from './user-settings.actions'; import { UserSettingsFacade } from './user-settings.facade'; import { UserSettingsState } from './user-settings.reducer'; @@ -27,7 +27,7 @@ describe('UserSettingsFacade', () => { }); describe('loadUserSettings', () => { - it("should dispatch 'loadUserSettings'", () => { + it('should dispatch "loadUserSettings"', () => { const currentUser: UserProfileResource = createUserProfileResource(); facade.loadUserSettings(currentUser); @@ -48,4 +48,14 @@ describe('UserSettingsFacade', () => { userSettingsSubj.next(expected); }) }) + + describe('setUserSettings', () => { + it('should dispatch "setUserSettings"', () => { + const userSettings: UserSettings = createUserSettings(); + + facade.setUserSettings(userSettings); + + expect(store.dispatch).toHaveBeenCalledWith(UserSettingsActions.setUserSettings({ userSettings })); + }) + }) }); diff --git a/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.facade.ts b/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.facade.ts index 15f1fc24ea3ac7af91d7951516827431da75e3ba..7fd419459644778fcc0186b3d1ea37600ec40f17 100644 --- a/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.facade.ts +++ b/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.facade.ts @@ -3,7 +3,7 @@ import { StateResource } from '@goofy-client/tech-shared'; import { UserProfileResource } from '@goofy-client/user-profile-shared'; import { Store } from '@ngrx/store'; 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 UserSettingsSelectors from './user-settings.selectors'; @@ -19,4 +19,8 @@ export class UserSettingsFacade { public getUserSettings(): Observable<StateResource<UserSettingsResource>> { return this.store.select(UserSettingsSelectors.userSettings) } + + public setUserSettings(userSettings: UserSettings): void { + this.store.dispatch(UserSettingsAction.setUserSettings({ userSettings })) + } } diff --git a/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.reducer.spec.ts b/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.reducer.spec.ts index 798b1fd91b889ddc770b626d8d83aa93d6e8d5ab..1725f2318ac7ef59c2578a292cc3ea07231c7cbc 100644 --- a/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.reducer.spec.ts +++ b/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.reducer.spec.ts @@ -58,4 +58,28 @@ describe('User Settings Reducer', () => { 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 diff --git a/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.reducer.ts b/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.reducer.ts index e11c32c6facf3c6468a3c161dcd7ed679755e6ad..d85ace2394110d6dfeffee525e151d4404a6d68e 100644 --- a/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.reducer.ts +++ b/goofy-client/libs/user-settings-shared/src/lib/+state/user-settings.reducer.ts @@ -3,7 +3,7 @@ import { createEntityAdapter, EntityAdapter } from '@ngrx/entity'; import { Action, createReducer, on } from '@ngrx/store'; import { UserSettingsResource } from '../user-settings.model'; 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'; @@ -29,7 +29,7 @@ const reducer = createReducer( ...state, userSettings: { ...state.userSettings, loading: true } })), - on(UserSettingsActions.loadUserSettingsSuccess, (state: UserSettingsState, action: UserSettingsAction) => ({ + on(UserSettingsActions.loadUserSettingsSuccess, (state: UserSettingsState, action: LoadUserSettingsAction) => ({ ...state, userSettings: createStateResource<UserSettingsResource>(action.userSettings) })), @@ -37,6 +37,18 @@ const reducer = createReducer( ...state, 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( diff --git a/goofy-client/libs/user-settings-shared/src/lib/user-settings.repository.spec.ts b/goofy-client/libs/user-settings-shared/src/lib/user-settings.repository.spec.ts index a121ce095834a7ab8ec8329fd919511909af7f01..7a05a2693470871083ee7208b779cfcaa863aaf7 100644 --- a/goofy-client/libs/user-settings-shared/src/lib/user-settings.repository.spec.ts +++ b/goofy-client/libs/user-settings-shared/src/lib/user-settings.repository.spec.ts @@ -1,5 +1,11 @@ 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 diff --git a/goofy-client/libs/user-settings-shared/src/lib/user-settings.repository.ts b/goofy-client/libs/user-settings-shared/src/lib/user-settings.repository.ts index 250828f8b802b724541ead58442c5a903ddc6b84..807f4f75ec21350108eb1c5bcb82397328950cbb 100644 --- a/goofy-client/libs/user-settings-shared/src/lib/user-settings.repository.ts +++ b/goofy-client/libs/user-settings-shared/src/lib/user-settings.repository.ts @@ -1,8 +1,8 @@ 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 { Observable } from 'rxjs'; -import { UserSettingsResource } from './user-settings.model'; +import { UserSettings, UserSettingsResource } from './user-settings.model'; @Injectable({ providedIn: 'root' }) export class UserSettingsRepository { @@ -10,6 +10,10 @@ export class UserSettingsRepository { constructor(private resourceFactory: ResourceFactory) { } 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 diff --git a/goofy-client/libs/user-settings-shared/src/lib/user-settings.service.spec.ts b/goofy-client/libs/user-settings-shared/src/lib/user-settings.service.spec.ts index 2df35c2dce1d5dc32814f7ecd2d75af9a279ba75..80d3f205f6a423813177fc4a6c608b2240c40f96 100644 --- a/goofy-client/libs/user-settings-shared/src/lib/user-settings.service.spec.ts +++ b/goofy-client/libs/user-settings-shared/src/lib/user-settings.service.spec.ts @@ -3,8 +3,9 @@ import { mock, Mock, useFromMock } from '@goofy-client/test-utils'; import { UserProfileResource, UserProfileService } from '@goofy-client/user-profile-shared'; import { cold, hot } from 'jest-marbles'; 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 { UserSettings } from './user-settings.model'; import { UserSettingsService } from './user-settings.service'; describe('UserSettingsService', () => { @@ -57,9 +58,13 @@ describe('UserSettingsService', () => { }) - describe('set UserSettings.notificationsSendFor', () => { - it('should call patch method in facade', () => { - // Naming an die Implementierung anpassen/spezifizieren + describe('set UserSettings', () => { + it('should call set method in facade', () => { + const userSettings: UserSettings = createUserSettings(); + + service.setUserSettings(userSettings); + + expect(facade.setUserSettings).toHaveBeenCalledWith(userSettings); }) }) }); diff --git a/goofy-client/libs/user-settings-shared/src/lib/user-settings.service.ts b/goofy-client/libs/user-settings-shared/src/lib/user-settings.service.ts index ee262b3ede1bf664481523502f618923d30b55ee..20fa1ad04f40fece2cd4d5d7b210c34351ec92fb 100644 --- a/goofy-client/libs/user-settings-shared/src/lib/user-settings.service.ts +++ b/goofy-client/libs/user-settings-shared/src/lib/user-settings.service.ts @@ -4,7 +4,7 @@ import { UserProfileService } from '@goofy-client/user-profile-shared'; import { combineLatest, Observable } from 'rxjs'; import { map, startWith, tap } from 'rxjs/operators'; import { UserSettingsFacade } from './+state/user-settings.facade'; -import { UserSettingsResource } from './user-settings.model'; +import { UserSettings, UserSettingsResource } from './user-settings.model'; @Injectable({ providedIn: 'root', }) @@ -21,10 +21,16 @@ export class UserSettingsService { return combineLatest([userProfile$, userSetting$]).pipe( tap(([userProfile, userSettings]) => doIfLoadingRequired(userSettings, () => { - this.userSettingsFacade.loadUserSettings(userProfile.resource) + if (userProfile.resource) { + this.userSettingsFacade.loadUserSettings(userProfile.resource); + } })), map(([, userSettings]) => userSettings), startWith(createEmptyStateResource<UserSettingsResource>(true)) ); } + + setUserSettings(userSettings: UserSettings): void { + this.userSettingsFacade.setUserSettings(userSettings); + } } diff --git a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.spec.ts b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.spec.ts index a3c9f90d4065535ef92ebb960278e17ac66da719..060f014d0d3064ac4b32e385ba1d7d32f464637a 100644 --- a/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.spec.ts +++ b/goofy-client/libs/user-settings/src/lib/user-settings-container/user-settings-container.component.spec.ts @@ -1,12 +1,18 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatMenuModule } from '@angular/material/menu'; import { AppService } from '@goofy-client/app-shared'; 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 { 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 appService = { ...mock(AppService), getDarkMode: () => darkModeSubj }; +const userSettingsService = mock(UserSettingsService); describe('UserSettingsContainerComponent', () => { let component: UserSettingsContainerComponent; @@ -14,13 +20,22 @@ describe('UserSettingsContainerComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [UiModule], - declarations: [UserSettingsContainerComponent], + imports: [MatMenuModule], + declarations: [ + UserSettingsContainerComponent, + MockComponent(UserSettingsDarkmodeComponent), + MockComponent(UserSettingsEmailBenachrichtigungComponent), + MockComponent(IconButtonWithSpinnerComponent) + ], providers: [ { provide: AppService, useValue: appService, }, + { + provide: UserSettingsService, + useValue: userSettingsService + } ], }).compileComponents();