Skip to content

RU-T50 Call notes and Inbox fix#257

Merged
ucswift merged 3 commits into
masterfrom
develop
Jul 26, 2026
Merged

RU-T50 Call notes and Inbox fix#257
ucswift merged 3 commits into
masterfrom
develop

Conversation

@ucswift

@ucswift ucswift commented Jul 26, 2026

Copy link
Copy Markdown
Member

Description

This PR addresses fixes and improvements to the Call Notes modal and Notification Inbox components.

Call Notes Modal

Replaced KeyboardStickyView with KeyboardAvoidingView to wrap the entire modal content (header, search bar, notes list, and footer) instead of just the footer. This provides more consistent keyboard handling behavior where the full view adjusts when the keyboard appears, rather than only sticking the input section to the keyboard.

Notification Inbox

Refactored the notification list for improved rendering performance:

  • Extracted individual notification rows into a memoized NotificationRow component with a custom comparison function to prevent unnecessary re-renders
  • Wrapped event handlers (handleNotificationPress, handleNotificationLongPress, toggleNotificationSelection, handleNavigateToReference, and renderItem) in useCallback to stabilize references and reduce re-renders
  • Separated long-press selection logic into its own dedicated handler

Notification Detail

Removed the entrance animation (slide and fade-in) and the automatic read-marking behavior (via Novu useNotifications refetch) that occurred when opening an unread notification. The detail panel now appears immediately without animation.

@Resgrid-Bot

This comment has been minimized.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ucswift, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 19 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d6644e8c-08b1-4632-b4ac-0b86b40fa00e

📥 Commits

Reviewing files that changed from the base of the PR and between 83f0dc0 and 80a9966.

📒 Files selected for processing (4)
  • src/components/calls/call-notes-modal.tsx
  • src/components/notifications/NotificationInbox.tsx
  • src/components/notifications/__tests__/NotificationInbox.test.tsx
  • src/types/notification.ts
📝 Walkthrough

Walkthrough

The PR changes call-note keyboard avoidance and updates notification detail initialization and inbox row interaction handling, including selection, long-press, navigation, and memoized row rendering.

Changes

Call note keyboard handling

Layer / File(s) Summary
Call-notes keyboard avoidance
src/components/calls/call-notes-modal.tsx, src/components/calls/__tests__/call-notes-modal-new.test.tsx
Replaces KeyboardStickyView with KeyboardAvoidingView, adds padding behavior and layout styling, and updates the Jest mock accordingly.

Notification interaction updates

Layer / File(s) Summary
Notification detail opening state
src/components/notifications/NotificationDetail.tsx
Removes mount-time refetch and animation effects and initializes the detail view in its visible state.
Notification row and selection flow
src/components/notifications/NotificationInbox.tsx
Extracts memoized row rendering and rewires selection, long-press, navigation, and list-item callbacks.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • Resgrid/Unit#186: Modifies notification item rendering in the same inbox component.

Suggested reviewers: github-actions

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title matches the main areas changed: call notes and the notifications inbox, even if it is broad.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
src/components/notifications/NotificationInbox.tsx (2)

37-38: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use the required React.FC signature.

NotificationRow is a new typed component but is not declared as React.FC<NotificationRowProps>. As per coding guidelines, “Utilize React.FC for defining functional components with props.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/notifications/NotificationInbox.tsx` around lines 37 - 38,
Update the NotificationRow component declaration to use the required
React.FC<NotificationRowProps> type while preserving its existing React.memo
wrapping and behavior.

Source: Coding guidelines


241-253: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Preserve the notification item type at the mapping boundary.

Line 242 uses any, so malformed SDK payloads can bypass the NotificationPayload contract. Type item from the notifications collection (or the Novu SDK model) and retain the referenceType union. As per coding guidelines, “Never use any type; use precise types and interfaces with TypeScript strict mode enabled.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/notifications/NotificationInbox.tsx` around lines 241 - 253,
Replace the any type in renderItem with the precise notification collection or
Novu SDK item type, and ensure the mapping to NotificationPayload preserves the
referenceType union without unsafe widening. Keep the existing field mapping
unchanged while enforcing the item shape under strict TypeScript.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/calls/__tests__/call-notes-modal-new.test.tsx`:
- Around line 69-71: Update the KeyboardAvoidingView mock to use a precise props
interface instead of any, including children, behavior, and
keyboardVerticalOffset, and forward those props to the rendered View. Add or
update the Jest assertions to verify behavior="padding" and
keyboardVerticalOffset={0} on the keyboard-avoiding wrapper.

In `@src/components/notifications/NotificationDetail.tsx`:
- Around line 31-32: Update the notification-open flow around NotificationDetail
so selecting an unread notification invokes the Novu SDK mark-as-read operation
and refreshes the inbox state, ensuring NotificationRow no longer derives it as
unread. Preserve already-read behavior and update the detail-open test to verify
the read-status update flow.

In `@src/components/notifications/NotificationInbox.tsx`:
- Around line 232-237: Update handleNavigateToReference to route each supported
referenceType to its referenced call, message, or note using the existing
navigation utilities, and invoke onClose only after navigation succeeds. Remove
the console.log call; if diagnostics are still needed, use the shared logger
from `@/lib/logging`.
- Around line 166-174: Update handleNotificationLongPress so the event handler
determines whether selection mode is currently inactive, then performs
setSelectedNotificationIds and setIsSelectionMode directly rather than nesting
the former inside the setIsSelectionMode updater. Keep the updater pure and
preserve selecting the pressed notification only when entering selection mode.

---

Nitpick comments:
In `@src/components/notifications/NotificationInbox.tsx`:
- Around line 37-38: Update the NotificationRow component declaration to use the
required React.FC<NotificationRowProps> type while preserving its existing
React.memo wrapping and behavior.
- Around line 241-253: Replace the any type in renderItem with the precise
notification collection or Novu SDK item type, and ensure the mapping to
NotificationPayload preserves the referenceType union without unsafe widening.
Keep the existing field mapping unchanged while enforcing the item shape under
strict TypeScript.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 94bae7fd-16c0-47c0-89ac-488e88d0b6a0

📥 Commits

Reviewing files that changed from the base of the PR and between 6f995da and 83f0dc0.

📒 Files selected for processing (4)
  • src/components/calls/__tests__/call-notes-modal-new.test.tsx
  • src/components/calls/call-notes-modal.tsx
  • src/components/notifications/NotificationDetail.tsx
  • src/components/notifications/NotificationInbox.tsx

Comment on lines +69 to +71
KeyboardAvoidingView: ({ children }: any) => {
const { View } = require('react-native');
return <View testID="keyboard-sticky-view">{children}</View>;
return <View testID="keyboard-avoiding-view">{children}</View>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Type and forward the keyboard wrapper props.

Line 69 uses prohibited any, and the mock drops behavior and keyboardVerticalOffset, so tests cannot detect regressions in this PR’s keyboard-avoidance configuration. Define a props interface, forward the props to View, and assert behavior="padding" and keyboardVerticalOffset={0}.

As per coding guidelines, “Never use any type; use precise types and interfaces with TypeScript strict mode enabled,” and generate Jest tests that validate generated components.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/calls/__tests__/call-notes-modal-new.test.tsx` around lines 69
- 71, Update the KeyboardAvoidingView mock to use a precise props interface
instead of any, including children, behavior, and keyboardVerticalOffset, and
forward those props to the rendered View. Add or update the Jest assertions to
verify behavior="padding" and keyboardVerticalOffset={0} on the
keyboard-avoiding wrapper.

Source: Coding guidelines

Comment thread src/components/notifications/NotificationDetail.tsx
Comment thread src/components/notifications/NotificationInbox.tsx Outdated
Comment thread src/components/notifications/NotificationInbox.tsx
<FlatList
data={filteredNotes}
renderItem={renderNote}
keyExtractor={(item) => item.CallNoteId}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Kody Rules high

Render inefficiency caused by the inline arrow function assigned to keyExtractor, which creates a new function reference on every render cycle. Extract this function definition outside the render method to prevent unnecessary re-renders.

Kody rule violation: Avoid using .bind() or arrow functions in JSX props

Prompt for LLM

File src/components/calls/call-notes-modal.tsx:

Line 136:

Render inefficiency caused by the inline arrow function assigned to `keyExtractor`, which creates a new function reference on every render cycle. Extract this function definition outside the render method to prevent unnecessary re-renders.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

@Resgrid-Bot

This comment has been minimized.

} else {
// Mark unread notifications as read via the Novu SDK; the SDK
// optimistically updates its cache, refreshing inbox state.
notification.markAsRead?.();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Kody Rules high

Unhandled promise rejection propagates when notification.markAsRead?.() invokes a Novu SDK method without awaiting or calling .catch(). Wrap the call in a try/catch block with await or append .catch((e) => logger.error('markAsRead failed', { err: e })) to handle network or auth failures.

Kody rule violation: Handle async operations with proper error handling

Prompt for LLM

File src/components/notifications/NotificationInbox.tsx:

Line 164:

Unhandled promise rejection propagates when `notification.markAsRead?.()` invokes a Novu SDK method without awaiting or calling `.catch()`. Wrap the call in a try/catch block with `await` or append `.catch((e) => logger.error('markAsRead failed', { err: e }))` to handle network or auth failures.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

} else {
// Mark unread notifications as read via the Novu SDK; the SDK
// optimistically updates its cache, refreshing inbox state.
notification.markAsRead?.();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Kody Rules high

Unhandled network call rejection occurs when notification.markAsRead?.() triggers a Novu backend request without a try/catch wrapper. Wrap the call in try { await notification.markAsRead?.(); } catch (e) { logger.error('Failed to mark notification as read', { err: e }); } to add context and map to application-level errors.

Kody rule violation: Add try-catch blocks for external calls

Prompt for LLM

File src/components/notifications/NotificationInbox.tsx:

Line 164:

Unhandled network call rejection occurs when `notification.markAsRead?.()` triggers a Novu backend request without a try/catch wrapper. Wrap the call in `try { await notification.markAsRead?.(); } catch (e) { logger.error('Failed to mark notification as read', { err: e }); }` to add context and map to application-level errors.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

referenceId: item.payload?.referenceId,
referenceType: item.payload?.referenceType,
metadata: item.payload?.metadata,
markAsRead: !item.isRead && typeof item.read === 'function' ? () => item.read() : undefined,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Bug medium

Unhandled promise rejection occurs when notification.markAsRead?.() (line 164) invokes the async Novu SDK call () => item.read() (line 261) without awaiting or catching the returned promise. Wrap the invocation in handleNotificationPress or attach a catch handler to surface a toast and prevent local 'read' state desync on network or auth errors.

markAsRead: !item.isRead && typeof item.read === 'function' ? async () => { try { await item.read(); } catch (e) { logger.warn({ message: 'Failed to mark notification as read', context: { error: e } }); } } : undefined,
Prompt for LLM

File src/components/notifications/NotificationInbox.tsx:

Line 261:

Unhandled promise rejection occurs when `notification.markAsRead?.()` (line 164) invokes the async Novu SDK call `() => item.read()` (line 261) without awaiting or catching the returned promise. Wrap the invocation in `handleNotificationPress` or attach a catch handler to surface a toast and prevent local 'read' state desync on network or auth errors.

Suggested Code:

markAsRead: !item.isRead && typeof item.read === 'function' ? async () => { try { await item.read(); } catch (e) { logger.warn({ message: 'Failed to mark notification as read', context: { error: e } }); } } : undefined,

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

</View>
const handleNavigateToReference = React.useCallback(
(referenceType: string, referenceId: string) => {
if (referenceType === 'call') {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Kody Rules low

Magic string detected where the string literal 'call' represents a value from a finite set of notification reference types but is inlined directly. Define an enum like NotificationReferenceType or a const tuple and compare against NotificationReferenceType.Call to prevent typos and ease maintenance.

Kody rule violation: Use enums instead of magic strings

Prompt for LLM

File src/components/notifications/NotificationInbox.tsx:

Line 239:

Magic string detected where the string literal `'call'` represents a value from a finite set of notification reference types but is inlined directly. Define an enum like `NotificationReferenceType` or a const tuple and compare against `NotificationReferenceType.Call` to prevent typos and ease maintenance.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

const handleNavigateToReference = React.useCallback(
(referenceType: string, referenceId: string) => {
if (referenceType === 'call') {
router.push(`/call/${referenceId}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Kody Rules low

Hardcoded route path detected where /call/${referenceId} is inlined directly. Centralize route names as constants using a route helper like ROUTES.CALL(referenceId) or buildRoute('call', referenceId) to ensure consistent referencing and single-point updates.

Kody rule violation: Centralize string constants

Prompt for LLM

File src/components/notifications/NotificationInbox.tsx:

Line 240:

Hardcoded route path detected where `/call/${referenceId}` is inlined directly. Centralize route names as constants using a route helper like `ROUTES.CALL(referenceId)` or `buildRoute('call', referenceId)` to ensure consistent referencing and single-point updates.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

Comment thread src/types/notification.ts
referenceId?: string;
referenceType?: 'call' | 'message' | 'status' | 'note' | 'other';
metadata?: Record<string, any>;
markAsRead?: () => void;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Kody Rules high

Separation of concerns violation found where the NotificationPayload interface mixes pure data with executable behavior via the markAsRead callback function. Remove the callback function from the payload interface to prevent serialization issues across network boundaries, and handle the markAsRead action separately in the consuming UI component or a dedicated service.

Kody rule violation: Separate UI logic from business logic

Prompt for LLM

File src/types/notification.ts:

Line 11:

Separation of concerns violation found where the `NotificationPayload` interface mixes pure data with executable behavior via the `markAsRead` callback function. Remove the callback function from the payload interface to prevent serialization issues across network boundaries, and handle the `markAsRead` action separately in the consuming UI component or a dedicated service.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

@Resgrid-Bot

Resgrid-Bot commented Jul 26, 2026

Copy link
Copy Markdown

Code Review Completed! 🔥

The code review was successfully completed based on your current configurations.

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the @kody start-review command at the root of your PR.

  • Validate Business Logic: Ask Kody to validate your code against business rules by adding a comment with the @kody -v business-logic command.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug
Performance
Security
Business Logic

Access your configuration settings here.

try {
await item.read();
} catch (error) {
logger.warn({ message: 'Failed to mark notification as read', context: { error } });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Kody Rules high

Incomplete warning logs prevent tracing failed notification read operations. Rule [3] mandates appending the operation name and relevant identifiers, such as notificationId: item.id, to the structured context object.

Kody rule violation: Include error context in structured logs

Prompt for LLM

File src/components/notifications/NotificationInbox.tsx:

Line 267:

Incomplete warning logs prevent tracing failed notification read operations. Rule [3] mandates appending the operation name and relevant identifiers, such as `notificationId: item.id`, to the structured `context` object.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

@ucswift

ucswift commented Jul 26, 2026

Copy link
Copy Markdown
Member Author

Approve

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This PR is approved.

@ucswift
ucswift merged commit 5d37c65 into master Jul 26, 2026
19 of 20 checks passed
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.

2 participants