Skip to content

fix: notifications pagination + dropdown updates#86

Open
Anshpujara5 wants to merge 5 commits into
tarinagarwal:mainfrom
Anshpujara5:fix/notifications-pagination
Open

fix: notifications pagination + dropdown updates#86
Anshpujara5 wants to merge 5 commits into
tarinagarwal:mainfrom
Anshpujara5:fix/notifications-pagination

Conversation

@Anshpujara5
Copy link
Copy Markdown
Contributor

@Anshpujara5 Anshpujara5 commented Jan 5, 2026

Description

Adds pagination to the notifications system so notifications load in batches instead of all at once.

Backend pagination parameters (page, limit) are verified and used correctly, and the frontend notification dropdown now supports incremental loading via a Load More button. This improves performance and provides a smoother user experience for users with large notification histories.


Type of Change

  • Bug fix
  • New feature

Related Issues

Closes #13


Testing

  • Tested locally
  • Client build (npm run build) passes successfully
  • Client lint reports existing repository-wide lint issues unrelated to this PR
  • Server has no lint script; notifications endpoint tested manually

Screenshots

Screenshot 2026-01-05 190246

Checklist

  • Code follows existing project style guidelines
  • Self-reviewed the code
  • Added comments for complex logic where needed
  • Documentation update not required for this change

@Anshpujara5
Copy link
Copy Markdown
Contributor Author

Hi @tarinagarwal 👋

Just a gentle follow-up regarding this PR.
Whenever you get a chance, could you please review it and let me know if any changes are required from my side?

I’m happy to iterate or make updates as needed.
Thanks for your time and guidance 😊

@tarinagarwal
Copy link
Copy Markdown
Owner

@Anshpujara5 Hey! ill review this pr asap, sorry for the delay

Copy link
Copy Markdown

@tarin-lgtm tarin-lgtm Bot left a comment

Choose a reason for hiding this comment

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

Changes Requested 🐈

This PR adds pagination to the notifications system, improving performance by loading notifications in batches and enhancing the UI with a Load More button. Review found improvements in backend pagination and UI, but raised concerns about input validation, potential race conditions, inefficient client-side data handling, lack of test coverage, and missing documentation.

There are a few things I'd like to see addressed before we merge this:

Before merging

  1. Add input validation and sanitization for notification IDs and pagination parameters to improve security.
  2. Refactor NotificationDropdown component to improve readability and maintainability, including adding JSDoc comments and reducing complexity.
  3. Optimize client-side notification handling by using efficient data structures for duplicate detection and read status updates, and add test coverage for new features.
Findings breakdown (35 total)

3 high / 12 medium / 15 low / 5 info

Confidence: 90%


🔗 View Full Review Report — detailed findings, severity breakdown, and agent analysis

Reviewed by Looks Good To Meow — AI-powered code review


const NotificationDropdown: React.FC = () => {
const [notifications, setNotifications] = useState<Notification[]>([]);
const [notifications, setNotifications] = useState<AppNotification[]>([]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ High — The NotificationDropdown component now implements pagination for notifications with page size 20 and supports loading more notifications on demand. This is a positive change preventing unbounded notification fetches.

No action needed; pagination is correctly implemented for notifications.

performance

where: { userId: req.user.id },
}),
]);
const [notifications, total,unreadCount] = await Promise.all([
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ High — The notifications API endpoint now supports pagination with page and limit parameters, fetching notifications with skip and take, and returns pagination metadata. This prevents unbounded queries and large data transfers.

No action needed; pagination is properly implemented in the notifications API.

performance


const NotificationDropdown: React.FC = () => {
const [notifications, setNotifications] = useState<Notification[]>([]);
const [notifications, setNotifications] = useState<AppNotification[]>([]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ High — The exported React functional component 'NotificationDropdown' lacks a JSDoc comment describing its purpose, parameters, and return value.

Add a JSDoc comment above the 'NotificationDropdown' component explaining its functionality, props (if any), and what it returns.

documentation


const NotificationDropdown: React.FC = () => {
const [notifications, setNotifications] = useState<Notification[]>([]);
const [notifications, setNotifications] = useState<AppNotification[]>([]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 Medium — The 'notifications' state is updated inside the socket 'new_notification' event handler using a functional update, but the 'unreadCount' state is updated separately inside the same handler. This can cause race conditions or inconsistent state if multiple notifications arrive rapidly.

Combine the updates to 'notifications' and 'unreadCount' into a single state update or use a reducer to manage both states atomically.

bugs

where: { userId: req.user.id },
}),
]);
const [notifications, total,unreadCount] = await Promise.all([
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 Medium — Notification read status update endpoint checks that the notification belongs to the authenticated user before allowing update, which is good. However, the notification ID is taken directly from the URL parameter without validation or sanitization. While Prisma ORM likely handles parameterization, ensure that the ID is validated to prevent injection or malformed input.

Validate and sanitize the notification ID parameter before using it in database queries. Use proper type checks and reject invalid IDs early.

security

{unreadCount > 0 && (
<span className="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full h-5 w-5 flex items-center justify-center animate-pulse">
{unreadCount > 9 ? "9+" : unreadCount}
<span className="absolute -top-1 -right-1 z-[9999] bg-red-500 text-white text-[10px] font-semibold rounded-full h-5 min-w-5 px-1 flex items-center justify-center">
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Suggestion — The unread count badge shows the exact number even if it exceeds 9, whereas previously it showed '9+'. This may cause UI inconsistency or overflow.

Consider limiting the displayed count to '9+' or a max value to maintain consistent badge size and appearance.

best-practices

notifications.map((notification) => (
<div
key={notification.id}
key={getNotifId(notification)}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Suggestion — Notification list items use getNotifId(notification) as key, which may cause issues if IDs are not unique or stable.

Ensure that notification IDs are unique and stable; otherwise, consider a more stable key or include additional identifiers.

best-practices

</p>
</span>
{!notification.is_read && (
<button
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Suggestion — The 'Mark as read' button inside each notification item stops propagation on click but does not prevent default, which may cause unexpected behavior in some browsers.

Add e.preventDefault() along with e.stopPropagation() to fully prevent event bubbling and default actions.

best-practices

{page < totalPages && (
<div className="p-3 text-center">
<button
onClick={() => fetchNotifications(page + 1)}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Suggestion — The 'Load More' button for pagination does not have aria-label or accessible name, which may affect accessibility.

Add aria-label or descriptive text for screen readers to improve accessibility.

best-practices

socket.on("new_notification", (notification: Notification) => {
setNotifications((prev) => [notification, ...prev]);
setUnreadCount((prev) => prev + 1);
const handler = (notification: AppNotification) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Suggestion — The variable 'n' in the getNotifId function and in the some() callback is typed as 'any', which reduces type safety and clarity.

Define a proper type for the notification parameter in getNotifId and the some() callback to improve type safety and readability.

readability

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 pagination to notifications

2 participants