Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/app/core/components/header/header.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class HeaderComponent {
label: 'navigation.myProfile',
command: () => this.router.navigate(['my-profile']),
},
{ label: 'navigation.settings', command: () => console.log('Settings') },
{ label: 'navigation.settings', command: () => this.router.navigate(['settings']) },
{ label: 'navigation.logOut', command: () => console.log('Log out') },
];
}
2 changes: 0 additions & 2 deletions src/app/core/constants/ngxs-states.constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { WikiState } from '@osf/features/project/wiki/store/wiki.state';
import { AccountSettingsState } from '@osf/features/settings/account-settings/store/account-settings.state';
import { DeveloperAppsState } from '@osf/features/settings/developer-apps/store';
import { NotificationSubscriptionState } from '@osf/features/settings/notifications/store';
import { ProfileSettingsState } from '@osf/features/settings/profile-settings/store/profile-settings.state';
import { AddonsState, InstitutionsState } from '@shared/stores';
import { LicensesState } from '@shared/stores/licenses';
import { RegionsState } from '@shared/stores/regions';
Expand All @@ -20,7 +19,6 @@ export const STATES = [
UserState,
MyProjectsState,
InstitutionsState,
ProfileSettingsState,
DeveloperAppsState,
AccountSettingsState,
NotificationSubscriptionState,
Expand Down
11 changes: 11 additions & 0 deletions src/app/core/models/user.mapper.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
User,
UserGetResponse,
UserNamesJsonApi,
UserSettings,
UserSettingsGetResponse,
UserSettingsUpdateRequest,
Expand Down Expand Up @@ -46,4 +47,14 @@ export class UserMapper {
},
};
}

static toNamesRequest(name: Partial<User>): UserNamesJsonApi {
return {
full_name: name.fullName ?? '',
given_name: name.givenName ?? '',
family_name: name.familyName ?? '',
middle_names: name.middleNames ?? '',
suffix: name.suffix ?? '',
};
}
}
8 changes: 8 additions & 0 deletions src/app/core/models/user.models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,11 @@ export interface UserSettingsUpdateRequest {
};
};
}

export interface UserNamesJsonApi {
full_name: string;
given_name: string;
family_name: string;
middle_names: string;
suffix: string;
}
13 changes: 13 additions & 0 deletions src/app/core/services/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { map, Observable } from 'rxjs';

import { inject, Injectable } from '@angular/core';

import { ProfileSettingsKey } from '@osf/shared/enums';
import { ProfileSettingsUpdate } from '@osf/shared/models';

import { JsonApiResponse, User, UserGetResponse, UserMapper, UserSettings, UserSettingsGetResponse } from '../models';

import { JsonApiService } from './json-api.service';
Expand Down Expand Up @@ -33,4 +36,14 @@ export class UserService {
.patch<UserSettingsGetResponse>(`${environment.apiUrl}/users/${userId}/settings/`, request)
.pipe(map((response) => UserMapper.fromUserSettingsGetResponse(response)));
}

updateUserProfile(userId: string, key: string, data: ProfileSettingsUpdate): Observable<User> {
const patchedData = key === ProfileSettingsKey.User ? data : { [key]: data };

return this.jsonApiService
.patch<UserGetResponse>(`${environment.apiUrl}/users/${userId}/`, {
data: { type: 'users', id: userId, attributes: patchedData },
})
.pipe(map((response) => UserMapper.fromUserGetResponse(response)));
}
}
28 changes: 26 additions & 2 deletions src/app/core/store/user/user.actions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Education, Employment, Social } from '@osf/shared/models';

import { User, UserSettings } from '../../models';

export class GetCurrentUser {
Expand All @@ -6,7 +8,6 @@ export class GetCurrentUser {

export class SetCurrentUser {
static readonly type = '[User] Set Current User';

constructor(public user: User) {}
}

Expand All @@ -16,9 +17,32 @@ export class GetCurrentUserSettings {

export class UpdateUserSettings {
static readonly type = '[User] Update User Settings';

constructor(
public userId: string,
public updatedUserSettings: UserSettings
) {}
}

export class UpdateProfileSettingsEmployment {
static readonly type = '[Profile Settings] Update Employment';

constructor(public payload: { employment: Employment[] }) {}
}

export class UpdateProfileSettingsEducation {
static readonly type = '[Profile Settings] Update Education';

constructor(public payload: { education: Education[] }) {}
}

export class UpdateProfileSettingsSocialLinks {
static readonly type = '[Profile Settings] Update Social Links';

constructor(public payload: { socialLinks: Partial<Social>[] }) {}
}

export class UpdateProfileSettingsUser {
static readonly type = '[Profile Settings] Update User';

constructor(public payload: { user: Partial<User> }) {}
}
16 changes: 15 additions & 1 deletion src/app/core/store/user/user.model.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
import { AsyncStateModel } from '@shared/models/store';
import { AsyncStateModel } from '@osf/shared/models';

import { User, UserSettings } from '../../models';

export interface UserStateModel {
currentUser: AsyncStateModel<User | null>;
currentUserSettings: AsyncStateModel<UserSettings | null>;
}

export const USER_STATE_INITIAL: UserStateModel = {
currentUser: {
data: null,
isLoading: false,
error: null,
},
currentUserSettings: {
data: null,
isLoading: false,
isSubmitting: false,
error: '',
},
};
45 changes: 24 additions & 21 deletions src/app/core/store/user/user.selectors.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Selector } from '@ngxs/store';

import { UserState, UserStateModel } from '@core/store/user';
import { User, UserSettings } from '@osf/core/models';
import { ProfileSettingsStateModel } from '@osf/features/settings/profile-settings/store';
import { Social } from '@osf/shared/models';
import { Education, Employment, Social } from '@osf/shared/models';

import { UserStateModel } from './user.model';
import { UserState } from './user.state';

export class UserSelectors {
@Selector([UserState])
Expand All @@ -16,24 +17,6 @@ export class UserSelectors {
return state.currentUser.isLoading;
}

@Selector([UserState])
static getProfileSettings(state: UserStateModel): ProfileSettingsStateModel {
return {
education: state.currentUser.data?.education ?? [],
employment: state.currentUser.data?.employment ?? [],
social: state.currentUser.data?.social ?? ({} as Social),
user: {
middleNames: state.currentUser.data?.middleNames ?? '',
suffix: state.currentUser.data?.suffix ?? '',
id: state.currentUser.data?.id ?? '',
fullName: state.currentUser.data?.fullName ?? '',
email: state.currentUser.data?.email ?? '',
givenName: state.currentUser.data?.givenName ?? '',
familyName: state.currentUser.data?.familyName ?? '',
},
} satisfies ProfileSettingsStateModel;
}

@Selector([UserState])
static getCurrentUserSettings(state: UserStateModel): UserSettings | null {
return state.currentUserSettings.data;
Expand All @@ -53,4 +36,24 @@ export class UserSelectors {
static getShareIndexing(state: UserStateModel): boolean | undefined {
return state.currentUser.data?.allowIndexing;
}

@Selector([UserState])
static getUserNames(state: UserStateModel): Partial<User> | null {
return state.currentUser.data;
}

@Selector([UserState])
static getEmployment(state: UserStateModel): Employment[] {
return state.currentUser.data?.employment || [];
}

@Selector([UserState])
static getEducation(state: UserStateModel): Education[] {
return state.currentUser.data?.education || [];
}

@Selector([UserState])
static getSocialLinks(state: UserStateModel): Social | undefined {
return state.currentUser.data?.social;
}
}
132 changes: 115 additions & 17 deletions src/app/core/store/user/user.state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,28 @@ import { tap } from 'rxjs';

import { inject, Injectable } from '@angular/core';

import { SetupProfileSettings } from '@osf/features/settings/profile-settings/store/profile-settings.actions';
import { UserMapper } from '@osf/core/models';
import { removeNullable } from '@osf/shared/constants';
import { ProfileSettingsKey } from '@osf/shared/enums';
import { Social } from '@osf/shared/models';

import { UserService } from '../../services';

import { GetCurrentUser, GetCurrentUserSettings, SetCurrentUser, UpdateUserSettings } from './user.actions';
import { UserStateModel } from './user.model';
import {
GetCurrentUser,
GetCurrentUserSettings,
SetCurrentUser,
UpdateProfileSettingsEducation,
UpdateProfileSettingsEmployment,
UpdateProfileSettingsSocialLinks,
UpdateProfileSettingsUser,
UpdateUserSettings,
} from './user.actions';
import { USER_STATE_INITIAL, UserStateModel } from './user.model';

@State<UserStateModel>({
name: 'user',
defaults: {
currentUser: {
data: null,
isLoading: false,
error: null,
},
currentUserSettings: {
data: null,
isLoading: false,
isSubmitting: false,
error: '',
},
},
defaults: USER_STATE_INITIAL,
})
@Injectable()
export class UserState {
Expand All @@ -50,7 +50,6 @@ export class UserState {
error: null,
},
});
ctx.dispatch(new SetupProfileSettings());
})
);
}
Expand Down Expand Up @@ -101,4 +100,103 @@ export class UserState {
})
);
}

@Action(UpdateProfileSettingsEmployment)
updateProfileSettingsEmployment(ctx: StateContext<UserStateModel>, { payload }: UpdateProfileSettingsEmployment) {
const state = ctx.getState();
const userId = state.currentUser.data?.id;

if (!userId) {
return;
}

const withoutNulls = payload.employment.map((item) => removeNullable(item));

return this.userService.updateUserProfile(userId, ProfileSettingsKey.Employment, withoutNulls).pipe(
tap((user) => {
ctx.patchState({
currentUser: {
...state.currentUser,
data: user,
},
});
})
);
}

@Action(UpdateProfileSettingsEducation)
updateProfileSettingsEducation(ctx: StateContext<UserStateModel>, { payload }: UpdateProfileSettingsEducation) {
const state = ctx.getState();
const userId = state.currentUser.data?.id;

if (!userId) {
return;
}

const withoutNulls = payload.education.map((item) => removeNullable(item));

return this.userService.updateUserProfile(userId, ProfileSettingsKey.Education, withoutNulls).pipe(
tap((user) => {
ctx.patchState({
currentUser: {
...state.currentUser,
data: user,
},
});
})
);
}

@Action(UpdateProfileSettingsUser)
updateProfileSettingsUser(ctx: StateContext<UserStateModel>, { payload }: UpdateProfileSettingsUser) {
const state = ctx.getState();
const userId = state.currentUser.data?.id;

if (!userId) {
return;
}

const withoutNulls = UserMapper.toNamesRequest(removeNullable(payload.user));

return this.userService.updateUserProfile(userId, ProfileSettingsKey.User, withoutNulls).pipe(
tap((user) => {
ctx.patchState({
currentUser: {
...state.currentUser,
data: user,
},
});
})
);
}

@Action(UpdateProfileSettingsSocialLinks)
updateProfileSettingsSocialLinks(ctx: StateContext<UserStateModel>, { payload }: UpdateProfileSettingsSocialLinks) {
const state = ctx.getState();
const userId = state.currentUser.data?.id;

if (!userId) {
return;
}

let social = {} as Partial<Social>;

payload.socialLinks.forEach((item) => {
social = {
...social,
...item,
};
});

return this.userService.updateUserProfile(userId, ProfileSettingsKey.Social, social).pipe(
tap((user) => {
ctx.patchState({
currentUser: {
...state.currentUser,
data: user,
},
});
})
);
}
}
2 changes: 0 additions & 2 deletions src/app/features/project/files/store/project-files.state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ export class ProjectFilesState {
error: null,
},
});
console.log('files is patched');
},
}),
catchError((error) => this.handleError(ctx, 'files', error))
Expand All @@ -97,7 +96,6 @@ export class ProjectFilesState {
@Action(SetCurrentFolder)
setSelectedFolder(ctx: StateContext<ProjectFilesStateModel>, action: SetCurrentFolder) {
ctx.patchState({ currentFolder: action.folder });
console.log('set currennt folder');
}

@Action(SetMoveFileCurrentFolder)
Expand Down
Loading