From a84f9059df8e577c8bbeb6444de26e6acbe076c9 Mon Sep 17 00:00:00 2001 From: MohammedKevin Date: Thu, 13 Jun 2024 16:59:35 +0200 Subject: [PATCH] feat(#35): link frontend and backend --- .../datagenerator/TestDataGenerator.java | 50 ++++++++++++ .../backend/endpoint/SharedMediaEndpoint.java | 2 + .../endpoint/dto/SharedMediaMetadataDto.java | 9 -- .../backend/entity/SharedMedia.java | 6 ++ backend/src/main/resources/application.yml | 2 +- backend/src/main/resources/testimage.png | Bin 0 -> 254 bytes .../groupphase/backend/basetest/TestData.java | 5 +- .../party-picture-card.component.html | 41 ++++++---- .../party-picture-card.component.scss | 77 +++++++++--------- .../party-picture-card.component.spec.ts | 7 +- .../party-picture-card.component.ts | 59 +++++++++++--- .../party-pics-approve.component.html | 8 +- .../party-pics-approve.component.scss | 33 ++++---- .../party-pics-approve.component.spec.ts | 7 +- .../party-pics-approve.component.ts | 71 +++++++++------- 15 files changed, 239 insertions(+), 138 deletions(-) create mode 100644 backend/src/main/resources/testimage.png diff --git a/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/datagenerator/TestDataGenerator.java b/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/datagenerator/TestDataGenerator.java index a78cefe..04c1386 100644 --- a/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/datagenerator/TestDataGenerator.java +++ b/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/datagenerator/TestDataGenerator.java @@ -3,13 +3,16 @@ package at.ac.tuwien.sepr.groupphase.backend.datagenerator; import at.ac.tuwien.sepr.groupphase.backend.endpoint.dto.TournamentUpdateQualificationMatchDto; import at.ac.tuwien.sepr.groupphase.backend.endpoint.dto.TournamentUpdateQualificationMatchDto.DrinksPickupDto; import at.ac.tuwien.sepr.groupphase.backend.endpoint.dto.TournamentUpdateQualificationMatchDto.ScoreUpdateDto; +import at.ac.tuwien.sepr.groupphase.backend.endpoint.dto.SharedMediaCreateDto; import at.ac.tuwien.sepr.groupphase.backend.entity.ApplicationUser; import at.ac.tuwien.sepr.groupphase.backend.entity.BeerPongTable; +import at.ac.tuwien.sepr.groupphase.backend.entity.SharedMedia; import at.ac.tuwien.sepr.groupphase.backend.entity.Team; import at.ac.tuwien.sepr.groupphase.backend.entity.Tournament; import at.ac.tuwien.sepr.groupphase.backend.entity.domainservice.MatchDomainService; import at.ac.tuwien.sepr.groupphase.backend.repository.BeerPongTableRepository; import at.ac.tuwien.sepr.groupphase.backend.repository.QualificationParticipationRepository; +import at.ac.tuwien.sepr.groupphase.backend.repository.SharedMediaRepository; import at.ac.tuwien.sepr.groupphase.backend.repository.TeamRepository; import at.ac.tuwien.sepr.groupphase.backend.repository.TournamentRepository; import at.ac.tuwien.sepr.groupphase.backend.repository.UserRepository; @@ -23,10 +26,14 @@ import lombok.AllArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Profile; +import org.springframework.core.io.ClassPathResource; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; +import java.io.IOException; import java.lang.invoke.MethodHandles; +import java.nio.file.Files; +import java.util.ArrayList; import java.util.List; import java.util.stream.IntStream; @@ -50,6 +57,7 @@ public class TestDataGenerator { private final TournamentQualificationService qualificationService; private final TournamentKoPhaseService koPhaseService; private final QualificationParticipationRepository qualificationParticipationRepository; + private final SharedMediaRepository sharedMediaRepository; public void generateTestUser() { userRepository.deleteAll(); @@ -103,6 +111,48 @@ public class TestDataGenerator { .toList(); beerPongTableRepository.saveAllAndFlush(tables3); matchDomainService.scheduleQualiMatches(tournament3.getId()); + + List tournaments = new ArrayList<>(); + tournaments.add(tournament); + tournaments.add(tournament2); + tournaments.add(tournament3); + addTestImagesToTournaments(tournaments); + } + + private void addTestImagesToTournaments(List tournaments) { + tournaments.forEach(tournament -> { + try { + uploadImageToTournament(tournament, "John Smith", "World Chess Championship", "testimage.png"); + uploadImageToTournament(tournament, "Emily Johnson", "Grand Slam Tennis Tournament", "testimage.png"); + uploadImageToTournament(tournament, "Michael Brown", "Olympic Games 2024", "testimage.png"); + uploadImageToTournament(tournament, "Jessica Martinez", "FIFA World Cup", "testimage.png"); + uploadImageToTournament(tournament, "David Garcia", "NBA Finals", "testimage.png"); + uploadImageToTournament(tournament, "Jane Doe", "Super Bowl", "testimage.png"); + uploadImageToTournament(tournament, "Andrew Wilson", "Rugby World Cup", "testimage.png"); + uploadImageToTournament(tournament, "Sophia Lee", "Australian Open", "testimage.png"); + uploadImageToTournament(tournament, "Ethan Clark", "UEFA Champions League", "testimage.png"); + uploadImageToTournament(tournament, "Olivia Scott", "Wimbledon", "testimage.png"); + } catch (IOException e) { + LOGGER.error("Failed to upload test images to tournament {}", tournament.getName(), e); + } + }); + } + + private void uploadImageToTournament(Tournament tournament, String author, String title, String imagePath) throws IOException { + SharedMediaCreateDto data = new SharedMediaCreateDto(); + data.setAuthor(author); + data.setTitle(title); + data.setTournamentId(tournament.getId()); + + byte[] imageBytes = Files.readAllBytes(new ClassPathResource(imagePath).getFile().toPath()); + + SharedMedia sharedMedia = new SharedMedia(); + sharedMedia.setAuthor(author); + sharedMedia.setTitle(title); + sharedMedia.setImage(imageBytes); + sharedMedia.setTournament(tournament); + + sharedMediaRepository.saveAndFlush(sharedMedia); } private void generateTestTournamentsWithFinishedQualificationAndStartedKoPhase() { diff --git a/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/endpoint/SharedMediaEndpoint.java b/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/endpoint/SharedMediaEndpoint.java index d1893a2..fd06695 100644 --- a/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/endpoint/SharedMediaEndpoint.java +++ b/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/endpoint/SharedMediaEndpoint.java @@ -8,6 +8,7 @@ import at.ac.tuwien.sepr.groupphase.backend.endpoint.dto.SharedMediaMetadataDto; import at.ac.tuwien.sepr.groupphase.backend.endpoint.mapper.SharedMediaMapper; import at.ac.tuwien.sepr.groupphase.backend.exception.NotFoundException; import at.ac.tuwien.sepr.groupphase.backend.service.SharedMediaService; +import jakarta.annotation.security.PermitAll; import lombok.AllArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,6 +40,7 @@ public class SharedMediaEndpoint { private final SharedMediaMapper sharedMediaMapper; //public for upload of images + @PermitAll @ResponseStatus(HttpStatus.CREATED) @PostMapping public SharedMediaMetadataDto createSharedMedia( diff --git a/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/endpoint/dto/SharedMediaMetadataDto.java b/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/endpoint/dto/SharedMediaMetadataDto.java index 35f7c19..5f2605f 100644 --- a/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/endpoint/dto/SharedMediaMetadataDto.java +++ b/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/endpoint/dto/SharedMediaMetadataDto.java @@ -1,18 +1,9 @@ package at.ac.tuwien.sepr.groupphase.backend.endpoint.dto; -import at.ac.tuwien.sepr.groupphase.backend.entity.SharedMedia; public record SharedMediaMetadataDto( Long id, String author, String title, Long tournamentId) { - - public static SharedMediaMetadataDto fromSharedMedia(SharedMedia e) { - return new SharedMediaMetadataDto( - e.getId(), - e.getAuthor(), - e.getTitle(), - e.getTournament() != null ? e.getTournament().getId() : null); - } } diff --git a/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/entity/SharedMedia.java b/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/entity/SharedMedia.java index 98b8ba6..3d75444 100644 --- a/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/entity/SharedMedia.java +++ b/backend/src/main/java/at/ac/tuwien/sepr/groupphase/backend/entity/SharedMedia.java @@ -10,6 +10,7 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.Lob; import jakarta.persistence.ManyToOne; +import jakarta.validation.constraints.Size; import lombok.Getter; import lombok.Setter; @@ -17,15 +18,20 @@ import lombok.Setter; @Getter @Setter public class SharedMedia { + private static final int MAX_IMAGE_SIZE = 2 * 1024 * 1024; // 2MB + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Size(max = 30, message = "Author can't be more than 30 characters long.") private String author; + @Size(max = 50, message = "Title can't be more than 50 characters long.") private String title; @Lob @Column(columnDefinition = "BLOB") + @Size(max = SharedMedia.MAX_IMAGE_SIZE) private byte[] image; @ManyToOne(fetch = FetchType.LAZY) diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 0ab21ec..e282529 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -16,7 +16,7 @@ spring: # Set this property to true if you want to see the executed queries show-sql: false hibernate: - ddl-auto: update + ddl-auto: create-drop # Allows to fetch lazy properties outside of the original transaction. Although this sounds helpful, the property # is disabled since it breaks the principle of least astonishment and leads to bad performance. To learn more, # follow this link: https://bit.ly/2LaX9ku diff --git a/backend/src/main/resources/testimage.png b/backend/src/main/resources/testimage.png new file mode 100644 index 0000000000000000000000000000000000000000..00857c20b199344046a809a3d367ed7b9e5a7124 GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^W+2SL1|)l2v+e>ZmSQK*5Dp-y;YjHK@+C`LBT9nv z(@M${i&7cV^YU|3b&HdWQd9GaGxAH`Gw-(pDpCb0axO|uEXmBzQwYh-O=WP&S1>eI z@G8wyFfuSQQ7|;IGBmU@HaZYJD+H(^-qXb~B%|@|`GdR-3JeDvQvP%Pv~J~}*)+p= zFXye-ap$e;GU{Xtypm@fGwIEgx@@v6)93PxWrn`Q2}s*4V^MW-oqP~z6@#a%pUXO@ GgeCy0Y*iot literal 0 HcmV?d00001 diff --git a/backend/src/test/java/at/ac/tuwien/sepr/groupphase/backend/basetest/TestData.java b/backend/src/test/java/at/ac/tuwien/sepr/groupphase/backend/basetest/TestData.java index d058707..f3ee692 100644 --- a/backend/src/test/java/at/ac/tuwien/sepr/groupphase/backend/basetest/TestData.java +++ b/backend/src/test/java/at/ac/tuwien/sepr/groupphase/backend/basetest/TestData.java @@ -13,6 +13,7 @@ import at.ac.tuwien.sepr.groupphase.backend.repository.TeamRepository; import at.ac.tuwien.sepr.groupphase.backend.repository.TournamentRepository; import at.ac.tuwien.sepr.groupphase.backend.repository.UserRepository; import at.ac.tuwien.sepr.groupphase.backend.service.TournamentKoPhaseService; +import at.ac.tuwien.sepr.groupphase.backend.repository.*; import at.ac.tuwien.sepr.groupphase.backend.service.TournamentQualificationService; import at.ac.tuwien.sepr.groupphase.backend.service.TournamentService; import at.ac.tuwien.sepr.groupphase.backend.service.TournamentTeamService; @@ -57,6 +58,7 @@ public class TestData { @Autowired private QualificationParticipationRepository qualificationParticipationRepository; + private SharedMediaRepository sharedMediaRepository; protected String BASE_URI = "/api/v1"; protected String TOURNAMENT_BASE_URI = BASE_URI + "/tournaments"; @@ -279,7 +281,8 @@ public class TestData { beerPongTableRepository, matchDomainService, tournamentQualificationService, this.qualificationService, this.koPhaseService, - this.qualificationParticipationRepository); + this.qualificationParticipationRepository, + sharedMediaRepository); dataGenerator.generateTestUser(); dataGenerator.generateTestTournaments(); } diff --git a/frontend/src/app/components/party-picture-card/party-picture-card.component.html b/frontend/src/app/components/party-picture-card/party-picture-card.component.html index a9e66e0..5755cde 100644 --- a/frontend/src/app/components/party-picture-card/party-picture-card.component.html +++ b/frontend/src/app/components/party-picture-card/party-picture-card.component.html @@ -1,20 +1,25 @@ -
- party pic +
+ party pic +
+
+

Author: {{ picture?.author }}

+

{{ picture?.title }}

+
+
+
11:00
+
+ +
-
-

Author: {{picture?.author}}

-

{{picture?.title}}

-
-
-
11:00
-
- - -
-
- \ No newline at end of file +
+ diff --git a/frontend/src/app/components/party-picture-card/party-picture-card.component.scss b/frontend/src/app/components/party-picture-card/party-picture-card.component.scss index 2b23e53..5918855 100644 --- a/frontend/src/app/components/party-picture-card/party-picture-card.component.scss +++ b/frontend/src/app/components/party-picture-card/party-picture-card.component.scss @@ -1,57 +1,56 @@ .party-picture-card { - width: 20rem; - padding-left: 2rem; - padding-right: 2rem; - padding-top: 2rem; - box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.2); - margin: 1rem; - display: flex; - border-radius: 0.5rem; - overflow: hidden; - justify-content: center; - align-items: center; - position: relative; - display: flex; - flex-direction: column; - justify-content: space-between; + width: 20rem; + padding-left: 2rem; + padding-right: 2rem; + padding-top: 2rem; + box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.2); + margin: 1rem; + display: flex; + border-radius: 0.5rem; + overflow: hidden; + justify-content: center; + align-items: center; + position: relative; + display: flex; + flex-direction: column; + justify-content: space-between; } .image-container { - width: 100%; - padding: 1rem; - height: 20rem; /* Fixed height for the image container */ - background-color: rgb(235, 235, 235); /* Grey background */ - display: flex; - justify-content: center; - align-items: center; + width: 100%; + padding: 1rem; + height: 20rem; /* Fixed height for the image container */ + background-color: rgb(235, 235, 235); /* Grey background */ + display: flex; + justify-content: center; + align-items: center; } .images { - max-width: 100%; - max-height: 100%; - width: auto; - height: auto; - display: block; - object-fit: contain; /* Ensure the image is contained within the container */ + max-width: 100%; + max-height: 100%; + width: auto; + height: auto; + display: block; + object-fit: contain; /* Ensure the image is contained within the container */ } -.bottom-bar{ - width: 100%; - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; +.bottom-bar { + width: 100%; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; } -.middle-bar{ - width: 100%; +.middle-bar { + width: 100%; } h5 { - color: grey + color: grey; } p { - color: rgb(80, 80, 80) + color: rgb(80, 80, 80); } - diff --git a/frontend/src/app/components/party-picture-card/party-picture-card.component.spec.ts b/frontend/src/app/components/party-picture-card/party-picture-card.component.spec.ts index b231c23..15ec390 100644 --- a/frontend/src/app/components/party-picture-card/party-picture-card.component.spec.ts +++ b/frontend/src/app/components/party-picture-card/party-picture-card.component.spec.ts @@ -8,10 +8,9 @@ describe('PartyPictureCardComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [PartyPictureCardComponent] - }) - .compileComponents(); - + imports: [PartyPictureCardComponent], + }).compileComponents(); + fixture = TestBed.createComponent(PartyPictureCardComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/frontend/src/app/components/party-picture-card/party-picture-card.component.ts b/frontend/src/app/components/party-picture-card/party-picture-card.component.ts index d771563..c9259b7 100644 --- a/frontend/src/app/components/party-picture-card/party-picture-card.component.ts +++ b/frontend/src/app/components/party-picture-card/party-picture-card.component.ts @@ -1,27 +1,62 @@ -import { Component, Input } from '@angular/core'; +import { Component, Input, OnInit, OnDestroy, ElementRef } from '@angular/core'; import { MatCard } from '@angular/material/card'; import { MatIcon } from '@angular/material/icon'; -import { ConfirmationService } from '../../services/confirmation.service'; import { MatIconButton } from '@angular/material/button'; import { MatTooltip } from '@angular/material/tooltip'; - -interface PictureDTO { - source: string; - author: string; - title: string; -} +import { SharedMediaMetadataDto } from '../../../../openapi-generated'; +import { SharedMediaEndpointService } from '@api'; +import { ConfirmationService } from '../../services/confirmation.service'; @Component({ selector: 'app-party-picture-card', standalone: true, imports: [MatCard, MatIcon, MatIconButton, MatTooltip], templateUrl: './party-picture-card.component.html', - styleUrl: './party-picture-card.component.scss', + styleUrls: ['./party-picture-card.component.scss'], }) -export class PartyPictureCardComponent { - @Input() picture: PictureDTO | undefined; +export class PartyPictureCardComponent implements OnInit, OnDestroy { + @Input() picture: SharedMediaMetadataDto | undefined; + imageUrl: string | undefined; - constructor(private confirmationService: ConfirmationService) {} + private observer: IntersectionObserver | undefined; + + constructor( + private confirmationService: ConfirmationService, + private sharedMediaService: SharedMediaEndpointService, + private element: ElementRef, + ) {} + + ngOnInit(): void { + this.observer = new IntersectionObserver(entries => { + entries.forEach(entry => { + if (entry.isIntersecting && this.picture && this.picture.id) { + this.loadImage(this.picture.id); + this.observer?.unobserve(this.element.nativeElement); + } + }); + }); + + this.observer.observe(this.element.nativeElement); + } + + ngOnDestroy(): void { + if (this.observer) { + this.observer.disconnect(); + } + } + + loadImage(sharedMediaId: number): void { + this.sharedMediaService.getSharedMediaImage(sharedMediaId).subscribe( + (response: any) => { + // Create a blob URL from the received Blob + this.imageUrl = URL.createObjectURL(response); + }, + (error: any) => { + // Handle errors + console.error('Error fetching shared media image:', error); + }, + ); + } async openConfirmDialog(): Promise { if (await this.confirmationService.openConfirmationDialog('approve picture')) { diff --git a/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.html b/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.html index 1611409..6d94dc6 100644 --- a/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.html +++ b/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.html @@ -1,9 +1,9 @@ - +
- @for (picture of getPictures(); track picture) { - - } + @for (picture of getPictures(); track picture) { + + }
diff --git a/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.scss b/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.scss index b9844ff..f04d7a9 100644 --- a/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.scss +++ b/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.scss @@ -1,22 +1,21 @@ .picture-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); - gap: 1rem; - width: 100%; - padding: 1rem; - box-sizing: border-box; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); + gap: 1rem; + width: 100%; + padding: 1rem; + box-sizing: border-box; } .party-picture-card { - width: 100%; - padding: 2rem; - box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.2); - margin: 0; - display: flex; - border-radius: 0.5rem; - overflow: hidden; - justify-content: center; - align-items: center; - position: relative; + width: 100%; + padding: 2rem; + box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.2); + margin: 0; + display: flex; + border-radius: 0.5rem; + overflow: hidden; + justify-content: center; + align-items: center; + position: relative; } - diff --git a/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.spec.ts b/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.spec.ts index f8a58b8..d9858f4 100644 --- a/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.spec.ts +++ b/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.spec.ts @@ -8,10 +8,9 @@ describe('PartyPicsApproveComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [PartyPicsApproveComponent] - }) - .compileComponents(); - + imports: [PartyPicsApproveComponent], + }).compileComponents(); + fixture = TestBed.createComponent(PartyPicsApproveComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.ts b/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.ts index 491781e..c3269a9 100644 --- a/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.ts +++ b/frontend/src/app/components/party-pictures-approve/party-pics-approve.component.ts @@ -1,43 +1,56 @@ -import { Component, input } from '@angular/core'; -import { HeaderCardComponent } from '../header-card/header-card.component'; -import { RouterModule } from '@angular/router'; +import { Component, OnInit, Input, input } from '@angular/core'; import { MatButton } from '@angular/material/button'; import { MatCard } from '@angular/material/card'; +import { HeaderCardComponent } from '../header-card/header-card.component'; import { PartyPictureCardComponent } from '../party-picture-card/party-picture-card.component'; - -interface PictureDTO { - source: string; - author: string; - title: string; -} - -const pics = [ - { - source: 'https://picsum.photos/200/300', - author: 'John Smith', - title: 'Sunset Over the Mountains', - }, - { source: 'https://picsum.photos/300/200', author: 'Jane Doe', title: 'Cityscape at Dusk' }, - { source: 'https://picsum.photos/300/300', author: 'Alice Johnson', title: 'Forest Pathway' }, - { source: 'https://picsum.photos/200/300', author: 'Robert Brown', title: 'Ocean Waves' }, - { source: 'https://picsum.photos/500/200', author: 'Emily Davis', title: 'Desert Mirage' }, - { source: 'https://picsum.photos/500/300', author: 'Michael Wilson', title: 'Winter Wonderland' }, - { source: 'https://picsum.photos/500/300', author: 'Sarah Thompson', title: 'Spring Blossoms' }, - { source: 'https://picsum.photos/300/200', author: 'David Martinez', title: 'Autumn Leaves' }, - { source: 'https://picsum.photos/300/300', author: 'Laura Taylor', title: 'Night Sky' }, -]; +import { SharedMediaEndpointService, SharedMediaMetadataDto } from '@api'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { RouterModule } from '@angular/router'; @Component({ selector: 'app-party-pics-approve', standalone: true, imports: [MatButton, MatCard, HeaderCardComponent, RouterModule, PartyPictureCardComponent], templateUrl: './party-pics-approve.component.html', - styleUrl: './party-pics-approve.component.scss', + styleUrls: ['./party-pics-approve.component.scss'], }) -export class PartyPicsApproveComponent { +export class PartyPicsApproveComponent implements OnInit { tournamentId = input.required(); + pictures: SharedMediaMetadataDto[] = []; - getPictures(): PictureDTO[] { - return pics; + constructor( + private sharedMediaService: SharedMediaEndpointService, + private snackBar: MatSnackBar, + ) {} + + getPictures(): SharedMediaMetadataDto[] { + return this.pictures; + } + + ngOnInit(): void { + this.fetchPictures(); + } + + fetchPictures(): void { + this.sharedMediaService.getSharedMediaByTournament(this.tournamentId()).subscribe({ + next: (data: SharedMediaMetadataDto[]) => { + this.pictures = data; + }, + error: error => { + this.defaultServiceErrorHandling(error); + }, + }); + } + + private defaultServiceErrorHandling(error: any): void { + let errorMessage = ''; + if (typeof error.error === 'object') { + errorMessage = error.error.error; + } else { + errorMessage = error.error; + } + this.snackBar.open(errorMessage, 'OK', { + duration: 5000, + }); } }