Skip to content

Commit

Permalink
user photo service
Browse files Browse the repository at this point in the history
  • Loading branch information
jorbush committed Nov 12, 2024
1 parent e8af752 commit a7100ae
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ public class UserController {
@Autowired private UserService userService;

@GetMapping("/{username}/image")
public ResponseEntity<String> getUserImage(@PathVariable String username) {
public ResponseEntity<String> getUserImage(@PathVariable final String username) {
String base64Image = userService.getUserImage(username);
return ResponseEntity.ok(base64Image);
}

@PutMapping("/{username}/image")
public ResponseEntity<String> updateUserImage(
@PathVariable String username, @RequestBody String base64Image) {
@PathVariable final String username, @RequestBody final String base64Image) {
userService.updateUserImage(username, base64Image);
return ResponseEntity.ok("User image updated successfully!");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ public User registerUser(final User user) {
return userRepository.save(user);
}

public String getUserImage(String username) {
public String getUserImage(final String username) {
User user = findByUsername(username);
return user.getImage();
}

public void updateUserImage(String username, String base64Image) {
public void updateUserImage(final String username, final String base64Image) {
User user = findByUsername(username);
user.setImage(base64Image);
userRepository.save(user);
Expand Down
19 changes: 16 additions & 3 deletions postrify-frontend/src/app/components/header/header.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Component, OnInit } from '@angular/core';
import { RouterLink } from '@angular/router';
import { AuthService } from '../../services/auth.service';
import { SettingsModalComponent } from '../settings-modal/settings-modal.component';
import { Subscription } from 'rxjs';
import { UserImageService } from '../../services/user-image.service';

@Component({
selector: 'app-header',
Expand Down Expand Up @@ -129,7 +131,9 @@ import { SettingsModalComponent } from '../settings-modal/settings-modal.compone
</div>
</header>
@if (isSettingsOpen) {
<app-settings-modal (close)="isSettingsOpen = false"></app-settings-modal>
<app-settings-modal
(closeModalEvent)="isSettingsOpen = false"
></app-settings-modal>
}
`,
styles: [
Expand Down Expand Up @@ -229,7 +233,7 @@ import { SettingsModalComponent } from '../settings-modal/settings-modal.compone
}
}
@media (max-width: 400px) {
@media (max-width: 450px) {
.username {
display: none;
}
Expand All @@ -249,19 +253,28 @@ import { SettingsModalComponent } from '../settings-modal/settings-modal.compone
],
})
export class HeaderComponent implements OnInit {
private imageUpdateSubscription: Subscription | undefined;

isDarkMode = false;
logoSrc = 'assets/logo-light.png';
isAuthenticated = false;
username: string | null = null;
userImage: string | null = null;
isSettingsOpen = false;

constructor(public authService: AuthService) {}
constructor(
public authService: AuthService,
private userImageService: UserImageService,
) {}

ngOnInit() {
this.loadDarkModePreference();
this.updateLogo();
this.checkAuthentication();
this.imageUpdateSubscription =
this.userImageService.imageUpdated$.subscribe(() => {
this.checkAuthentication();
});
}

toggleDarkMode() {
Expand Down
25 changes: 15 additions & 10 deletions postrify-frontend/src/app/components/home/home.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { PostResponseDTO } from '../../models/post-response.model';
import { PostService } from '../../services/post.service';
import { Router } from '@angular/router';
import { AuthService } from '../../services/auth.service';
import { CommonModule } from '@angular/common';
import { Page } from '../../models/page.model';
import { Subscription } from 'rxjs';
import { UserImageService } from '../../services/user-image.service';

@Component({
selector: 'app-home',
Expand Down Expand Up @@ -199,7 +201,9 @@ import { Page } from '../../models/page.model';
}
`,
})
export class HomeComponent implements OnInit {
export class HomeComponent implements OnInit, OnDestroy {
private imageUpdateSubscription: Subscription | undefined;

posts: PostResponseDTO[] = [];
isLogged = false;
currentPage = 0;
Expand All @@ -211,11 +215,16 @@ export class HomeComponent implements OnInit {
private postService: PostService,
private router: Router,
private authService: AuthService,
private userImageService: UserImageService,
) {}

ngOnInit(): void {
this.fetchPosts(this.currentPage, this.pageSize);
this.isLogged = this.authService.isAuthenticated();
this.imageUpdateSubscription =
this.userImageService.imageUpdated$.subscribe(() => {
this.fetchPosts(this.currentPage, this.pageSize);
});
}

fetchPosts(page: number, size: number): void {
Expand Down Expand Up @@ -259,13 +268,9 @@ export class HomeComponent implements OnInit {
}
}

getPages(): number[] {
return Array(this.totalPages)
.fill(0)
.map((x, i) => i);
}

trackById(index: number, post: PostResponseDTO): number {
return post.id;
ngOnDestroy(): void {
if (this.imageUpdateSubscription) {
this.imageUpdateSubscription.unsubscribe();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { CommonModule } from '@angular/common';
import { ToastService } from '../../services/toast.service';
import { ReadingTimePipe } from '../../pipes/reading-time.pipe';
import { BoldTextPipe } from '../../pipes/bold-text.pipe';
import { Subscription } from 'rxjs';
import { UserImageService } from '../../services/user-image.service';

@Component({
selector: 'app-post-detail',
Expand Down Expand Up @@ -242,10 +244,24 @@ import { BoldTextPipe } from '../../pipes/bold-text.pipe';
position: relative;
border: 2px solid var(--border-color);
}
@media (max-width: 500px) {
.post-detail-container {
padding: 0.5rem;
}
.post-title {
font-size: 2rem;
}
.post-content {
padding: 1rem;
}
}
`,
],
})
export class PostDetailComponent implements OnInit {
private imageUpdateSubscription: Subscription | undefined;

post?: PostResponseDTO;
isLogged = false;
username?: string;
Expand All @@ -256,13 +272,18 @@ export class PostDetailComponent implements OnInit {
private router: Router,
private authService: AuthService,
private toastService: ToastService,
private userImageService: UserImageService,
) {}

ngOnInit(): void {
const postId = Number(this.route.snapshot.paramMap.get('id'));
this.fetchPost(postId);
this.isLogged = this.authService.isAuthenticated();
this.username = localStorage.getItem('username') || '';
this.imageUpdateSubscription =
this.userImageService.imageUpdated$.subscribe(() => {
this.fetchPost(postId);
});
}

fetchPost(id: number): void {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { SettingsModalComponent } from './settings-modal.component';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { provideHttpClient } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';

describe('SettingsModalComponent', () => {
let component: SettingsModalComponent;
Expand All @@ -9,6 +11,11 @@ describe('SettingsModalComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SettingsModalComponent],
providers: [
provideHttpClient(),
provideHttpClientTesting(),
{ provide: ActivatedRoute, useValue: {} },
],
}).compileComponents();

fixture = TestBed.createComponent(SettingsModalComponent);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AuthService } from '../../services/auth.service';
import { UserImageService } from '../../services/user-image.service';

@Component({
selector: 'app-settings-modal',
standalone: true,
imports: [CommonModule],
template: `
<div class="modal-overlay" (click)="closeModal()">
<div class="modal-container" (click)="$event.stopPropagation()">
<div
class="modal-overlay"
(click)="closeModal()"
(keydown.enter)="closeModal()"
tabindex="0"
>
<div
class="modal-container"
(click)="$event.stopPropagation()"
(keydown.enter)="$event.stopPropagation()"
tabindex="0"
>
<div class="modal-header">
<h2>Profile Configuration</h2>
<button class="close-button" (click)="closeModal()">
<button
class="close-button"
(click)="closeModal()"
(keydown.enter)="closeModal()"
tabindex="0"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
Expand Down Expand Up @@ -40,7 +56,12 @@ import { AuthService } from '../../services/auth.service';
: 'url(/assets/placeholder.jpg)'
"
>
<div class="photo-overlay" (click)="fileInput.click()">
<div
class="photo-overlay"
(click)="fileInput.click()"
(keydown.enter)="fileInput.click()"
tabindex="0"
>
<span>Change photo</span>
</div>
</div>
Expand Down Expand Up @@ -272,14 +293,17 @@ import { AuthService } from '../../services/auth.service';
],
})
export class SettingsModalComponent implements OnInit {
@Output() close = new EventEmitter<void>();
@Output() closeModalEvent = new EventEmitter<void>();

selectedFile: File | null = null;
previewUrl: string | null = null;
errorMessage: string = '';
isLoading: boolean = false;
errorMessage = '';
isLoading = false;

constructor(private authService: AuthService) {}
constructor(
private authService: AuthService,
private userImageService: UserImageService,
) {}

ngOnInit() {
this.loadCurrentUserImage();
Expand All @@ -299,7 +323,7 @@ export class SettingsModalComponent implements OnInit {
}

closeModal() {
this.close.emit();
this.closeModalEvent.emit();
}

onFileSelected(event: Event) {
Expand Down Expand Up @@ -340,6 +364,7 @@ export class SettingsModalComponent implements OnInit {
this.authService.uploadUserImage(base64Image).subscribe({
next: () => {
this.isLoading = false;
this.userImageService.notifyImageUpdate();
this.closeModal();
},
error: (error) => {
Expand Down
14 changes: 14 additions & 0 deletions postrify-frontend/src/app/services/user-image.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
providedIn: 'root',
})
export class UserImageService {
private imageUpdateSource = new BehaviorSubject<void>(undefined);
imageUpdated$ = this.imageUpdateSource.asObservable();

notifyImageUpdate() {
this.imageUpdateSource.next();
}
}

0 comments on commit a7100ae

Please sign in to comment.