aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/app/components/profile-settings/profile-settings.component.html107
-rw-r--r--src/app/components/profile-settings/profile-settings.component.ts134
-rw-r--r--src/app/components/profile/profile.component.html8
-rw-r--r--src/app/components/success-bar/success-bar.component.css1
-rw-r--r--src/app/services/user.service.ts12
-rw-r--r--src/styles.css4
6 files changed, 159 insertions, 107 deletions
diff --git a/src/app/components/profile-settings/profile-settings.component.html b/src/app/components/profile-settings/profile-settings.component.html
index dd3d186..1471859 100644
--- a/src/app/components/profile-settings/profile-settings.component.html
+++ b/src/app/components/profile-settings/profile-settings.component.html
@@ -54,59 +54,80 @@
</div>
<input type="text" class="fancy-input border-faded-slim border-bottom-only" formControlName="email" required>
</section>
- <section class="flex-col">
- <div class="flex-row">
- <label class="flexible fg-focus">Password</label>
-
- <label *ngIf="updateUserFormGroup.get('password')?.errors?.required" class="error">*Required</label>
- <label *ngIf="updateUserFormGroup.get('password')?.errors?.minlength" class="error">*Minimum 3 characters</label>
- <label *ngIf="updateUserFormGroup.get('password')?.errors?.pattern" class="error">*At least 1 number</label>
- </div>
- <input type="password" class="fancy-input border-faded-slim border-bottom-only" formControlName="password" required>
- </section>
<button type="button" class="fg-focus width-full border-faded-slim padding-dot3 lighter-hover click-effect margin-top-dot4" (click)="toggleLanguages()">
▼ Edit Languages ▼
</button>
- <section *ngIf="showLanguages">
- <div class="margin-top-dot5">
- <label class="error">
- Type in your desired languages, separated by a space
- </label>
- <input class="fancy-input width-full border-faded-slim border-bottom-only" type="text" placeholder="You have no selected languages!" formControlName="languageInput" required>
- </div>
- <div class="none-message" *ngIf="availableLanguages.length === 0">
- No languages available!
- </div>
- <div *ngIf="availableLanguages.length > 0">
- Available languages:
- </div>
- <div class="flex-row margin-top-dot4">
- <div class="sec-info border-radius-dot5r padding-dot2" *ngFor="let lang of availableLanguages">
- {{ lang.name }}
+ <section class="flex-row flexible-children border-faded-slim padding-dot3 margin-top-dot5" *ngIf="showLanguages">
+ <section class="padding-right-1">
+ <div class="none-message" *ngIf="chosenLanguages.length === 0">
+ You haven't chosen any languages!
</div>
- </div>
+ <div class="border-faded-slim border-bottom-only" *ngIf="chosenLanguages.length > 0">
+ Chosen languages:
+ </div>
+ <div class="flex-row margin-top-dot4">
+ <div class="sec-info border-radius-dot5r padding-dot2 hover-half-opacity click-effect" *ngFor="let lang of chosenLanguages" (click)="langClick(lang.name)">
+ {{ lang.name }}
+ </div>
+ </div>
+ </section>
+ <section>
+ <div class="none-message" *ngIf="availableLanguages.length === 0">
+ No other languages available!
+ </div>
+ <div class="border-faded-slim border-bottom-only" *ngIf="availableLanguages.length > 0">
+ Available languages:
+ </div>
+ <div class="flex-row margin-top-dot4">
+ <div class="sec-info border-radius-dot5r padding-dot2 hover-half-opacity click-effect" *ngFor="let lang of availableLanguages" (click)="langClick(lang.name)">
+ {{ lang.name }}
+ </div>
+ </div>
+ </section>
</section>
<button type="button" class="fg-focus width-full border-faded-slim padding-dot3 lighter-hover click-effect margin-top-dot4" (click)="toggleTechnologies()">
▼ Edit Technologies ▼
</button>
- <section *ngIf="showTechnologies">
- <div class="margin-top-dot5">
- <label class="error">
- Type in your desired technologies, separated by a space
- </label>
- <input class="fancy-input width-full border-faded-slim border-bottom-only" type="text" placeholder="You have no selected technologies!" formControlName="technologyInput" required>
- </div>
- <div class="none-message" *ngIf="availableTechnologies.length === 0">
- No technologies available!
- </div>
- <div *ngIf="availableTechnologies.length > 0">
- Available technologies:
- </div>
- <div class="flex-row margin-top-dot4">
- <div class="sec-info border-radius-dot5r padding-dot2" *ngFor="let tech of availableTechnologies">
- {{ tech.name }}
+ <section class="flex-row flexible-children border-faded-slim padding-dot3 margin-top-dot5" *ngIf="showTechnologies">
+ <section class="padding-right-1">
+ <div class="none-message" *ngIf="chosenTechnologies.length === 0">
+ You haven't chosen any technologies!
+ </div>
+ <div class="border-faded-slim border-bottom-only" *ngIf="chosenTechnologies.length > 0">
+ Chosen technologies:
+ </div>
+ <div class="flex-row margin-top-dot4">
+ <div class="sec-info border-radius-dot5r padding-dot2 hover-half-opacity click-effect" *ngFor="let tech of chosenTechnologies" (click)="techClick(tech.name)">
+ {{ tech.name }}
+ </div>
+ </div>
+ </section>
+ <section>
+ <div class="none-message" *ngIf="availableTechnologies.length === 0">
+ No other technologies available!
+ </div>
+ <div class="border-faded-slim border-bottom-only" *ngIf="availableTechnologies.length > 0">
+ Available technologies:
</div>
+ <div class="flex-row margin-top-dot4">
+ <div class="sec-info border-radius-dot5r padding-dot2 hover-half-opacity click-effect" *ngFor="let tech of availableTechnologies" (click)="techClick(tech.name)">
+ {{ tech.name }}
+ </div>
+ </div>
+ </section>
+ </section>
+ <section class="flex-col input-selection">
+ <div class="flex-row">
+ <label class="flexible fg-focus">Current Password</label>
+
+ <label *ngIf="updateUserFormGroup.get('password')?.errors?.required" class="error">*Required</label>
+ <label *ngIf="updateUserFormGroup.get('password')?.errors?.minlength" class="error">*Minimum 3 characters</label>
+ <label *ngIf="updateUserFormGroup.get('password')?.errors?.pattern" class="error">*At least 1 number</label>
</div>
+ <input [type]="showCurrentPassword ? 'text' : 'password'" class="fancy-input border-faded-slim border-bottom-only padding-right-1dot5" formControlName="password" required>
+ <button type="button" class="show-password-button hover-half-opacity click-effect" (click)="toggleShowPassword(0)">
+ <img [src]="showCurrentPassword ? '/assets/icons/tabler-icon-eye-off.svg' : '/assets/icons/tabler-icon-eye.svg'">
+ </button>
</section>
<section class="margin-top-bot-dot3">
<app-success-bar></app-success-bar>
diff --git a/src/app/components/profile-settings/profile-settings.component.ts b/src/app/components/profile-settings/profile-settings.component.ts
index 79519aa..f329942 100644
--- a/src/app/components/profile-settings/profile-settings.component.ts
+++ b/src/app/components/profile-settings/profile-settings.component.ts
@@ -34,8 +34,11 @@ export class ProfileSettingsComponent implements OnInit {
public updateProfilePictureFormGroup: FormGroup;
public newProfilePicture: File;
public user: User;
+ public chosenLanguages: Language[];
+ public chosenTechnologies: Technology[];
public availableLanguages: Language[];
public availableTechnologies: Technology[];
+ public showCurrentPassword = false;
constructor(private _titleService: Title, private _router: Router, private _userService: UserService, private _languageService: LanguageService, private _technologyService: TechnologyService, private _tokenService: TokenService, private _fb: FormBuilder, private _location: Location) {
this._titleService.setTitle(this._title);
@@ -57,16 +60,11 @@ export class ProfileSettingsComponent implements OnInit {
username: new FormControl(''),
email: new FormControl(''),
password: new FormControl(''),
- languageInput: new FormControl(''),
- languages: new FormControl(''),
- technologyInput: new FormControl(''),
- technologies: new FormControl('')
});
this.updateProfilePictureFormGroup = this._fb.group({
fileUpload: new FormControl('')
});
-
this._userService.getUserByUsernameRequest(this._urlUsername).subscribe({
next: (res: object) => {
Object.assign(this.user, res);
@@ -77,18 +75,7 @@ export class ProfileSettingsComponent implements OnInit {
this._router.navigate(['/not-found']);
}
});
-
- this._languageService.getAllLanguagesWithSessionStorageRequest().subscribe({
- next: (result: object) => {
- this.availableLanguages = result as Language[];
- }
- });
- this._technologyService.getAllTechnologiesWithSessionStorageRequest().subscribe({
- next: (result: object) => {
- this.availableTechnologies = result as Technology[];
- }
- });
- }
+ }
private finishUserLoading(): void {
if (sessionStorage.getItem('UserCred')) {
@@ -99,6 +86,7 @@ export class ProfileSettingsComponent implements OnInit {
Object.assign(userFromToken, tokenRes);
if (userFromToken.userName === this._urlUsername) {
+ this.loadUserSecondaryInfo();
this.initForms();
this.dataArrived = true;
}
@@ -116,6 +104,43 @@ export class ProfileSettingsComponent implements OnInit {
}
}
+ private loadUserSecondaryInfo(): void {
+ // Load languages and tehnologies of user
+ this._languageService.getFullLanguagesFromIncomplete(this.user.languages).then(
+ (result) => {
+ this.chosenLanguages = result as Language[];
+ this.loadAvailableLanguages();
+ }
+ );
+
+ this._technologyService.getFullTechnologiesFromIncomplete(this.user.technologies).then(
+ (result) => {
+ this.chosenTechnologies = result as Technology[];
+ this.loadAvailableTechnologies();
+ }
+ );
+ }
+
+ private loadAvailableLanguages(): void {
+ this._languageService.getAllLanguagesWithSessionStorageRequest().subscribe({
+ next: (result: object) => {
+ const allAvailable = result as Language[];
+ // Remove the chosen languages from all of the avaiable ones
+ this.availableLanguages = allAvailable.filter(a => !this.user.languages.some(l => l.name === a.name));
+ }
+ });
+ }
+
+ private loadAvailableTechnologies(): void {
+ this._technologyService.getAllTechnologiesWithSessionStorageRequest().subscribe({
+ next: (result: object) => {
+ const allAvailable = result as Technology[];
+ // Remove the chosen technologies from all of the avaiable ones
+ this.availableTechnologies = allAvailable.filter(a => !this.user.technologies.some(t => t.name === a.name));
+ }
+ });
+ }
+
private initForms(): void {
this.updateUserFormGroup = this._fb.group({
firstName: new FormControl(this.user.firstName, [
@@ -139,25 +164,6 @@ export class ProfileSettingsComponent implements OnInit {
Validators.minLength(3),
Validators.pattern('.*[0-9].*') // Check if password contains atleast one number
]),
-
- // For language we have two different controls,
- // the first one is used for input, the other one for sending data
- // because if we edit the control for input,
- // we're also gonna change the input field in the HTML
- languageInput: new FormControl(''), // The one for input
- languages: new FormControl(''), // The one that is sent
-
- // For technologies it's the same as it is with languages
- technologyInput: new FormControl(''),
- technologies: new FormControl('')
- });
-
- this.getLanguagesForShowing().then(value => {
- this.updateUserFormGroup.patchValue({ languageInput : value });
- });
-
- this.getTechnologiesForShowing().then(value => {
- this.updateUserFormGroup.patchValue({ technologyInput : value });
});
this.updateProfilePictureFormGroup = this._fb.group({
@@ -172,24 +178,6 @@ export class ProfileSettingsComponent implements OnInit {
});
}
- private getLanguagesForShowing(): Promise<string> {
- return new Promise(resolve => {
- this._languageService.getFullLanguagesFromIncomplete(this.user.languages).then(value => {
- this.user.languages = value;
- resolve(value.map(x => x.name).join(' '));
- });
- });
- }
-
- private getTechnologiesForShowing(): Promise<string> {
- return new Promise(resolve => {
- this._technologyService.getFullTechnologiesFromIncomplete(this.user.technologies).then(value => {
- this.user.technologies = value;
- resolve(value.map(x => x.name).join(' '));
- });
- });
- }
-
onFileUpload(event: any): void {
this.newProfilePicture = event.target.files[0];
}
@@ -214,7 +202,7 @@ export class ProfileSettingsComponent implements OnInit {
this.patchLanguagesControl();
this.patchTechnologiesControl();
- this._userService.putUserFromSessionStorageRequest(this.updateUserFormGroup, this.user.roles, this.user.friends).subscribe({
+ this._userService.putUserFromSessionStorageRequest(this.updateUserFormGroup, this.chosenLanguages, this.chosenTechnologies, this.user.roles, this.user.friends).subscribe({
next: () => {
this._successBar.showMsg('Profile updated successfully!');
@@ -286,6 +274,36 @@ export class ProfileSettingsComponent implements OnInit {
}
}
+ langClick(name: string): void {
+ if (this.chosenLanguages.some(c => c.name === name)) {
+ const index = this.chosenLanguages.findIndex(t => t.name === name);
+
+ this.availableLanguages.push(this.chosenLanguages[index]);
+ this.chosenLanguages.splice(index, 1);
+ }
+ else {
+ const index = this.availableLanguages.findIndex(t => t.name === name);
+
+ this.chosenLanguages.push(this.availableLanguages[index]);
+ this.availableLanguages.splice(index, 1);
+ }
+ }
+
+ techClick(name: string): void {
+ if (this.chosenTechnologies.some(c => c.name === name)) {
+ const index = this.chosenTechnologies.findIndex(t => t.name === name);
+
+ this.availableTechnologies.push(this.chosenTechnologies[index]);
+ this.chosenTechnologies.splice(index, 1);
+ }
+ else {
+ const index = this.availableTechnologies.findIndex(t => t.name === name);
+
+ this.chosenTechnologies.push(this.availableTechnologies[index]);
+ this.availableTechnologies.splice(index, 1);
+ }
+ }
+
goToProfile(): void {
this._router.navigate([this._router.url.substring(0, this._router.url.length - 9)]);
}
@@ -329,4 +347,10 @@ export class ProfileSettingsComponent implements OnInit {
this._router.onSameUrlNavigation = 'reload';
this._router.navigate([this._router.url]);
}
+
+ toggleShowPassword(index: number): void {
+ switch (index) {
+ case 0: this.showCurrentPassword = !this.showCurrentPassword;
+ }
+ }
}
diff --git a/src/app/components/profile/profile.component.html b/src/app/components/profile/profile.component.html
index 7de1d09..1a360fc 100644
--- a/src/app/components/profile/profile.component.html
+++ b/src/app/components/profile/profile.component.html
@@ -29,8 +29,8 @@
<div class="none-message" *ngIf="user.languages.length === 0">
None
</div>
- <div class="flex-row" *ngFor="let lang of user.languages">
- <div class="sec-info border-radius-dot5r padding-dot2">
+ <div class="flex-row">
+ <div class="sec-info border-radius-dot5r padding-dot2" *ngFor="let lang of user.languages">
{{ lang.name }}
</div>
</div>
@@ -42,8 +42,8 @@
<div class="none-message" *ngIf="user.technologies.length === 0">
None
</div>
- <div class="flex-row" *ngFor="let tech of user.technologies">
- <div class="sec-info border-radius-dot5r padding-dot2">
+ <div class="flex-row">
+ <div class="sec-info border-radius-dot5r padding-dot2" *ngFor="let tech of user.technologies">
{{ tech.name }}
</div>
</div>
diff --git a/src/app/components/success-bar/success-bar.component.css b/src/app/components/success-bar/success-bar.component.css
index bee634d..32fe099 100644
--- a/src/app/components/success-bar/success-bar.component.css
+++ b/src/app/components/success-bar/success-bar.component.css
@@ -4,6 +4,7 @@
color: white;
padding: .2em;
text-align: center;
+ box-sizing: border-box;
}
#success-bar:empty {
diff --git a/src/app/services/user.service.ts b/src/app/services/user.service.ts
index 29058b4..10c8c59 100644
--- a/src/app/services/user.service.ts
+++ b/src/app/services/user.service.ts
@@ -8,6 +8,8 @@ import { Observable } from 'rxjs';
import { Role } from 'src/models/identity/role.model';
import { Friend } from 'src/models/identity/friend.model';
import { TokenService } from './token.service';
+import { Language } from 'src/models/language.model';
+import { Technology } from 'src/models/technology.model';
@Injectable({
providedIn: 'root'
@@ -36,11 +38,11 @@ export class UserService {
return this.addFriendToUserRequest(userUserName, token, newFriendUserName);
}
- putUserFromSessionStorageRequest(updateUserFormGroup: FormGroup, userRoles: Role[], userFriends: Friend[]): Observable<object> {
+ putUserFromSessionStorageRequest(updateUserFormGroup: FormGroup, languages: Language[], technologies: Technology[], userRoles: Role[], userFriends: Friend[]): Observable<object> {
const userId = this._tokenService.getUserIdFromSessionStorageToken();
const token = this._tokenService.getTokenFromSessionStorage();
- return this.putUserRequest(userId, token, updateUserFormGroup, userRoles, userFriends);
+ return this.putUserRequest(userId, token, updateUserFormGroup, languages, technologies, userRoles, userFriends);
}
putProfilePictureFromSessionStorageRequest(newPicture: File): Observable<object> {
@@ -119,7 +121,7 @@ export class UserService {
return this._http.get(AppConstants.API_USER_URL + '/GetUser', options);
}
- putUserRequest(userId: Guid, authToken: string, updateUserFormGroup: FormGroup, userRoles: Role[], userFriends: Friend[]): Observable<object> {
+ putUserRequest(userId: Guid, authToken: string, updateUserFormGroup: FormGroup, languages: Language[], technologies: Technology[], userRoles: Role[], userFriends: Friend[]): Observable<object> {
const body = {
UserName: updateUserFormGroup.get('username')?.value,
Email: updateUserFormGroup.get('email')?.value,
@@ -128,8 +130,8 @@ export class UserService {
Password: updateUserFormGroup.get('password')?.value,
Roles: userRoles,
Friends: userFriends,
- Languages: updateUserFormGroup.get('languages')?.value,
- Technologies: updateUserFormGroup.get('technologies')?.value
+ Languages: languages,
+ Technologies: technologies
};
const options = {
params: new HttpParams().set('Id', userId.toString()),
diff --git a/src/styles.css b/src/styles.css
index 39b6fb1..c9a4f25 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -279,6 +279,10 @@ input[type=file]::file-selector-button {
padding: 0.1em;
}
+.padding-right-1 {
+ padding-right: 1em !important;
+}
+
.padding-right-1dot5 {
padding-right: 1.5em !important;
}