diff --git a/client/src/app/posts/post-details/post-details.component.html b/client/src/app/posts/post-details/post-details.component.html index 28d51fad78cb776d5d694f0fa20779b07b9a7abb..36b87b33831c109a91536434921ccafc44d25061 100644 --- a/client/src/app/posts/post-details/post-details.component.html +++ b/client/src/app/posts/post-details/post-details.component.html @@ -36,13 +36,15 @@ <div *ngIf="userId != post.getOwner" class="buttonContainer"> <a [href]="'mailto:'+owner.getEmail"><app-button class="ownerButton" text="Kontakt selger" (click)="contactPost()"></app-button></a> + <app-button *ngIf="userId != post.getOwner && !isFavourited" text="Legg til som favoritt ♡" (click)="addFavourite()"></app-button> + <app-button *ngIf="userId != post.getOwner && isFavourited" text="Slett fra dine favoritter" (click)="removeFavourite()"></app-button> </div> <div *ngIf="userId == post.getOwner || user.getIsAdmin" class="buttonContainer"> <app-button class="ownerButton" text="Rediger annonse" (click)="editPost()"></app-button> <app-button class="ownerButton" text="Slett annonse" (click)="deletePost()"></app-button> - <div *ngIf="post.getStatus != 1"> - <app-button class="ownerButton" text="Marker solgt" (click)="markClosePost()"></app-button> - </div> + </div> + <div *ngIf="userId == post.getOwner && post.getStatus != 1"> + <app-button class="ownerButton" text="Marker solgt" (click)="markClosePost()"></app-button> </div> </div> </div> diff --git a/client/src/app/posts/post-details/post-details.component.scss b/client/src/app/posts/post-details/post-details.component.scss index ae4a555fee5eb6f3529533b53b043452c3d29692..a4515594cf79755734821072e177aecd38d07caf 100644 --- a/client/src/app/posts/post-details/post-details.component.scss +++ b/client/src/app/posts/post-details/post-details.component.scss @@ -75,6 +75,7 @@ div.container{ margin-top: 30px; display: grid; gap: 15px; + margin-bottom: 15px; } hr{ @@ -97,6 +98,7 @@ div.container{ p#timestamp{ margin-top: 30px; font-size: 14pt; + margin-bottom: 10px; } } } diff --git a/client/src/app/posts/post-details/post-details.component.ts b/client/src/app/posts/post-details/post-details.component.ts index 337853ed20b0a7f8abc1873d75955ccf6a481c34..7070aaee4933d850878475823a7715c91005e520 100644 --- a/client/src/app/posts/post-details/post-details.component.ts +++ b/client/src/app/posts/post-details/post-details.component.ts @@ -20,6 +20,7 @@ export class PostDetailsComponent implements OnInit { user: User = new User(); isAdmin: number = 0; userId: number = 0; + isFavourited: boolean = false; soldToUser: number = 0; constructor(private postService: PostService, private activatedRoute: ActivatedRoute, private router: Router, @@ -39,7 +40,8 @@ export class PostDetailsComponent implements OnInit { // Gets Post with id from database this.postService.getPost(id).then(post => { this.post = post; - + // Check if post is favourited + this.checkFavourite(); // Gets Post owner from database this.userService.getUser(this.post.getOwner).then(user => { this.owner = user; @@ -80,6 +82,18 @@ export class PostDetailsComponent implements OnInit { } } + /** + * Add post to favourites in database + */ + addFavourite() { + // Check if user is not the owner of the post + if (this.userId != this.post.getOwner) { + this.postService.addFavourite(this.post.getId, this.userId).then(data => { + console.log("Successfully added post to favourites: " + this.post.getId); + this.isFavourited = true; + }); + } + } /** * Get users in relation postContacted in database and opens popup */ @@ -91,8 +105,19 @@ export class PostDetailsComponent implements OnInit { console.log(error); }); } - // Open popup - this.contactPopup = true; + } + + /** + * Check if post is favourited in database + */ + checkFavourite() { + // Check if user is not the owner of the post + if (this.userId != this.post.getOwner) { + this.postService.getFavourite(this.post.getId, this.userId).then(data => { + console.log("Successfully received post from favourites: " + this.post.getId); + this.isFavourited = data; + }); + } } closePopup() { this.contactPopup = false; @@ -122,6 +147,18 @@ export class PostDetailsComponent implements OnInit { }); } } + /** + * Remove post from favourites in database + */ + removeFavourite() { + // Check if user is not the owner of the post + if (this.userId != this.post.getOwner) { + this.postService.deleteFavourite(this.post.getId, this.userId).then(data => { + console.log("Successfully removed post from favourites: " + this.post.getId); + this.isFavourited = false; + }); + } + } /** * Add user to postContact relation in database diff --git a/client/src/app/posts/post.service.ts b/client/src/app/posts/post.service.ts index 074f0c6ab8d29edee2bbd7505cd32bd605f5eb4c..0230ace215fd81300b20197a2b7bf7044b471ef4 100644 --- a/client/src/app/posts/post.service.ts +++ b/client/src/app/posts/post.service.ts @@ -11,6 +11,7 @@ export class PostService { postUrl = "api/post/"; categoryUrl = "api/category/"; + favouriteUrl = "api/post/favourite/"; contactUrl = "api/post/contact/"; reviewUrl = "api/post/review/"; @@ -371,4 +372,117 @@ export class PostService { private get_posts_by_user_id(userId: number) { return this.http.get(this.postUrl, {params: {userId: String(userId)}}); } + + /** + * Check favourite status in database by id. + */ + getFavourite(id: number, userId: number): Promise<any> { + return new Promise<any>( + (resolve, reject) => { + this.get_favourite(id, userId).subscribe((data: any) => { + try { + let favourited = false; + if (data?.data[0]?.favourited == 1) { + favourited = true; + } + resolve(favourited); + } catch (err: any) { + reject(err); + } + }, + (err: any) => { + console.log(err.message); + reject(err); + }); + } + ); + } + + private get_favourite(id: number, userId: number) { + return this.http.get(this.favouriteUrl + id + "/" + userId); + } + + /** + * Delete favourite in database by id. + */ + addFavourite(id: number, userId: number): Promise<any> { + return new Promise<any>( + (resolve, reject) => { + this.add_favourite(id, userId).subscribe((data: any) => { + try { + resolve(data); + } catch (err: any) { + reject(err); + } + }, + (err: any) => { + console.log(err.message); + reject(err); + }); + } + ); + } + + private add_favourite(id: number, userId: number) { + return this.http.post(this.favouriteUrl, {id: id, userId: userId}); + } + + /** + * Delete favourite in database by id. + */ + deleteFavourite(id: number, userId: number): Promise<any> { + return new Promise<any>( + (resolve, reject) => { + this.delete_favourite(id, userId).subscribe((data: any) => { + try { + resolve(data); + } catch (err: any) { + reject(err); + } + }, + (err: any) => { + console.log(err.message); + reject(err); + }); + } + ); + } + + private delete_favourite(id: number, userId: number) { + return this.http.delete(this.favouriteUrl + id + "/" + userId); + } + + /** + * Delete favourite in database by id. + */ + getFavouritedPosts(userId: number): Promise<any> { + return new Promise<any>( + (resolve, reject) => { + this.get_favourited_posts(userId).subscribe((data: any) => { + try { + let outputPosts = []; + for (let post of data.data) { + outputPosts.push(new Post(post)); + + if (!post.id || post.id == 0) { + reject("Could not deserialize Post"); + return; + } + } + resolve(outputPosts); + } catch (err: any) { + reject(err); + } + }, + (err: any) => { + console.log(err.message); + reject(err); + }); + } + ); + } + + private get_favourited_posts(userId: number) { + return this.http.get(this.favouriteUrl+userId); + } } diff --git a/client/src/app/users/user-profile/user-profile.component.html b/client/src/app/users/user-profile/user-profile.component.html index 842251d7940e76942f8b6094c501cf74effc4d64..c994e67a3a61bc73e50f9e18ec6fa6e93659fad6 100644 --- a/client/src/app/users/user-profile/user-profile.component.html +++ b/client/src/app/users/user-profile/user-profile.component.html @@ -68,9 +68,13 @@ Fotball er livet <div class="post_list"> <h2>Mine aktive annonser</h2> <div class="posts"> - <!-- All users posts for now :) --> <app-post-thumbnail *ngFor="let post of allPosts" [post]="post"></app-post-thumbnail> </div> - <a href="#">Se flere annonser</a> + <br><br> + <h2>Mine favoritter</h2> + <div class="posts"> + <app-post-thumbnail *ngFor="let post of favouritedPosts" [post]="post"></app-post-thumbnail> + </div> </div> + </div> diff --git a/client/src/app/users/user-profile/user-profile.component.ts b/client/src/app/users/user-profile/user-profile.component.ts index aa4809bc3709abcadb5a6f62f6507f9c02ec8ff4..f1cac1ef25935ea44d57ca37537ff386d2d2b99f 100644 --- a/client/src/app/users/user-profile/user-profile.component.ts +++ b/client/src/app/users/user-profile/user-profile.component.ts @@ -19,6 +19,7 @@ import { UserService } from '../user.service'; export class UserProfileComponent implements OnInit { allPosts: Array<Post> = []; + favouritedPosts: Array<Post> = []; user: User = new User(); givenReviews: Array<Review> = []; @@ -31,8 +32,9 @@ export class UserProfileComponent implements OnInit { ngOnInit(): void { this.user = this.authService.getCurrentUser(); this.getPostsByUserId(); + this.getFavouritedPosts(); } - + showReceivedUserReviews() { this.getUserReceivedReviewsByUserId(); this.receivedReviewPopup = true; @@ -56,6 +58,17 @@ export class UserProfileComponent implements OnInit { console.log(error); }); } + + getFavouritedPosts() { + // Gets all favourited posts from database, and displays them + this.postService.getFavouritedPosts(this.user.getUserId).then(posts => { + this.favouritedPosts = posts; + console.log(posts); + }).catch(error => { + console.log(error); + }); + } + /** * Gets all given reviews from database */ @@ -72,7 +85,7 @@ export class UserProfileComponent implements OnInit { */ getPostsByUserId() { this.postService.getPostsByUserId(this.user.getUserId).then(posts => { - this.allPosts = posts; + this.allPosts = posts.filter((post: Post) => post.getStatus == 0); // Active posts }).catch(error => { console.log(error); }); diff --git a/server/src/controllers/postController/index.ts b/server/src/controllers/postController/index.ts index 1fa7f55363dfe125abe0cfd5204f70dea521f5ae..b2efec37dcca2e8121ff45850d42b12f62e5ba7b 100644 --- a/server/src/controllers/postController/index.ts +++ b/server/src/controllers/postController/index.ts @@ -43,6 +43,25 @@ router.route("/").post(async (request: Request, response: Response) => { } }); +// Add favourite post by id and userId `/api/post/favourite/` +router.route("/favourite").post(authenticateToken, async (request: Request, response: Response) => { + const {id, userId} = request.body; + try { + if (id == undefined || userId == undefined) return response.status(500).send("Error"); + // Check for user duplicates + const duplicate_input = "SELECT * FROM postFavourite WHERE id=? AND userId=?;" + const user = await query(duplicate_input,[id, userId]); + const retrievedUserObj = Object.values(JSON.parse(JSON.stringify(user.data)))[0]; + if (retrievedUserObj) { + return response.status(403).send("Already favourited!"); + } + const input = `INSERT INTO postFavourite (id, userId) VALUES (?, ?);`; + response.status(200).json(await query(input, [id, userId])); + } catch (error) { + response.status(400).send("Bad Request"); + } +}); + // Contact post with body id and userId`/api/post/contact/` router.route("/contact").post(authenticateToken, async (request: Request, response: Response) => { const {id, userId} = request.body; @@ -175,6 +194,31 @@ router.route("/:id").get(async (request: Request, response: Response) => { } }); +// Get status of post is favoritted by id `/api/post/favourite/:id/:userId` +router.route("/favourite/:id/:userId").get(authenticateToken, async (request: Request, response: Response) => { + const id: string = request.params.id as string; + const userId: string = request.params.userId as string; + try { + if (id == undefined || userId == undefined) return response.status(500).send("Error"); + const input = `SELECT COUNT(*) as favourited FROM postFavourite WHERE id = ? AND userId = ?;`; + response.status(200).json(await query(input, [parseInt(id), parseInt(userId)])); + } catch (error) { + response.status(400).send("Bad Request"); + } +}); + +// Get favourited post of userid `/api/post/favourite/:userId` +router.route("/favourite/:userId").get(authenticateToken, async (request: Request, response: Response) => { + const userId: string = request.params.userId as string; + try { + if (userId == undefined) return response.status(500).send("Error"); + const input = `SELECT P.id, P.title, P.description, P.price, P.timestamp, P.owner, P.categoryId, P.imageUrl, P.status FROM postFavourite as PF INNER JOIN post as P ON P.id = PF.id WHERE PF.userId = ?;`; + response.status(200).json(await query(input, [parseInt(userId)])); + } catch (error) { + response.status(400).send("Bad Request"); + } +}); + // Get users relating to contact post with params postId: `/api/post/contact/:id` router.route("/contact/:id").get(authenticateToken, async (request: Request, response: Response) => { const postId: string = request.params.id as string; @@ -283,4 +327,17 @@ router.route("/:id").delete(authenticateToken, async (request: Request, response } }); +// Remove favourites with id and userId `/api/post/favourite/:id/:userId` +router.route("/favourite/:id/:userId").delete(authenticateToken, async (request: Request, response: Response) => { + const id: string = request.params.id as string; + const userId: string = request.params.userId as string; + try { + if (id == undefined || userId == undefined) return response.status(500).send("Error"); + response + .status(200) + .json(await query("DELETE FROM postFavourite WHERE id=? AND userId=?;", [parseInt(id), parseInt(userId)])); + } catch (error) { + response.status(400).send("Bad Request"); + } +}); export default router; \ No newline at end of file