Skip to content

Feature/8044/display news likes and details for admins on eco news page #3563

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

holus-bolus
Copy link
Contributor

@holus-bolus holus-bolus commented Feb 11, 2025

Summary by CodeRabbit

  • New Features

    • Users can now dislike comments, enhancing interactivity.
    • Like/dislike actions on events now provide more detailed feedback, ensuring updated reaction counts.
    • New properties added to enhance comment and event data structures, allowing for better tracking of user interactions.
    • A new interface for LikeResponse has been introduced to provide a structured response for like actions.
  • Refactor

    • Streamlined event reaction handling to improve UI synchronization.
    • Updated processing for like/dislike actions, resulting in more accurate and responsive displays.
    • Improved method structures for handling likes and dislikes across various components and services.
    • Enhanced comment update logic to utilize full object updates instead of count-based.
  • Bug Fixes

    • Corrected the like/dislike functionality to ensure accurate counts and user feedback.
    • Fixed issues with event display metrics to show net likes instead of separate like and dislike counts.

This comment was marked as resolved.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🔭 Outside diff range comments (1)
src/app/main/component/events/services/events.service.ts (1)

267-269: 🛠️ Refactor suggestion

Consider removing redundant method.

The postToggleLike method appears to be redundant with the new likeEvent method. Consider removing it or refactoring to use one consistent implementation.

🧹 Nitpick comments (7)
src/app/main/component/events/models/events.interface.ts (1)

172-173: Consider making the dislikes property optional for backward compatibility.

The dislikes property should be marked as optional to maintain backward compatibility with existing event responses that may not include this field.

-  dislikes: number;
+  dislikes?: number;
src/app/main/component/events/services/events.service.ts (1)

46-48: Define a specific return type for the API response.

Using Observable<any> reduces type safety. Consider defining an interface for the API response.

-  likeEvent(eventId: number): Observable<any> {
+  interface LikeResponse {
+    success: boolean;
+    message?: string;
+  }
+  likeEvent(eventId: number): Observable<LikeResponse> {
src/app/main/component/shared/components/events-list-item/events-list-item.component.ts (1)

383-383: Standardize method naming convention.

The methods use inconsistent naming: likePost vs dislikePost. Consider renaming to likeEvent and dislikeEvent to match the service method names.

-  likePost() {
+  likeEvent() {
-  dislikePost() {
+  dislikeEvent() {

Also applies to: 396-396

src/app/main/component/events/components/events-list/events-list.component.ts (2)

142-164: Simplify reaction update logic.

The updateEventReaction method has complex nested conditions that could be simplified for better readability.

   private updateEventReaction(event: EventListResponse, reactionType: 'like' | 'dislike'): void {
     const i = this.eventsList.findIndex((e) => e.id === event.id);
     if (i !== -1) {
       const current = this.eventsList[i];
-      if (reactionType === 'like') {
-        if (!current.isLiked) {
-          current.likes++;
-          current.isLiked = true;
-          current.isDisliked = false;
-        }
-      } else {
-        if (current.isDisliked) {
-          current.isDisliked = false;
-        } else {
-          if (current.isLiked && current.likes > 0) {
-            current.likes--;
-            current.isLiked = false;
-          }
-          current.isDisliked = true;
-        }
-      }
+      switch (reactionType) {
+        case 'like':
+          if (!current.isLiked) {
+            current.likes++;
+            current.isLiked = true;
+            current.isDisliked = false;
+          }
+          break;
+        case 'dislike':
+          if (current.isLiked && current.likes > 0) {
+            current.likes--;
+            current.isLiked = false;
+          }
+          current.isDisliked = !current.isDisliked;
+          break;
+      }
     }
   }

114-119: Handle event not found case.

The refreshEventInList method should handle the case when the event is not found in the list.

   private refreshEventInList(updatedEvent: EventListResponse): void {
     const index = this.eventsList.findIndex((e) => e.id === updatedEvent.id);
-    if (index !== -1) {
-      this.eventsList[index] = updatedEvent;
-    }
+    if (index === -1) {
+      console.warn(`Event with ID ${updatedEvent.id} not found in the list`);
+      return;
+    }
+    this.eventsList[index] = updatedEvent;
   }
src/app/main/component/shared/components/events-list-item/events-list-item.component.scss (1)

18-20: Optimize icon rotation animation performance.

The rotation transform could benefit from hardware acceleration and smooth transitions.

Apply this diff to enhance the animation:

 .rotate-icon {
-  transform: rotate(180deg);
+  transform: rotate(180deg);
+  transform-style: preserve-3d;
+  backface-visibility: hidden;
+  transition: transform 0.2s ease;
+  will-change: transform;
 }
src/app/main/component/comments/components/comments-list/comments-list.component.scss (1)

163-173: Add interactive states and fix linting.

  1. Add empty line before nested rule
  2. Add hover and focus states for better user experience
 .comment-likes {
   display: flex;
   gap: 10px;
   align-items: center;
+
+  button {
+    padding: 8px;
+    border: none;
+    background: none;
+    cursor: pointer;
+
+    &:hover {
+      background-color: var(--quaternary-light-grey);
+      border-radius: 50%;
+    }
+
+    &:focus-visible {
+      outline: 2px solid var(--primary-color);
+      border-radius: 50%;
+    }
+
+    &.active {
+      color: var(--primary-color);
+    }
+  }
+
   .like-amount {
     font-family: var(--primary-font);
     font-size: 12px;
🧰 Tools
🪛 GitHub Actions: CI/CD GreenCityClient

[error] 167-167: Expected empty line before rule

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ce645c5 and c98ecf4.

📒 Files selected for processing (10)
  • src/app/main/component/comments/components/comments-list/comments-list.component.html (1 hunks)
  • src/app/main/component/comments/components/comments-list/comments-list.component.scss (2 hunks)
  • src/app/main/component/comments/components/comments-list/comments-list.component.ts (2 hunks)
  • src/app/main/component/events/components/events-list/events-list.component.html (1 hunks)
  • src/app/main/component/events/components/events-list/events-list.component.ts (2 hunks)
  • src/app/main/component/events/models/events.interface.ts (2 hunks)
  • src/app/main/component/events/services/events.service.ts (4 hunks)
  • src/app/main/component/shared/components/events-list-item/events-list-item.component.html (1 hunks)
  • src/app/main/component/shared/components/events-list-item/events-list-item.component.scss (1 hunks)
  • src/app/main/component/shared/components/events-list-item/events-list-item.component.ts (2 hunks)
🧰 Additional context used
🪛 GitHub Actions: CI/CD GreenCityClient
src/app/main/component/comments/components/comments-list/comments-list.component.scss

[error] 14-14: Expected empty line before rule


[error] 17-17: Expected empty line before rule


[error] 167-167: Expected empty line before rule

🔇 Additional comments (1)
src/app/main/component/events/components/events-list/events-list.component.html (1)

145-146: LGTM!

The event bindings for like/dislike status changes are properly implemented.

@holus-bolus holus-bolus self-assigned this Feb 11, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/app/main/component/events/services/events.service.ts (2)

50-60: 🛠️ Refactor suggestion

Remove debug logging and standardize error handling.

  1. Remove console.log statements from production code.
  2. Standardize error handling to match the likeEvent method.

Apply this diff:

-  dislikeEvent(eventId: number): Observable<any> {
-    return this.http.post<any>(`${this.backEnd}events/${eventId}/dislike`, {}).pipe(
-      tap((response: any) => {
-        console.log(`DISLIKE request successful. Response:`, response);
-      }),
-      catchError((error) => {
-        console.error(`DISLIKE request failed for event ID: ${eventId}`, error);
-        return throwError(error);
-      })
-    );
+  dislikeEvent(eventId: number): Observable<LikeResponse> {
+    return this.http.post<LikeResponse>(`${this.backEnd}events/${eventId}/dislike`, {}).pipe(
+      catchError((error) => throwError(error))
+    );

241-241: 🛠️ Refactor suggestion

Remove debug logging statement.

Remove the console.log statement from production code.

Apply this diff:

-    console.log(requestParams);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c98ecf4 and 2ae1634.

📒 Files selected for processing (1)
  • src/app/main/component/events/services/events.service.ts (4 hunks)

@holus-bolus holus-bolus force-pushed the feature/8044/display-news-likes-and-details-for-admins-on-eco-news-page branch from eb2f31b to bdd32dc Compare February 11, 2025 11:01
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (2)
src/app/main/component/events/services/events.service.ts (2)

58-60: 🛠️ Refactor suggestion

Improve type safety and standardize error handling.

  1. The response type any should be replaced with LikeResponse.
  2. Error handling should be consistent with other methods.

Apply this diff:

-  dislikeEvent(eventId: number): Observable<any> {
-    return this.http.post<any>(`${this.backEnd}events/${eventId}/dislike`, {}).pipe(catchError((error) => throwError(error)));
+  dislikeEvent(eventId: number): Observable<LikeResponse> {
+    return this.http.post<LikeResponse>(`${this.backEnd}events/${eventId}/dislike`, {}).pipe(
+      catchError((error) => throwError(() => error))
+    );
   }

49-56: 🛠️ Refactor suggestion

Remove duplicate functionality and improve error handling.

  1. This method duplicates the functionality of the existing postToggleLike method at line 265.
  2. Error handling could be simplified by removing the console.error statement.

Apply this diff:

-  likeEvent(eventId: number): Observable<LikeResponse> {
-    return this.http.post<LikeResponse>(`${this.backEnd}events/${eventId}/like`, {}).pipe(
-      catchError((error) => {
-        console.error('Error liking event:', error);
-        return throwError(() => error);
-      })
-    );
-  }

And update the postToggleLike method to use the LikeResponse interface:

-  postToggleLike(eventId: number): Observable<any> {
+  postToggleLike(eventId: number): Observable<LikeResponse> {
-    return this.http.post(`${this.backEnd}events/${eventId}/like`, {});
+    return this.http.post<LikeResponse>(`${this.backEnd}events/${eventId}/like`, {}).pipe(
+      catchError((error) => throwError(() => error))
+    );
   }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ae1634 and bdd32dc.

📒 Files selected for processing (5)
  • src/app/main/component/comments/components/comments-list/comments-list.component.ts (4 hunks)
  • src/app/main/component/comments/services/comments.service.ts (1 hunks)
  • src/app/main/component/events/services/events.service.ts (4 hunks)
  • src/app/main/component/shared/components/events-list-item/events-list-item.component.html (1 hunks)
  • src/app/main/component/shared/components/events-list-item/events-list-item.component.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/main/component/shared/components/events-list-item/events-list-item.component.html
🔇 Additional comments (11)
src/app/main/component/comments/components/comments-list/comments-list.component.ts (8)

9-10: Imports look good
No issues found with these added imports; they align well with the new functionality.


12-15: Enum usage is appropriate
Defining an enum for reaction types helps maintain clarity and type safety.


56-57: Good approach to manage concurrent requests
Introducing separate booleans for like and dislike actions effectively prevents overlapping requests.


62-63: Constructor injections are fine
Injecting MatDialog and MatSnackBar aligns with Angular best practices for modular services.


85-92: Bulk update logic is concise
Using Math.max to prevent negative values is a good safeguard, and the mapping approach effectively updates the targeted comment.


94-120: Consider toggling reactions
This method only increments like counts, potentially allowing multiple likes from the same user. A toggle mechanism (adding or removing a like) could help avoid inconsistent states, as previously suggested.


122-148: Same toggle suggestion applies here
Just like the like flow, consider a toggle approach to avoid inflating dislike counts if a user repeatedly dislikes the same comment.


204-207: Verify toggling logic
This assignment toggles isAdd based on the current repliedComment. Verify that the first-time toggle and subsequent toggles flow as intended, especially if repliedComment starts as null.

src/app/main/component/comments/services/comments.service.ts (1)

25-26: New method aligns with existing pattern
Introducing postDislike alongside postLike maintains symmetry and clarity in the service.

src/app/main/component/events/services/events.service.ts (1)

22-25: LGTM!

The interface is well-defined and properly types the response from the like/dislike endpoints.

src/app/main/component/shared/components/events-list-item/events-list-item.component.ts (1)

51-52: LGTM!

The event emitters are well-defined and properly typed to communicate like/dislike status changes to the parent component.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
src/app/main/component/eco-news/services/eco-news-comments.service.ts (1)

63-65: 🛠️ Refactor suggestion

Add error handling to postLike method for consistency.

The new postDislike method includes proper error handling, but it's missing in the postLike method. Let's maintain consistency across similar operations.

Apply this diff to add error handling:

   postLike(parentCommentId: number): Observable<void> {
-    return this.http.post<void>(`${this.backEnd}eco-news/comments/like?commentId=${parentCommentId}`, {});
+    return this.http.post<void>(`${this.backEnd}eco-news/comments/like?commentId=${parentCommentId}`, {}).pipe(
+      catchError((error) => {
+        console.error('Failed to post like:', error);
+        return throwError(() => error);
+      })
+    );
   }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 97b0934 and aeb2a79.

📒 Files selected for processing (1)
  • src/app/main/component/eco-news/services/eco-news-comments.service.ts (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (18.x)
🔇 Additional comments (2)
src/app/main/component/eco-news/services/eco-news-comments.service.ts (2)

3-3: LGTM! Proper error handling imports added.

The new imports for error handling operators are correctly added and well-organized with existing rxjs imports.


25-32:

✅ Verification successful

Verify URL format usage across the codebase.

Let's ensure the URL format change won't impact other parts of the application.


🏁 Script executed:

#!/bin/bash
# Search for similar URL patterns in the codebase
echo "Searching for similar comment action endpoints..."
rg -l "comments/.*like" --type ts

echo "Searching for specific dislike endpoint usage..."
rg -l "comments/.*/dislike" --type ts

Length of output: 1135


Verification Complete: URL Format is Localized

  • The search confirms that the /dislike endpoint is used only in src/app/main/component/eco-news/services/eco-news-comments.service.ts.
  • Similar endpoints using a /like pattern appear throughout the codebase and follow a consistent format.
  • There’s no evidence that the URL change will impact other parts of the application.

You can proceed with this change.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/app/main/component/events/services/events-comments.service.ts (1)

57-59: LGTM! The implementation follows established patterns.

The new postDislike method is well-implemented and maintains consistency with the existing postLike method. The implementation follows Angular's service patterns and properly handles HTTP requests.

Consider adding error handling to both postLike and postDislike methods to provide better feedback to the UI layer. For example:

 postDislike(commentId: number): Observable<void> {
-  return this.http.post<void>(`${this.backEnd}events/comments/dislike/${commentId}`, {});
+  return this.http.post<void>(`${this.backEnd}events/comments/dislike/${commentId}`, {}).pipe(
+    catchError((error) => {
+      console.error('Error disliking comment:', error);
+      throw error;
+    })
+  );
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aeb2a79 and f81cfad.

📒 Files selected for processing (1)
  • src/app/main/component/events/services/events-comments.service.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (18.x)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/assets/mocks/events/mock-events.ts (2)

243-243: Remove unnecessary inline comment.

The comment "// Added this property" is redundant and inconsistent with the rest of the file's style.

-    dislikes: 2,  // Added this property
+    dislikes: 2,

183-183: Consider adding more diverse test cases.

While the current mock data provides basic test cases for the dislikes feature, consider adding edge cases such as:

  • Zero dislikes
  • Very large numbers
  • Cases where dislikes > likes

Also applies to: 243-243, 296-296, 358-358, 515-515

src/app/main/service/habit-comments/habit-comments.service.ts (1)

34-36: Consider adding error handling and type safety.

To improve robustness and maintainability:

  1. Add retry logic for network failures
  2. Add rate limiting to prevent spam
  3. Define an interface for the response type

Example implementation:

interface DislikeResponse {
  success: boolean;
  message?: string;
}

postDislike(parentCommentId: number): Observable<DislikeResponse> {
  return this.http
    .post<DislikeResponse>(
      `${this.backEnd}habits/comments/dislike?commentId=${parentCommentId}`,
      {}
    )
    .pipe(
      retry(3),
      throttleTime(1000)
    );
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f81cfad and 25248d7.

📒 Files selected for processing (2)
  • src/app/main/service/habit-comments/habit-comments.service.ts (1 hunks)
  • src/assets/mocks/events/mock-events.ts (6 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (18.x)
🔇 Additional comments (2)
src/assets/mocks/events/mock-events.ts (1)

183-183: LGTM! Consistent implementation of dislikes property.

The dislikes property has been consistently added across all mock event objects, providing a good range of test values.

Also applies to: 243-243, 296-296, 358-358, 515-515

src/app/main/service/habit-comments/habit-comments.service.ts (1)

34-36: LGTM! Implementation follows existing patterns.

The implementation is consistent with the existing postLike method and follows the service's established patterns.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/app/main/service/localstorage/local-storage.service.spec.ts (2)

13-59: LGTM! Consider adding test cases for social interaction metrics.

The mock event object has been properly updated to include likes, dislikes, and comment counts, which aligns with the PR objectives. However, since these are new fields being added, it would be beneficial to add specific test cases that verify the handling of these social interaction metrics.

Consider adding test cases like:

it('should handle event social metrics correctly', () => {
  const eventWithMetrics = { ...mockEvent };
  service.setEventForEdit('testKey', eventWithMetrics);
  const savedEvent = JSON.parse(localStorage.getItem('testKey'));
  expect(savedEvent.likes).toBe(5);
  expect(savedEvent.dislikes).toBe(2);
  expect(savedEvent.countComments).toBe(7);
});

613-617: Enhance test coverage for event storage.

While the test verifies basic storage functionality, it could be improved to ensure type safety and deep object equality.

Consider enhancing the test:

it('should correctly store and retrieve the event with all properties', () => {
  const key = 'testKey';
  service.setEventForEdit(key, mockEvent);
  
  // Get and parse the stored event
  const storedEvent: EventResponse = JSON.parse(localStorage.getItem(key));
  
  // Verify type safety and deep equality
  expect(storedEvent).toBeTruthy();
  expect(storedEvent.likes).toBe(mockEvent.likes);
  expect(storedEvent.dislikes).toBe(mockEvent.dislikes);
  expect(storedEvent.countComments).toBe(mockEvent.countComments);
  expect(storedEvent.tags).toEqual(mockEvent.tags);
  expect(storedEvent.dates[0].coordinates).toEqual(mockEvent.dates[0].coordinates);
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 25248d7 and 1be65b1.

📒 Files selected for processing (1)
  • src/app/main/service/localstorage/local-storage.service.spec.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (18.x)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/app/main/component/comments/components/comments-list/comments-list.component.spec.ts (1)

14-16: LGTM! Consider organizing imports.

The new imports and module setup are comprehensive and align well with the component's functionality.

Consider organizing imports by category (Angular core, Material, shared components, models) for better maintainability:

- import { WarningPopUpComponent } from '@shared/components';
- import { AddedCommentDTO } from '../../models/comments-model';
- import { MatSnackBarModule } from '@angular/material/snack-bar';
+ // Angular Material
+ import { MatSnackBarModule } from '@angular/material/snack-bar';
+ 
+ // Shared Components
+ import { WarningPopUpComponent } from '@shared/components';
+ 
+ // Models
+ import { AddedCommentDTO } from '../../models/comments-model';

Also applies to: 77-84

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1be65b1 and b2063bc.

📒 Files selected for processing (1)
  • src/app/main/component/comments/components/comments-list/comments-list.component.spec.ts (4 hunks)
🔇 Additional comments (4)
src/app/main/component/comments/components/comments-list/comments-list.component.spec.ts (4)

46-56: LGTM! Clean mock implementations.

The mock implementations are concise and well-structured, using arrow functions for better readability.


108-109: Consider maintaining language consistency in test descriptions.

The test descriptions are in Ukrainian while the code and variables are in English. This mixed language approach might affect maintainability and collaboration.

Would you like to maintain all test descriptions in English for consistency? This would align with the codebase's primary language.

Also applies to: 112-118


120-131: LGTM! Well-structured test for comment deletion.

The test case properly verifies the deletion functionality using AddedCommentDTO and includes all necessary properties.


164-230: LGTM! Comprehensive test coverage for comment interactions.

The test cases thoroughly cover:

  • Counter updates (likes)
  • Reply functionality
  • Content form updates
  • Author verification
  • isAddingReply flag management

The tests are well-structured with clear setup and expectations.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
src/app/main/component/comments/components/comments-list/comments-list.component.spec.ts (1)

22-50: 🛠️ Refactor suggestion

Add tests for like/dislike functionality.

The new like/dislike methods need test coverage. Add the following to the service mock:

 const commentsServiceMock: any = {
   editComment: jasmine.createSpy('editComment').and.returnValue(of()),
+  postLike: jasmine.createSpy('postLike').and.returnValue(of()),
+  postDislike: jasmine.createSpy('postDislike').and.returnValue(of()),
   getActiveRepliesByPage: jasmine.createSpy('getActiveRepliesByPage').and.returnValue(
     // ... existing mock implementation
   )
 };

And add these test cases:

it('should handle successful like action', () => {
  const commentId = 1;
  component.likeComment(commentId);
  expect(commentsServiceMock.postLike).toHaveBeenCalledWith(commentId);
});

it('should handle successful dislike action', () => {
  const commentId = 1;
  component.dislikeComment(commentId);
  expect(commentsServiceMock.postDislike).toHaveBeenCalledWith(commentId);
});

it('should prevent concurrent like/dislike requests', () => {
  const commentId = 1;
  component.likeComment(commentId);
  component.likeComment(commentId);
  expect(commentsServiceMock.postLike).toHaveBeenCalledTimes(1);
});
🧹 Nitpick comments (4)
src/app/main/component/comments/components/comments-list/comments-list.component.ts (2)

81-88: Consider enhancing updateLikeDislikeCount with additional safeguards.

The method could be more robust by:

  1. Adding type safety for the comment object
  2. Adding validation for negative counts
-  private updateLikeDislikeCount(commentId: number, type: ReactionType, isAdd: boolean): void {
+  private updateLikeDislikeCount(commentId: number, type: ReactionType, isAdd: boolean): void {
+    if (!commentId || !type) {
+      console.warn('Invalid parameters passed to updateLikeDislikeCount');
+      return;
+    }
     this.elementsList = this.elementsList.map((comment) => {
       if (comment?.id === commentId) {
-        comment[type] = Math.max(0, comment[type] + (isAdd ? 1 : -1));
+        const currentCount = comment[type] || 0;
+        comment[type] = Math.max(0, currentCount + (isAdd ? 1 : -1));
       }
       return comment;
     });
   }

90-116: Improve user feedback messages for better UX.

The success and error messages could be more user-friendly and specific.

-          this.snackBar.open('Comment liked successfully', 'Close', {
+          this.snackBar.open('Thanks for liking this comment!', 'Dismiss', {
             duration: 3000
           });
-          this.snackBar.open('Failed to like the comment. Please try again.', 'Close', {
+          this.snackBar.open('Unable to like the comment. Please try again later.', 'Dismiss', {

-          this.snackBar.open('Comment disliked successfully', 'Close', {
+          this.snackBar.open('Your feedback has been recorded', 'Dismiss', {
             duration: 3000
           });
-          this.snackBar.open('Failed to dislike the comment. Please try again.', 'Close', {
+          this.snackBar.open('Unable to record your feedback. Please try again later.', 'Dismiss', {

Also applies to: 118-144

src/app/main/component/comments/components/comments-list/comments-list.component.spec.ts (1)

108-110: Fix typos in test descriptions and improve clarity.

Several test descriptions contain typos and are unclear:

  • 'return the created componennt''should create the component'
  • 'inititilez preperties''should initialize properties'

Also applies to: 112-118

src/app/main/component/events/components/events-list/events-list.component.ts (1)

141-163: Add error handling for edge cases in updateEventReaction.

The updateEventReaction method should handle edge cases where:

  1. The likes count might go negative
  2. The event might not be found in the list
 private updateEventReaction(event: EventListResponse, reactionType: 'like' | 'dislike'): void {
   const i = this.eventsList.findIndex((e) => e.id === event.id);
   if (i !== -1) {
     const current = this.eventsList[i];
     if (reactionType === 'like') {
       if (!current.isLiked) {
         current.likes++;
         current.isLiked = true;
         current.isDisliked = false;
       }
     } else {
       if (current.isDisliked) {
         current.isDisliked = false;
       } else {
-        if (current.isLiked && current.likes > 0) {
+        if (current.isLiked) {
           current.likes--;
           current.isLiked = false;
         }
         current.isDisliked = true;
       }
     }
+  } else {
+    this.toastr.error('Event not found in the list');
   }
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b2063bc and 997b808.

📒 Files selected for processing (4)
  • src/app/main/component/comments/components/comments-list/comments-list.component.spec.ts (4 hunks)
  • src/app/main/component/comments/components/comments-list/comments-list.component.ts (4 hunks)
  • src/app/main/component/comments/components/comments-list/reaction-type.enum.ts (1 hunks)
  • src/app/main/component/events/components/events-list/events-list.component.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (18.x)
🔇 Additional comments (2)
src/app/main/component/comments/components/comments-list/reaction-type.enum.ts (1)

1-4: LGTM! Well-structured enum for reaction types.

The enum provides good type safety and clear naming for reaction types.

src/app/main/component/events/components/events-list/events-list.component.ts (1)

114-119: LGTM: Efficient event list update implementation.

The refreshEventInList method efficiently updates a single event in the list without requiring a full list refresh.

@semeriak-andrii semeriak-andrii self-requested a review February 17, 2025 08:55
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/app/main/component/comments/models/comments-model.ts (1)

15-15: Consider consolidating like-related properties.

The interface has both currentUserLiked and isLiked properties which appear to serve the same purpose. Consider consolidating these properties to maintain a single source of truth and consistent naming:

-  currentUserLiked: boolean;
-  isLiked: boolean;
-  isDisliked: boolean;
+  reactionStatus: {
+    isLiked: boolean;
+    isDisliked: boolean;
+  };

Also applies to: 18-19

src/app/main/component/comments/components/comments-list/comments-list.component.ts (1)

27-27: Remove redundant processing state properties.

The isProcessingLike and isProcessingDislike properties are redundant since you're already using the isProcessing Set to track the processing state per comment.

  private isProcessing = new Set<number>();
- private isProcessingLike = false;
- private isProcessingDislike = false;

Also applies to: 56-57

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 997b808 and 652de5f.

⛔ Files ignored due to path filters (2)
  • src/assets/img/comments/dislike.png is excluded by !**/*.png
  • src/assets/img/comments/disliked.png is excluded by !**/*.png
📒 Files selected for processing (9)
  • src/app/main/component/comments/components/comments-container/comments-container.component.ts (1 hunks)
  • src/app/main/component/comments/components/comments-list/comments-list.component.html (1 hunks)
  • src/app/main/component/comments/components/comments-list/comments-list.component.scss (3 hunks)
  • src/app/main/component/comments/components/comments-list/comments-list.component.ts (5 hunks)
  • src/app/main/component/comments/models/comments-model.ts (2 hunks)
  • src/app/main/component/events/services/events.service.ts (3 hunks)
  • src/app/main/component/shared/components/events-list-item/events-list-item.component.html (1 hunks)
  • src/app/main/component/shared/components/events-list-item/events-list-item.component.scss (2 hunks)
  • src/app/main/component/shared/components/events-list-item/events-list-item.component.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/app/main/component/shared/components/events-list-item/events-list-item.component.scss
  • src/app/main/component/comments/components/comments-list/comments-list.component.scss
  • src/app/main/component/events/services/events.service.ts
  • src/app/main/component/comments/components/comments-list/comments-list.component.html
🔇 Additional comments (6)
src/app/main/component/comments/components/comments-container/comments-container.component.ts (1)

72-74: LGTM!

The initialization of the new properties isLiked and isDisliked to false is correct and follows the interface changes.

src/app/main/component/comments/components/comments-list/comments-list.component.ts (2)

86-93: Consider enhancing the like/dislike state management.

The current implementation only supports incrementing counts, which might lead to incorrect state if users change their reactions.


99-126: LGTM! Robust implementation of like/dislike functionality.

The implementation includes:

  • Proper error handling with user feedback
  • Proper cleanup of processing state
  • Proper null checks
  • Proper state updates for both like and dislike counts

Also applies to: 128-154

src/app/main/component/shared/components/events-list-item/events-list-item.component.ts (2)

51-52: LGTM! Event emitters are properly defined.

The event emitters are correctly decorated and typed for communicating like/dislike status changes.


398-415: Add authentication check before disliking.

The method needs to verify if the user is authenticated before making the API call.

src/app/main/component/shared/components/events-list-item/events-list-item.component.html (1)

99-121: LGTM! Like/dislike buttons implementation follows best practices.

The implementation includes:

  • Proper event bubbling prevention
  • ARIA attributes for accessibility
  • Semantic button elements
  • Separate counts for likes and dislikes

@holus-bolus holus-bolus force-pushed the feature/8044/display-news-likes-and-details-for-admins-on-eco-news-page branch from 652de5f to 1965343 Compare March 9, 2025 13:04
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/app/greencity/modules/events/services/events-comments.service.ts (1)

57-59: Inconsistent parameter naming and missing error handling.

The postDislike method uses commentId as parameter name while related methods like postLike use parentCommentId. For consistency, consider using the same parameter name. Also, unlike the similar methods in EventsService, there's no error handling here.

-  postDislike(commentId: number): Observable<void> {
-    return this.http.post<void>(`${this.backEnd}events/comments/dislike/${commentId}`, {});
+  postDislike(parentCommentId: number): Observable<void> {
+    return this.http.post<void>(`${this.backEnd}events/comments/dislike/${parentCommentId}`, {})
+      .pipe(
+        catchError((error) => {
+          console.error('Error disliking comment:', error);
+          return throwError(() => error);
+        })
+      );

Don't forget to add the necessary imports:

import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
src/app/greencity/modules/events/services/events.service.ts (1)

168-170: Inconsistent error handling and return type.

The dislikeEvent method has a different error handling style and return type compared to likeEvent. For consistency, consider:

  1. Using the same error handling pattern (with or without logging)
  2. Using the same return type (LikeResponse instead of any)
-  dislikeEvent(eventId: number): Observable<any> {
-    return this.http.post<any>(`${this.backEnd}events/${eventId}/dislike`, {}).pipe(catchError((error) => throwError(() => error)));
+  dislikeEvent(eventId: number): Observable<LikeResponse> {
+    return this.http.post<LikeResponse>(`${this.backEnd}events/${eventId}/dislike`, {}).pipe(
+      catchError((error) => {
+        console.error('Error disliking event:', error);
+        return throwError(() => error);
+      })
+    );
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 652de5f and 1965343.

📒 Files selected for processing (4)
  • src/app/greencity/modules/events/models/events.interface.ts (3 hunks)
  • src/app/greencity/modules/events/services/LikeResponse.ts (1 hunks)
  • src/app/greencity/modules/events/services/events-comments.service.ts (1 hunks)
  • src/app/greencity/modules/events/services/events.service.ts (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/app/greencity/modules/events/services/LikeResponse.ts
🔇 Additional comments (3)
src/app/greencity/modules/events/models/events.interface.ts (1)

151-153: LGTM! Good additions to the EventResponse interface.

The new properties for tracking dislikes and like/dislike status are well-placed and properly typed. They complement the existing likes property and provide a more complete representation of user interactions with events.

src/app/greencity/modules/events/services/events.service.ts (2)

4-4: LGTM! Appropriate imports for the new functionality.

The added imports are necessary for the new like/dislike methods and their error handling.

Also applies to: 16-17


17-17:

✅ Verification successful

Missing LikeResponse interface definition.

The LikeResponse interface is imported but not defined in the provided files. Make sure this interface exists and is properly defined.


🏁 Script executed:

#!/bin/bash
# Check if the LikeResponse interface exists
echo "Searching for LikeResponse interface definition:"
fd -e ts | xargs grep -l "interface LikeResponse"

Length of output: 319


Interface Definition Verified: The LikeResponse interface is now defined and available.

The verification shows that the file
src/app/greencity/modules/events/services/LikeResponse.ts
exists and contains the LikeResponse interface definition. Please ensure that this file correctly exports the interface (e.g., using export interface LikeResponse) so that the import in events.service.ts works as expected.

Comment on lines 159 to 166
likeEvent(eventId: number): Observable<LikeResponse> {
return this.http.post<LikeResponse>(`${this.backEnd}events/${eventId}/like`, {}).pipe(
catchError((error) => {
console.error('Error liking event:', error);
return throwError(() => error);
})
);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Consider aligning with existing postToggleLike method.

The new likeEvent method seems to overlap with the existing postToggleLike method (line 129). Consider either deprecating the old method or clarifying the different purposes in documentation.


🏁 Script executed:

#!/bin/bash
# Check if postToggleLike is still being used elsewhere in the codebase
echo "Checking usages of postToggleLike method:"
rg -A 2 -B 2 "postToggleLike" --type=ts

Length of output: 7299


Action Required: Consolidate Duplicate "Like" Methods

The new implementation of likeEvent in src/app/greencity/modules/events/services/events.service.ts overlaps significantly with the existing postToggleLike method—which is also used in both the events and eco-news modules. In particular, both methods target the same endpoint (events/${eventId}/like) and perform very similar operations, with the only notable difference being additional error handling and response typing in likeEvent.

Recommendations:

  • Consolidate or Deprecate: Consider merging these methods into a single implementation to avoid redundancy, or deprecate one if a distinct behavior is not warranted.
  • Clarify Differences: If both methods must coexist (e.g., one for stricter error reporting and another for a different usage context), update the inline documentation and external docs to clearly articulate their intended purposes and differences.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/app/greencity/shared/components/events-list-item/events-list-item.component.scss (1)

22-26: Style Update: Border Removal on #like and #dislike
Removing the border from the #like and #dislike elements aligns with the desired UI adjustments for the new like/dislike indicators. As a minor suggestion, consider whether using ID selectors is optimal for styling or if a class-based approach might offer more flexibility in the future.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1965343 and e372219.

📒 Files selected for processing (1)
  • src/app/greencity/shared/components/events-list-item/events-list-item.component.scss (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (18.x)
🔇 Additional comments (1)
src/app/greencity/shared/components/events-list-item/events-list-item.component.scss (1)

18-21: Style Update: New .rotate-icon Class Addition
The addition of the .rotate-icon class, which applies a 180-degree rotation via transform: rotate(180deg);, clearly supports the design intent for toggling icon orientation. This change is straightforward and meets the styling needs as described in the PR objectives.

Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
33.7% Coverage on New Code (required ≥ 75%)

See analysis details on SonarQube Cloud

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/app/greencity/modules/events/services/events.service.ts (1)

159-166: ⚠️ Potential issue

Action Required: Consolidate Duplicate "Like" Methods

The new implementation of likeEvent overlaps significantly with the existing postToggleLike method (line 129). Both methods target similar endpoints (events/${eventId}/like-v2 vs events/${eventId}/like) and perform very similar operations, with the main differences being additional error handling and response typing in likeEvent.

Consider:

  1. Consolidating these methods by enhancing postToggleLike with better typing and error handling
  2. Deprecating the old method if the new one should be used going forward
  3. Adding clear documentation to explain the difference between these methods
postToggleLike(eventId: number): Observable<LikeResponse> {
-  return this.http.post(`${this.backEnd}events/${eventId}/like`, {});
+  return this.http.post<LikeResponse>(`${this.backEnd}events/${eventId}/like-v2`, {}).pipe(
+    catchError((error) => {
+      console.error('Error liking event:', error);
+      return throwError(() => error);
+    })
+  );
}

// Remove this duplicate method
-likeEvent(eventId: number): Observable<LikeResponse> {
-  return this.http.post<LikeResponse>(`${this.backEnd}events/${eventId}/like-v2`, {}).pipe(
-    catchError((error) => {
-      console.error('Error liking event:', error);
-      return throwError(() => error);
-    })
-  );
-}
🧹 Nitpick comments (2)
src/app/greencity/modules/events/services/events.service.ts (2)

4-4: Consider organizing related imports together.

While the new imports are necessary for the added functionality, they could be organized more consistently. Consider grouping related imports together - RxJS operators (catchError) could be included in the existing RxJS imports, and model-related imports (LikeResponse) could be grouped with other model imports.

 import { HttpClient, HttpParams } from '@angular/common/http';
 import { Injectable, OnDestroy } from '@angular/core';
 import { environment } from '@environment/environment';
-import { Observable, ReplaySubject, throwError } from 'rxjs';
+import { Observable, ReplaySubject } from 'rxjs';
+import { throwError } from 'rxjs';
 import {
   Addresses,
   EventAttender,
   EventForm,
   EventResponse,
   EventResponseDto,
   LocationResponse,
   EventDto,
   PlaceOnline
-} from '../models/events.interface';
+} from '../models/events.interface';
+import { LikeResponse } from './LikeResponse';
 import { LanguageService } from 'src/app/shared/i18n/language.service';
-import { catchError } from 'rxjs/operators';
-import { LikeResponse } from './LikeResponse';
+import { catchError } from 'rxjs/operators';

Also applies to: 16-16, 17-17


159-170: Document the differences between like/dislike methods and their corresponding endpoints.

Adding clear documentation comments for the new methods would help explain:

  1. The purpose of the new -v2 endpoints compared to existing ones
  2. The relationship between the new methods and the existing postToggleLike method
  3. When developers should use each method
/**
 * Likes an event using the v2 endpoint.
 * @param eventId - The ID of the event to like
 * @returns An Observable containing the like response with ID and liked status
 * @see postToggleLike - Legacy method for toggling likes
 */
likeEvent(eventId: number): Observable<LikeResponse> {
  return this.http.post<LikeResponse>(`${this.backEnd}events/${eventId}/like-v2`, {}).pipe(
    catchError((error) => {
      console.error('Error liking event:', error);
      return throwError(() => error);
    })
  );
}

/**
 * Dislikes an event using the v2 endpoint.
 * @param eventId - The ID of the event to dislike
 * @returns An Observable containing the like response
 */
dislikeEvent(eventId: number): Observable<any> {
  return this.http.post<any>(`${this.backEnd}events/${eventId}/dislike-v2`, {}).pipe(catchError((error) => throwError(() => error)));
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e372219 and 71f8dce.

📒 Files selected for processing (2)
  • src/app/greencity/modules/events/services/events.service.ts (3 hunks)
  • src/app/shared/services/localstorage/local-storage.service.spec.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/app/shared/services/localstorage/local-storage.service.spec.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (18.x)

Comment on lines 159 to 170
likeEvent(eventId: number): Observable<LikeResponse> {
return this.http.post<LikeResponse>(`${this.backEnd}events/${eventId}/like-v2`, {}).pipe(
catchError((error) => {
console.error('Error liking event:', error);
return throwError(() => error);
})
);
}

dislikeEvent(eventId: number): Observable<any> {
return this.http.post<any>(`${this.backEnd}events/${eventId}/dislike-v2`, {}).pipe(catchError((error) => throwError(() => error)));
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify API endpoint naming patterns for consistency.

The new endpoints use -v2 suffix (like-v2, dislike-v2), while other endpoints in this service follow different patterns. For example, getEventById uses /v2/ in the path rather than a suffix. Ensure this follows the API's established versioning patterns.

Run the following to check endpoint versioning patterns across the codebase:


🏁 Script executed:

#!/bin/bash
# Check for different API version patterns in the codebase
echo "Checking for /v2/ pattern in paths:"
rg "this\.backEnd.*?/v2/" --type ts

echo -e "\nChecking for -v2 suffix pattern in paths:"
rg "this\.backEnd.*?-v2" --type ts

echo -e "\nChecking other version patterns:"
rg "this\.backEnd.*?(v\d|V\d)" --type ts

Length of output: 2494


Attention: API Endpoint Versioning Inconsistency

It appears that within the Events service the versioning pattern is mixed. The endpoints for liking/disliking events—likeEvent and dislikeEvent—append a -v2 suffix (e.g. ${this.backEnd}events/${eventId}/like-v2), while other endpoints (such as getEventById, createV2, and updateV2) use a /v2/ segment or embed the version directly in the action name. This discrepancy could lead to confusion or misalignment with the API’s established versioning guidelines.

Please review and either update the like/dislike endpoints to match the /v2/ pattern or confirm that the suffix approach is intentional (with appropriate documentation) for consistency.

  • File: src/app/greencity/modules/events/services/events.service.ts
    • getEventById: Uses /v2/ (e.g., ${this.backEnd}events/v2/${eventId})
    • likeEvent/dislikeEvent: Use -v2 suffix (e.g., ${this.backEnd}events/${eventId}/like-v2)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 71f8dce and 1526c17.

📒 Files selected for processing (8)
  • src/app/greencity/modules/comments/mocks/comments-mock.ts (1 hunks)
  • src/app/greencity/modules/events/components/event-details/event-details.component.spec.ts (1 hunks)
  • src/app/greencity/modules/events/components/event-details/event-details.component.ts (0 hunks)
  • src/app/greencity/modules/events/models/events.interface.ts (1 hunks)
  • src/app/greencity/modules/events/services/events-comments.service.ts (1 hunks)
  • src/app/greencity/modules/events/services/events.service.ts (0 hunks)
  • src/app/greencity/shared/components/events-list-item/events-list-item.component.scss (1 hunks)
  • src/assets/mocks/events/mock-events.ts (6 hunks)
💤 Files with no reviewable changes (2)
  • src/app/greencity/modules/events/services/events.service.ts
  • src/app/greencity/modules/events/components/event-details/event-details.component.ts
✅ Files skipped from review due to trivial changes (2)
  • src/app/greencity/modules/events/components/event-details/event-details.component.spec.ts
  • src/app/greencity/modules/comments/mocks/comments-mock.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/app/greencity/modules/events/services/events-comments.service.ts
  • src/app/greencity/modules/events/models/events.interface.ts
  • src/assets/mocks/events/mock-events.ts
🧰 Additional context used
🪛 GitHub Actions: CI/CD GreenCityClient
src/app/greencity/shared/components/events-list-item/events-list-item.component.scss

[error] 22-22: Unexpected unknown type selector '<<<<<<' (selector-type-no-unknown)


[error] 22-22: Expected 'HEAD' to be 'head' (selector-type-case)


[error] 27-27: Unexpected unknown type selector '=======' (selector-type-no-unknown)


[error] 27-27: Unexpected unknown type selector 'dev' (selector-type-no-unknown)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1526c17 and b2175fb.

📒 Files selected for processing (3)
  • src/app/greencity/modules/events/components/events-list/LikeResponse.ts (1 hunks)
  • src/app/greencity/modules/events/components/events-list/events-list.component.html (1 hunks)
  • src/app/greencity/modules/events/components/events-list/events-list.component.ts (3 hunks)
🔇 Additional comments (6)
src/app/greencity/modules/events/components/events-list/LikeResponse.ts (1)

1-7: Well-structured interface for like/dislike functionality.

This interface is clearly defined with appropriate properties for tracking like/dislike status and counts.

src/app/greencity/modules/events/components/events-list/events-list.component.html (1)

145-146: Event handler names updated to match component implementation.

The event handler names have been updated from likeEvent($event) and dislikeEvent($event) to onLikeStatusChange($event) and onDislikeStatusChange($event) respectively, aligning with the new method names in the component class.

src/app/greencity/modules/events/components/events-list/events-list.component.ts (4)

2-2: Added EventDto import for the updated event handling logic.

The import statement now includes EventDto, which is needed for the new updateEventFromServer method.


116-127: New method to update event from server response.

The new updateEventFromServer method replaces the removed refreshEventInList method with a more streamlined approach. It efficiently updates only the necessary properties (likes, dislikes, isLiked, isDisliked) while preserving the rest of the event data.


128-133: New handler for like status changes.

This handler efficiently updates an event in the list when its like status changes, using the spread operator to merge properties instead of making additional API calls.


135-140: New handler for dislike status changes.

This method mirrors the like status change handler, providing consistent handling for both types of reactions. This is a good example of code reuse pattern.

@@ -18,6 +18,7 @@ import { MatOption } from '@angular/material/core';
import { HttpParams } from '@angular/common/http';
import { EventStoreService } from '../../services/event-store.service';
import { initializeSavedState } from 'src/app/greencity/shared/components/saved-tabs/saved-section-const';
import { LikeResponse } from '../../services/LikeResponse';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect import path for LikeResponse interface.

The import statement is using a path to the services directory, but the file we're reviewing shows this interface is located in the components directory.

-import { LikeResponse } from '../../services/LikeResponse';
+import { LikeResponse } from './LikeResponse';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { LikeResponse } from '../../services/LikeResponse';
import { LikeResponse } from './LikeResponse';

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/app/greencity/shared/components/events-list-item/events-list-item.component.ts (1)

338-354: Improved likePost implementation with proper response handling

The updated likePost method now properly handles both successful (200) and "reset" (204) responses, updating the event object's like/dislike properties accordingly. Good error handling is also included.

However, there's a minor inconsistency in the error message:

- (error) => console.error('Error in likeEvent:', error)
+ (error) => console.error('Error in likePost:', error)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b2175fb and 3ec3db1.

📒 Files selected for processing (3)
  • src/app/greencity/modules/events/services/LikeResponse.ts (1 hunks)
  • src/app/greencity/modules/events/services/events.service.ts (2 hunks)
  • src/app/greencity/shared/components/events-list-item/events-list-item.component.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
src/app/greencity/modules/events/services/events.service.ts (1)
src/app/greencity/modules/events/models/events.interface.ts (1)
  • EventDto (8-32)
🔇 Additional comments (4)
src/app/greencity/modules/events/services/LikeResponse.ts (1)

1-6: Interface changes look good and provide better metrics

The revised LikeResponse interface now provides a more comprehensive view of reaction metrics with numeric counts (likes, dislikes) and user state flags (isLiked, isDisliked). This is a good improvement over the previous boolean representation.

src/app/greencity/modules/events/services/events.service.ts (3)

1-1: Additional HttpResponse import added correctly

The import of HttpResponse is correctly added to support the updated return types of the like/dislike methods.


175-177: Standardized return type for dislikeEvent method

Great improvement! The method now returns a properly typed response (Observable<HttpResponse<EventDto>>) instead of Observable<any>, which aligns with the likeEvent method. This standardization ensures consistency and better type safety.


171-173:

❓ Verification inconclusive

Improved type safety and response handling for likeEvent

The method now properly returns the full HTTP response object with appropriate typing, enabling status code checks in consuming components. This is a good improvement.

However, note that the versioning inconsistency raised in a previous review still exists - this method uses -v2 suffix while other methods in this service use /v2/ in the path. Verify if this inconsistency is intentional or should be fixed.


🏁 Script executed:

#!/bin/bash
# Check if there are other endpoints using -v2 suffix vs /v2/ path
echo "Endpoints using -v2 suffix:"
rg "this\.backEnd.*[^/]-v2" --type ts

echo -e "\nEndpoints using /v2/ in path:"
rg "this\.backEnd.*\/v2\/" --type ts

Length of output: 664


Versioning Inconsistency – Please Verify

The improved type safety and response handling in likeEvent (and similarly in dislikeEvent) are great improvements. However, based on our searches, these endpoints use the -v2 suffix, and there’s an indication (from previous context) that other endpoints in this service might be structured with /v2/ in the path. I couldn’t clearly confirm /v2/ usage in this file (aside from the regex issue during search), so please review the endpoint versioning across the service to verify if the discrepancy is intentional or if the URLs should be aligned.

  • Endpoints using -v2:
    • src/app/greencity/modules/events/services/events.service.ts (e.g., like-v2, dislike-v2)
  • Action Requested:
    • Confirm whether the -v2 suffix is the intentional pattern for these endpoints or if they should follow the /v2/ convention used elsewhere.

Comment on lines +356 to +378
dislikePost(): void {
this.eventService.dislikeEvent(this.event.id).subscribe(
(res) => {
if (res.status === 200 && res.body) {
this.event = {
...this.event,
likes: res.body.likes,
dislikes: res.body.dislikes,
isLiked: res.body.isLiked,
isDisliked: res.body.isDisliked
};
} else if (res.status === 204) {
this.event.isLiked = false;
this.event.likes = Math.max(0, this.event.likes - 1);
}

this.likeStatusChange.emit(this.event);
},
(error) => {
console.error('Error in likeEvent:', error);
}
);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Logic inconsistency in dislikePost implementation

The dislikePost method handles responses differently from likePost:

  1. It uses object spread to update the event object in the 200 status case
  2. It's only updating isLiked and likes properties in the 204 case, not touching isDisliked or dislikes
  3. It emits likeStatusChange instead of dislikeStatusChange

Fix these issues for consistent behavior:

dislikePost(): void {
  this.eventService.dislikeEvent(this.event.id).subscribe(
    (res) => {
      if (res.status === 200 && res.body) {
-        this.event = {
-          ...this.event,
-          likes: res.body.likes,
-          dislikes: res.body.dislikes,
-          isLiked: res.body.isLiked,
-          isDisliked: res.body.isDisliked
-        };
+        this.event.likes = res.body.likes;
+        this.event.dislikes = res.body.dislikes;
+        this.event.isLiked = res.body.isLiked;
+        this.event.isDisliked = res.body.isDisliked;
      } else if (res.status === 204) {
-        this.event.isLiked = false;
-        this.event.likes = Math.max(0, this.event.likes - 1);
+        this.event.isDisliked = false;
+        this.event.dislikes = Math.max(0, this.event.dislikes - 1);
      }

-      this.likeStatusChange.emit(this.event);
+      this.dislikeStatusChange.emit(this.event);
    },
    (error) => {
-      console.error('Error in likeEvent:', error);
+      console.error('Error in dislikePost:', error);
    }
  );
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
dislikePost(): void {
this.eventService.dislikeEvent(this.event.id).subscribe(
(res) => {
if (res.status === 200 && res.body) {
this.event = {
...this.event,
likes: res.body.likes,
dislikes: res.body.dislikes,
isLiked: res.body.isLiked,
isDisliked: res.body.isDisliked
};
} else if (res.status === 204) {
this.event.isLiked = false;
this.event.likes = Math.max(0, this.event.likes - 1);
}
this.likeStatusChange.emit(this.event);
},
(error) => {
console.error('Error in likeEvent:', error);
}
);
}
dislikePost(): void {
this.eventService.dislikeEvent(this.event.id).subscribe(
(res) => {
if (res.status === 200 && res.body) {
this.event.likes = res.body.likes;
this.event.dislikes = res.body.dislikes;
this.event.isLiked = res.body.isLiked;
this.event.isDisliked = res.body.isDisliked;
} else if (res.status === 204) {
this.event.isDisliked = false;
this.event.dislikes = Math.max(0, this.event.dislikes - 1);
}
this.dislikeStatusChange.emit(this.event);
},
(error) => {
console.error('Error in dislikePost:', error);
}
);
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
src/app/greencity/modules/user/services/habit-comments/habit-comments.service.ts (1)

8-8: ⚠️ Potential issue

Update required for CommentsDTO import.

The file needs to import CommentsDTO from the comments-model to match the interface requirements defined in CommentsService.

-import { AddedCommentDTO, CommentFormData, CommentsModel } from 'src/app/greencity/modules/comments/models/comments-model';
+import { AddedCommentDTO, CommentFormData, CommentsDTO, CommentsModel } from 'src/app/greencity/modules/comments/models/comments-model';
🧹 Nitpick comments (1)
src/app/greencity/modules/eco-news/services/eco-news-comments.service.ts (1)

63-65: New postLikeV2 method looks good, but consider removing old postDislike method.

The new postLikeV2 method correctly returns an Observable instead of Observable, allowing components to update with the latest comment data immediately after a like action. However, while you've added this new method, the old postDislike method (lines 25-32) still exists in the file, which could lead to confusion for developers.

Consider removing the old postDislike method since it's being replaced by postDislikeV2.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ec3db1 and 4561caf.

📒 Files selected for processing (9)
  • src/app/greencity/modules/comments/components/comments-container/comments-container.component.ts (1 hunks)
  • src/app/greencity/modules/comments/components/comments-list/comments-list.component.ts (3 hunks)
  • src/app/greencity/modules/comments/components/like-comment/like-comment.component.html (1 hunks)
  • src/app/greencity/modules/comments/components/like-comment/like-comment.component.ts (0 hunks)
  • src/app/greencity/modules/comments/models/comments-model.ts (2 hunks)
  • src/app/greencity/modules/comments/services/comments.service.ts (2 hunks)
  • src/app/greencity/modules/eco-news/services/eco-news-comments.service.ts (2 hunks)
  • src/app/greencity/modules/events/services/events-comments.service.ts (2 hunks)
  • src/app/greencity/modules/user/services/habit-comments/habit-comments.service.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/app/greencity/modules/comments/components/like-comment/like-comment.component.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/greencity/modules/events/services/events-comments.service.ts
🧰 Additional context used
🧬 Code Definitions (3)
src/app/greencity/modules/comments/components/comments-list/comments-list.component.ts (1)
src/app/greencity/modules/comments/models/comments-model.ts (1)
  • CommentsDTO (13-31)
src/app/greencity/modules/eco-news/services/eco-news-comments.service.ts (1)
src/app/greencity/modules/comments/models/comments-model.ts (1)
  • CommentsDTO (13-31)
src/app/greencity/modules/comments/services/comments.service.ts (1)
src/app/greencity/modules/comments/models/comments-model.ts (1)
  • CommentsDTO (13-31)
🔇 Additional comments (11)
src/app/greencity/modules/comments/components/like-comment/like-comment.component.html (1)

2-2:

❓ Verification inconclusive

Button is no longer interactive

The click event handler has been removed from this button, making it non-interactive. If this is intentional as part of a broader refactoring (moving like functionality elsewhere), ensure the button has proper styling to indicate its non-interactive state to users.


🏁 Script executed:

#!/bin/bash
# Search for any other files that might be handling the like functionality now
rg -A 5 "pressLike" src/app/greencity/modules/comments/components/

Length of output: 66


Below is the rewritten review comment. Please confirm that the removal of the click event was indeed intended as part of the refactoring, and if so, ensure that the inactive state of the button is clearly communicated through appropriate styling.


Attention: Click Event Missing on Like Button

The <button class="cta-btn like"> in src/app/greencity/modules/comments/components/like-comment/like-comment.component.html currently lacks a click event binding. Our initial search for like-related handlers (e.g., “pressLike”) did not yield any results suggesting that this functionality has been moved elsewhere.

  • Verify whether this removal is intentional.
  • If the button is meant to remain non-interactive, consider applying a disabled or inactive style to signal this state to users.
  • If the removal was accidental, please reinstate the click event handler so that the like functionality remains operative.
src/app/greencity/modules/comments/components/comments-container/comments-container.component.ts (1)

67-69: Added dislike properties to reply object

The addition of currentUserDisliked and dislikes properties aligns with the updated CommentsDTO interface. This ensures newly created replies have the proper structure for tracking dislike interactions.

src/app/greencity/modules/comments/models/comments-model.ts (1)

16-19: Enhanced comment model with dislike functionality

The CommentsDTO interface has been expanded to include dislike functionality, which enables tracking both user-specific dislike status and the total dislike count for each comment. This enhancement will facilitate displaying dislike metrics to admin users as specified in the PR title.

src/app/greencity/modules/comments/components/comments-list/comments-list.component.ts (3)

86-90: Improved comment update logic with immutability

The new updateCommentData method uses immutable pattern to update comments in the list. This is a better approach than direct mutation as it ensures proper change detection in Angular.


102-112: Enhanced like functionality with improved error handling

The likeComment method has been updated to use the new postLikeV2 service method which returns the updated comment object. The subscription now uses the object-style syntax with separate handlers for success and error cases, which is more maintainable.

I particularly like:

  1. The use of finalize to ensure the comment is removed from processing regardless of success/failure
  2. The dynamic snackbar message based on whether the comment was liked or unliked
  3. The proper error handling with user feedback

120-130: Enhanced dislike functionality with similar improvements

The dislikeComment method has been updated with the same pattern used in likeComment, providing consistent behavior and error handling for both types of reactions.

src/app/greencity/modules/eco-news/services/eco-news-comments.service.ts (2)

7-7: Good update to include CommentsDTO in imports.

The import statement has been properly updated to include CommentsDTO, which is necessary for the new method return types.


67-69: postDislikeV2 implementation looks good.

This method correctly implements the commented interface and returns a CommentsDTO object, which will provide immediate feedback to the UI about the updated comment state.

src/app/greencity/modules/comments/services/comments.service.ts (3)

3-3: Good update to include CommentsDTO in imports.

The import statement has been properly updated to include CommentsDTO, which is necessary for the new method signatures.


23-23: Updated method signature to postLikeV2 looks good.

This change from postLike to postLikeV2 with a return type of Observable provides more useful functionality to implementing services, allowing components to receive updated comment data immediately after a like action.


25-25: Updated method signature to postDislikeV2 looks good.

Similar to the like method, this change provides a more useful contract for implementations and improves the user experience by enabling immediate UI updates.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/app/greencity/shared/components/events-list-item/events-list-item.component.html (1)

105-105: Clarify Computation of Net Likes Inline

The updated <span> now displays the net likes by subtracting event.dislikes from event.likes. While this inline calculation is concise, consider handling potential edge cases (such as one of the values being null or undefined) using either a safe navigation approach or by computing the net likes within the component class. This would improve clarity and maintainability of the template code.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 48199d1 and 5ba7b71.

📒 Files selected for processing (1)
  • src/app/greencity/shared/components/events-list-item/events-list-item.component.html (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (18.x)

@holus-bolus holus-bolus closed this Apr 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add dislike ability to eco-news, events, comments
3 participants