Skip to content

Commit a8215dd

Browse files
committed
fill public profile page with content
1 parent 68d307d commit a8215dd

File tree

21 files changed

+318
-57
lines changed

21 files changed

+318
-57
lines changed

src/app/chat/data-access/chat-http.service.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { inject, Injectable } from '@angular/core';
33
import { catchError, map, Observable, of, switchMap } from 'rxjs';
44
import { EnvironmentService } from '@shared/data-access/environment.service';
55
import {
6-
APIResponse,
76
asError,
87
asSuccess,
8+
OldAPIResponse,
99
} from '@shared/util/http/response.types';
1010
import {
1111
ChatDto,
@@ -43,7 +43,7 @@ export class ChatHttpService {
4343
createMessage$(
4444
chatId: string,
4545
message: CreateMessageRequest
46-
): Observable<APIResponse<void>> {
46+
): Observable<OldAPIResponse<void>> {
4747
return this.http
4848
.post<void>(
4949
`${this.chatApiUrl}/${chatId}/messages`,
@@ -107,7 +107,7 @@ export class ChatHttpService {
107107
);
108108
}
109109

110-
getChatsAndDancers$(): Observable<APIResponse<ChatsAndDancers>> {
110+
getChatsAndDancers$(): Observable<OldAPIResponse<ChatsAndDancers>> {
111111
return this.http.get<ChatList>(this.chatApiUrl, this.defaultOptions).pipe(
112112
map((chatList) => {
113113
const dancerIds = this.getAllDancerIds(chatList.chats);

src/app/home/data-access/contact.service.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import {
88
} from '@angular/common/http';
99
import { EnvironmentService } from '@shared/data-access/environment.service';
1010
import {
11-
APIResponse,
1211
asError,
1312
asSuccess,
13+
OldAPIResponse,
1414
} from '@shared/util/http/response.types';
1515
import { EventLogService } from '@shared/data-access/log/event-log.service';
1616

@@ -28,7 +28,10 @@ export class ContactService {
2828
private eventLogService: EventLogService
2929
) {}
3030

31-
sendMessage(message: string, sender: string): Observable<APIResponse<void>> {
31+
sendMessage(
32+
message: string,
33+
sender: string
34+
): Observable<OldAPIResponse<void>> {
3235
const apiUrlContact = `${this.environment.getApiUrl()}/contacts`;
3336
const payload = {
3437
sender,

src/app/home/feature/contact/contact.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { AuthenticationService } from '@shared/data-access/auth/authentication.s
1010
import { EventLogService } from '@shared/data-access/log/event-log.service';
1111
import { ContactService } from '../../data-access/contact.service';
1212
import { tap } from 'rxjs';
13-
import { APIResponse } from '@shared/util/http/response.types';
13+
import { OldAPIResponse } from '@shared/util/http/response.types';
1414
import { ErrorMessagePipe } from '@shared/util/http/error-message.pipe';
1515
import { MatButtonModule } from '@angular/material/button';
1616
import { RecaptchaModule } from 'ng-recaptcha';
@@ -40,7 +40,7 @@ import { DataTestDirective } from '@shared/util/data-test.directive';
4040
})
4141
export class ContactComponent implements OnInit {
4242
contactForm!: FormGroup;
43-
contactResponse?: APIResponse<void>;
43+
contactResponse?: OldAPIResponse<void>;
4444

4545
// TODO: refactor, we should solve this in a reactive way (e.g. subscribe in the template)
4646
isCaptchaSolved = false;

src/app/profile/data-access/image-upload.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { HttpClient, HttpErrorResponse } from '@angular/common/http';
33
import { catchError, map, Observable, of } from 'rxjs';
44
import { EnvironmentService } from '@shared/data-access/environment.service';
55
import {
6-
APIResponse,
76
asError,
87
asSuccess,
8+
OldAPIResponse,
99
} from '@shared/util/http/response.types';
1010
import { UploadedImageDao } from './types/profile.types';
1111

@@ -36,7 +36,7 @@ export class ImageUploadService {
3636

3737
uploadImage$(
3838
croppedImage: string
39-
): Observable<APIResponse<UploadedImageDao>> {
39+
): Observable<OldAPIResponse<UploadedImageDao>> {
4040
const blobFromDataUrl = this.dataURItoBlob(croppedImage);
4141
const formData: FormData = new FormData();
4242
formData.append('file', blobFromDataUrl);
Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,42 @@
1-
import { Injectable } from '@angular/core';
1+
import { inject, Injectable } from '@angular/core';
2+
import { EnvironmentService } from '@shared/data-access/environment.service';
3+
import { HttpClient } from '@angular/common/http';
4+
import { PublicProfile } from './types/public-profile.types';
5+
import { Observable } from 'rxjs';
6+
import { toApiResponse } from '@shared/util/http/response.utils';
7+
import { ApiResponse } from '@shared/util/http/response.types';
8+
import { ImageService } from '@shared/data-access/image.service';
29

310
@Injectable({
411
providedIn: 'root',
512
})
613
export class ProfileService {
7-
constructor() {}
14+
private readonly http = inject(HttpClient);
15+
private readonly imageService = inject(ImageService);
16+
private readonly profileApiUrl = `${inject(
17+
EnvironmentService
18+
).getApiUrl()}/profile`;
819

920
// public getOwnProfile(): void {}
1021
//
11-
// public getProfile(dancerId: string): void {}
22+
23+
public getPublicProfile(
24+
dancerId: string
25+
): Observable<ApiResponse<PublicProfile>> {
26+
return toApiResponse(
27+
this.http.get<PublicProfile>(`${this.profileApiUrl}/${dancerId}`)
28+
);
29+
}
30+
31+
getProfileImageSrc(imgHash: string | undefined, width = 150): string {
32+
if (imgHash) {
33+
return this.imageService.getDancerImageSrcOrDefault(imgHash, width);
34+
} else {
35+
return this.imageService.getDancerImageSrcOrDefault(null, width);
36+
}
37+
}
38+
39+
getDefaultProfileImage(): string {
40+
return this.imageService.getDefaultDancerImage();
41+
}
1242
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Dance, Gender } from './profile.types';
2+
3+
export type PublicProfile = {
4+
id: string;
5+
size: number;
6+
gender: Gender;
7+
dancerName: string;
8+
age: number;
9+
ableTo: Dance[];
10+
wantsTo: Dance[];
11+
city: string;
12+
country: string;
13+
profileImageHash: string;
14+
aboutMe: string;
15+
};

src/app/profile/feature/edit-profile/edit-profile.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
NonNullableFormBuilder,
55
ReactiveFormsModule,
66
} from '@angular/forms';
7-
import { APIError, APIResponse } from '@shared/util/http/response.types';
7+
import { APIError, OldAPIResponse } from '@shared/util/http/response.types';
88
import { ProfileOldService } from '@shared/data-access/profile/profile-old.service';
99
import {
1010
Profile,
@@ -56,7 +56,7 @@ export class EditProfileComponent {
5656
});
5757
croppedImage?: string | null;
5858
imageChangedEvent: any = '';
59-
uploadResponse?: APIResponse<UploadedImageDao>;
59+
uploadResponse?: OldAPIResponse<UploadedImageDao>;
6060
error?: APIError;
6161

6262
constructor(

src/app/profile/feature/initial-setup/init-profile-image/init-profile-image.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Component } from '@angular/core';
22
import { ImageUploadService } from '../../../data-access/image-upload.service';
33
import { ImageCroppedEvent, ImageCropperModule } from 'ngx-image-cropper';
44
import { ProfileOldService } from '@shared/data-access/profile/profile-old.service';
5-
import { APIResponse } from '@shared/util/http/response.types';
5+
import { OldAPIResponse } from '@shared/util/http/response.types';
66
import { UploadedImageDao } from '../../../data-access/types/profile.types';
77
import { Router } from '@angular/router';
88
import { NgIf } from '@angular/common';
@@ -18,7 +18,7 @@ import { MatButtonModule } from '@angular/material/button';
1818
export class InitProfileImageComponent {
1919
croppedImage?: string | null | undefined;
2020
imageChangedEvent: any = '';
21-
uploadResponse?: APIResponse<UploadedImageDao>;
21+
uploadResponse?: OldAPIResponse<UploadedImageDao>;
2222

2323
constructor(
2424
private imageUploadService: ImageUploadService,

src/app/profile/feature/initial-setup/init-user-name/init-user-name.component.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import { ProfileHttpService } from '@shared/data-access/profile/profile-http.ser
99
import { ProfileOldService } from '@shared/data-access/profile/profile-old.service';
1010
import {
1111
APIError,
12-
APIResponse,
1312
asError,
13+
OldAPIResponse,
1414
ResponseError,
1515
} from '@shared/util/http/response.types';
1616
import { of, switchMap } from 'rxjs';
@@ -60,7 +60,7 @@ export class InitUserNameComponent {
6060
this.profileHttpService
6161
.checkNameAvailability$(username)
6262
.pipe(
63-
switchMap((response: APIResponse<NameAvailability>) => {
63+
switchMap((response: OldAPIResponse<NameAvailability>) => {
6464
if (!response.isSuccess) {
6565
return of(response as ResponseError);
6666
}
@@ -70,7 +70,7 @@ export class InitUserNameComponent {
7070
return this.profileService.setDancerName(username);
7171
})
7272
)
73-
.subscribe((response: APIResponse<void>) => {
73+
.subscribe((response: OldAPIResponse<void>) => {
7474
if (response.isSuccess) {
7575
this.router.navigate(['profile/initial-setup/personal-info']);
7676
} else {
Lines changed: 123 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,135 @@
11
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
22
import { CommonModule } from '@angular/common';
3-
import { ActivatedRoute } from '@angular/router';
3+
import { ActivatedRoute, Router } from '@angular/router';
4+
import { ProfileService } from '../data-access/profile.service';
5+
import { AgePipe } from '@shared/util/age.pipe';
6+
import { DisplayDanceLevelPipe } from '../util/pipes/display-dance-level.pipe';
7+
import { DisplayDanceRolePipe } from '../util/pipes/display-dance-role.pipe';
8+
import { DisplayGenderPipe } from '../util/pipes/display-gender.pipe';
9+
import { ProfileDataEntryComponent } from '../ui/profile-data-entry.component';
410

511
@Component({
612
selector: 'app-public-profile',
713
standalone: true,
8-
imports: [CommonModule],
14+
imports: [
15+
CommonModule,
16+
AgePipe,
17+
DisplayDanceLevelPipe,
18+
DisplayDanceRolePipe,
19+
DisplayGenderPipe,
20+
ProfileDataEntryComponent,
21+
],
922
template: `
10-
<p>
11-
public-profile works and the id is
12-
{{ activeRoute.snapshot.params['participantId'] }}
13-
</p>
23+
<!-- TODO: loading and error view -->
24+
<ng-container *ngIf="profileResponse$ | async as profileResponse">
25+
<div
26+
*ngIf="
27+
profileResponse.fetchStatus === 'success' &&
28+
profileResponse.payload as profile
29+
"
30+
class="my-12 mx-auto flex max-w-[1200px] flex-col gap-10 px-4 md:flex-row md:px-10 lg:px-10"
31+
>
32+
<div class="mx-auto lg:px-16">
33+
<!-- TODO: use pipe-->
34+
<img
35+
class="relative h-[250px] w-[250px] max-w-none rounded-full"
36+
alt="Profile Image"
37+
[src]="
38+
profileService.getProfileImageSrc(profile.profileImageHash, 250)
39+
"
40+
(error)="handleMissingImage($event)"
41+
/>
42+
</div>
43+
<div class="grow">
44+
<h1 class="page-header">
45+
<span class="text-gray-500">Profil von</span>
46+
{{ profile.dancerName }}
47+
</h1>
48+
49+
<button
50+
class="mb-4 flex items-center gap-2 rounded border border-red-800 fill-red-800 px-3 py-1 text-red-800 transition-colors hover:bg-red-50"
51+
(click)="openChat(profile.id)"
52+
>
53+
<div class="grow-0">
54+
<svg class="h-6 w-6">
55+
<use href="assets/icons/bootstrap-icons.svg#chat-dots" />
56+
</svg>
57+
</div>
58+
<div class="grow-0">Nachricht schreiben</div>
59+
</button>
60+
61+
<app-profile-data-entry
62+
*ngIf="profile.aboutMe"
63+
icon="info-square"
64+
label="Über mich"
65+
class="block border-t"
66+
[value]="profile.aboutMe"
67+
></app-profile-data-entry>
68+
69+
<app-profile-data-entry
70+
*ngIf="profile.city"
71+
icon="buildings"
72+
label="Wohnort"
73+
[value]="profile.city"
74+
></app-profile-data-entry>
75+
76+
<app-profile-data-entry
77+
*ngIf="profile.age"
78+
icon="calendar3"
79+
label="Alter"
80+
[value]="profile.age.toString()"
81+
></app-profile-data-entry>
82+
83+
<app-profile-data-entry
84+
*ngIf="profile.size"
85+
icon="arrows-vertical"
86+
label="Körpergröße"
87+
[value]="profile.size + ' cm'"
88+
></app-profile-data-entry>
89+
90+
<app-profile-data-entry
91+
*ngIf="profile.gender"
92+
icon="gender-ambiguous"
93+
label="Geschlecht"
94+
[value]="profile.gender | displayGender"
95+
></app-profile-data-entry>
96+
97+
<app-profile-data-entry
98+
*ngFor="let danceExperience of profile.ableTo"
99+
icon="music-note-beamed"
100+
label="Tanzerfahrung"
101+
[value]="
102+
danceExperience.dance +
103+
' (' +
104+
(danceExperience.level | displayDanceLevel) +
105+
', ' +
106+
(danceExperience.leading | displayDanceRole) +
107+
')'
108+
"
109+
></app-profile-data-entry>
110+
</div>
111+
</div>
112+
</ng-container>
14113
`,
15114
changeDetection: ChangeDetectionStrategy.OnPush,
16115
})
17116
export class PublicProfileComponent {
18-
public readonly activeRoute = inject(ActivatedRoute);
117+
private readonly activeRoute = inject(ActivatedRoute);
118+
public readonly profileService = inject(ProfileService);
119+
private readonly router = inject(Router);
120+
121+
public readonly profileResponse$ = this.profileService.getPublicProfile(
122+
this.activeRoute.snapshot.params['participantId']
123+
);
124+
125+
handleMissingImage($event: ErrorEvent): void {
126+
($event.target as HTMLImageElement).src =
127+
this.profileService.getDefaultProfileImage();
128+
}
129+
130+
openChat(dancerId: string): void {
131+
this.router.navigate(['chat'], {
132+
queryParams: { participantId: dancerId },
133+
});
134+
}
19135
}

src/app/profile/profile.routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { PublicProfileComponent } from './feature/public-profile.component';
1919
export const PROFILE_ROUTES: Routes = [
2020
{
2121
path: 'view/:participantId',
22+
// add guard: only open if not the own profile...
2223
pathMatch: 'full',
2324
component: PublicProfileComponent,
2425
},

src/app/recommendation/data-access/recommendation-http.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { HttpClient, HttpErrorResponse } from '@angular/common/http';
33
import { EnvironmentService } from '@shared/data-access/environment.service';
44
import { RecommendationsDto } from './types/recommendations.dto';
55
import {
6-
APIResponse,
76
asError,
87
asSuccess,
8+
OldAPIResponse,
99
} from '@shared/util/http/response.types';
1010
import { catchError, map, Observable, of } from 'rxjs';
1111

@@ -28,7 +28,7 @@ export class RecommendationHttpService {
2828
this.recommendationsApiUrl = `${this.environment.getApiUrl()}/recommendations`;
2929
}
3030

31-
getRecommendations$(): Observable<APIResponse<RecommendationsDto>> {
31+
getRecommendations$(): Observable<OldAPIResponse<RecommendationsDto>> {
3232
return this.http
3333
.get<RecommendationsDto>(this.recommendationsApiUrl, this.defaultOptions)
3434
.pipe(

0 commit comments

Comments
 (0)