Skip to content

fix: connect NotificationsPanel to API and fix animation race condition and pointerEvents bugΒ #61

Description

@Josue19-08

πŸ”– Title

Fix `NotificationsPanel` β€” connect to real API, fix animation close race condition, fix `pointerEvents` bug


πŸ“„ Description

`NotificationsPanel` has three distinct bugs and uses entirely hardcoded mock data.

Bug 1 β€” Animation close race condition:
`NotificationsPanel.tsx` line ~147:
```ts
if (!isOpen && translateX.value === SCREEN_WIDTH) return null;
```
When `isOpen` flips to false, the close animation fires (`withTiming(SCREEN_WIDTH, …)`), but on the very next re-render the guard checks `translateX.value === SCREEN_WIDTH` β€” because the animated value hasn't finished yet, it's not equal to `SCREEN_WIDTH` yet, so the panel stays rendered. BUT if the component re-renders mid-animation (e.g. state update), the value may momentarily equal `SCREEN_WIDTH` and immediately unmount the component, cutting the closing animation short. The panel disappears abruptly instead of sliding out.

Fix: Use a `isMounted` flag controlled by `runOnJS` in the animation's `callback` argument:
```ts
withTiming(SCREEN_WIDTH, { duration: 300 }, (finished) => {
if (finished) runOnJS(setIsMounted)(false);
});
```

Bug 2 β€” `pointerEvents` as style prop:
`animatedBackdropStyle` in `NotificationsPanel.tsx` includes `pointerEvents` inside the style object. In React Native, `pointerEvents` is a prop on the View element, not a style property. It has no effect as a style β€” backdrop taps pass through even when the panel is open.

Bug 3 β€” All notification data is hardcoded:
`MOCK_NOTIFICATIONS` is a static constant. Mark-as-read and delete actions only mutate local state β€” no API call is made.


βœ… Tasks to complete

  • Fix animation race condition in `NotificationsPanel.tsx` β€” replace the `translateX.value === SCREEN_WIDTH` guard with a separate `isMounted` boolean state controlled by the animation callback's `runOnJS` call
  • Fix `pointerEvents` β€” move it from `animatedBackdropStyle` to a prop on the `Animated.View` element: `<Animated.View pointerEvents={isOpen ? 'auto' : 'none'} style={animatedBackdropStyle}>`
  • Create `hooks/notifications/use-notifications.ts` β€” fetches `GET /notifications` from API (with `?unread=true` filter support); exposes `notifications`, `unreadCount`, `isLoading`, `markAsRead(id)`, `markAllAsRead()`
  • Update `NotificationsPanel.tsx` β€” replace `MOCK_NOTIFICATIONS` constant with data from `useNotifications` hook; show a loading skeleton while fetching; show empty state when there are no notifications
  • Update `markAsRead` and delete handlers to call `PATCH /notifications/:id/read` and update local state optimistically
  • Update `markAllAsRead` to call `PATCH /notifications/read-all`
  • Update the notification bell icon in `Header.tsx` to display the real `unreadCount` badge from the hook (currently has no badge at all)

πŸ“š Documentation/context for AI

https://github.com/TrustUp-app/TrustUp-Frontend/tree/main/docs

Files to create:

  • `hooks/notifications/use-notifications.ts`

Files to modify:

  • `components/shared/NotificationsPanel.tsx` (animation fix, pointerEvents fix, real data)
  • `components/shared/Header.tsx` (real unread badge count on bell icon)

πŸ—’οΈ Additional notes

  • API endpoints: `GET /notifications`, `PATCH /notifications/:id/read`, `PATCH /notifications/read-all`
  • Optimistic update: when tapping "mark as read", update local state immediately before the API call completes; roll back on error
  • The notification bell badge should show the count as a red circle with number; hide it when `unreadCount === 0`
  • On Android, `BlurView` with `intensity={40}` is unreliable β€” add a fallback semi-transparent `backgroundColor` for Android: `Platform.OS === 'android' ? 'rgba(0,0,0,0.5)' : undefined`
  • Empty state: show "No notifications" centered in the panel with a subtle icon

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions