Skip to content

Comments

chore: fix NotificationSettings component to improve notification handling and type safety#42

Merged
alexmarqs merged 5 commits intomainfrom
chore/fix-notification-settings-for-old-db-entries
Dec 29, 2025
Merged

chore: fix NotificationSettings component to improve notification handling and type safety#42
alexmarqs merged 5 commits intomainfrom
chore/fix-notification-settings-for-old-db-entries

Conversation

@alexmarqs
Copy link
Owner

@alexmarqs alexmarqs commented Dec 29, 2025

fix NotificationSettings component to improve notification handling and type safety


Note

Notifications

  • Refactors NotificationSettings.tsx to use typed enums (Enums<"notification_type">, Enums<"notification_channel">) and a typed NOTIFICATION_LABEL_MAP.
  • Renders a specific NotificationSettingItem for new_companies via email instead of mapping all settings.
  • Reworks optimistic updates: cancels/inserts via a single queryKey, snapshots previous data (default []), updates or appends items (with temp IDs and timestamps), then invalidates on settle.
  • Simplifies payload (drops created_at/updated_at in mutation), stabilizes labelId, and safely handles missing settings (checked={setting?.enabled ?? false}).

UI/Perf

  • Adds loading="lazy" to the OpenStatus badge image in LogoFooter.tsx.

Written by Cursor Bugbot for commit b7dd521. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • Performance

    • Enabled lazy loading for footer images to improve page load efficiency.
  • Improvements

    • Redesigned notification settings UI with clearer labels and safer handling of missing or new entries.
    • Strengthened typing and props flow to simplify rendering logic.
    • Improved optimistic updates and cache handling for notification changes to reduce UI flicker and ensure consistent state.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 29, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

LogoFooter image now loads lazily. NotificationSettings is refactored to use DB enum-derived types, accept an array of settings plus explicit type and channel, change label/key generation, and broaden optimistic-update handling to add temporary items when missing.

Changes

Cohort / File(s) Summary
Image Optimization
apps/web/src/components/LogoFooter.tsx
Added loading="lazy" attribute to the external <img> to defer loading.
Notification Settings Typing & Refactor
apps/web/src/components/settings/notification/NotificationSettings.tsx
Introduced NotificationType and NotificationChannel (from Enums); typed NOTIFICATION_LABEL_MAP as Record<NotificationType,string>; changed NotificationSettingItem to accept settings array plus explicit type and channel; resolution now finds matching setting by type/channel and uses setting?.enabled ?? false; label IDs generated as notification-setting-${type}-${channel}; removed per-item render guard and adjusted optimistic-update logic to snapshot/update a queryKey, insert temporary items when absent, and update cache via computed nextData; imports updated to include Enums.

Sequence Diagram(s)

(omitted — changes are focused inside a UI component and cache/mutation handling; no new multi-system sequential flow diagram is necessary)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Poem

🐰 I nibble code and skip a byte,
Lazy logos nap in soft daylight,
Enums hop in, labels all align,
Temp items bloom where data’s thinned fine,
A rabbit claps — the settings shine.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main changes: refactoring NotificationSettings for better notification handling and type safety, which aligns with the primary objectives of the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/fix-notification-settings-for-old-db-entries

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 and usage tips.

@alexmarqs alexmarqs changed the title chore: fix NotificationSettings component to improve notification hnadling and type safety chore: fix NotificationSettings component to improve notification handling and type safety Dec 29, 2025
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/components/settings/notification/NotificationSettings.tsx (1)

70-92: Add guard to prevent optimistic updates when creating new notification settings.

At line 84, the comparison item.id === newData.setting.id will be problematic when id is undefined (when creating a new setting). Although the condition won't match any items, it's clearer and safer to explicitly skip the optimistic update for new settings by adding newData.setting.id !== undefined to the condition at line 80.

Consider this update:

 // Only perform optimistic update if previousData exists
-if (previousData) {
+if (previousData && newData.setting.id !== undefined) {
   queryClient.setQueryData<Tables<"notification_settings">[]>(
     [NotificationsServerKeys.GET_USER_NOTIFICATION_SETTINGS],
     previousData.map((item) =>
       item.id === newData.setting.id
         ? { ...item, ...newData.setting }
         : item,
     ),
   );
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d36066b and 904319b.

📒 Files selected for processing (2)
  • apps/web/src/components/LogoFooter.tsx
  • apps/web/src/components/settings/notification/NotificationSettings.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/src/components/settings/notification/NotificationSettings.tsx (2)
apps/web/src/lib/supabase/database.types.ts (2)
  • Enums (203-218)
  • Tables (124-151)
apps/web/src/components/ui/switch.tsx (1)
  • Switch (29-29)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Web E2E Tests
  • GitHub Check: Cursor Bugbot
🔇 Additional comments (7)
apps/web/src/components/LogoFooter.tsx (1)

26-26: Good performance optimization!

Adding loading="lazy" to the footer badge image is a best practice that defers loading until it's near the viewport.

apps/web/src/components/settings/notification/NotificationSettings.tsx (6)

9-9: Excellent type safety improvement!

Using Enums<> from the database types ensures compile-time validation against the actual database schema for notification types and channels.

Also applies to: 18-19


14-16: Type-safe label mapping looks good.

The Record<NotificationType, string> ensures all notification types have corresponding labels, making future additions type-safe.


39-43: Focused rendering approach is clearer.

Rendering a single, explicitly-defined notification setting is more maintainable than generic iteration when only one type/channel combination is currently supported.


50-62: Component signature refactoring improves reusability.

Accepting the full settings array with explicit type/channel props allows the component to derive its target setting internally, making it more flexible.


130-142: UI rendering is well-implemented.

The stable labelId generation, type-safe label lookup, and safe default for the switch checked state all handle the missing setting case appropriately for the UI layer.


64-64: No action required. The user_id default value is harmless—the upsertUserNotificationSetting mutation function retrieves the authenticated user's ID from the server session and overwrites any passed value with session.user.id (line 52 in apps/web/src/lib/db/notifications.ts). Invalid database entries cannot be created through this code path.

Likely an incorrect or invalid review comment.

… handle existing items and improve data consistency
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)
apps/web/src/components/settings/notification/NotificationSettings.tsx (2)

14-19: Consider defining types before usage for clarity.

While TypeScript hoists type aliases, declaring NotificationType and NotificationChannel after their usage in NOTIFICATION_LABEL_MAP (line 14) can confuse readers scanning top-to-bottom.

Suggested reordering
+type NotificationType = Enums<"notification_type">;
+type NotificationChannel = Enums<"notification_channel">;
+
 const NOTIFICATION_LABEL_MAP: Record<NotificationType, string> = {
   new_companies: "Receive email updates for new companies added",
 };
-
-type NotificationType = Enums<"notification_type">;
-type NotificationChannel = Enums<"notification_channel">;

118-123: Consider typing the mutation context explicitly.

The type assertion for context works but is brittle. React Query v5 can infer context types, but since useUpsertUserNotificationSetting is a pre-defined hook, you may want to define a context type for better type safety.

Alternative approach
type MutationContext = {
  previousData: Tables<"notification_settings">[];
};

// Then in onError:
onError: (_err, _newData, context: MutationContext | undefined) => {
  queryClient.setQueryData(
    [NotificationsServerKeys.GET_USER_NOTIFICATION_SETTINGS],
    context?.previousData,
  );
},
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 904319b and 9208822.

📒 Files selected for processing (1)
  • apps/web/src/components/settings/notification/NotificationSettings.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Web E2E Tests
  • GitHub Check: Cursor Bugbot
🔇 Additional comments (3)
apps/web/src/components/settings/notification/NotificationSettings.tsx (3)

39-43: Clean, extensible pattern for notification settings.

Passing explicit type and channel props with the settings array enables easy addition of new notification types while maintaining type safety through the enum constraints.


85-107: Optimistic update now correctly handles new settings.

The logic addresses the previous concern about optimistic updates failing for new notification settings. By searching for existingItem using the user_id + type + channel combination (rather than just id), and creating a temporary record when none exists, the UI now responds immediately for both existing and first-time settings.


133-165: LGTM — callback and rendering logic are correct.

  • The useCallback dependencies are exhaustive and accurate.
  • The labelId pattern (notification-setting-${type}-${channel}) ensures unique accessibility IDs.
  • Defaulting checked to false when no setting exists is the safe behavior.
  • The throttled callback appropriately prevents rapid-fire mutations.

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

♻️ Duplicate comments (1)
apps/web/src/components/settings/notification/NotificationSettings.tsx (1)

64-67: Good fix for temp ID filtering; comment still misleading.

Line 65 correctly prevents temp IDs from being sent to the server—this addresses the prior review concern.

However, the comment on line 67 claims "user id is already overridden in the onMutate function," but onMutate doesn't modify user_id—it passes the value through as-is. Consider clarifying where user_id is actually resolved (likely the backend/mutation hook).

Suggested comment update
-    const user_id = setting?.user_id ?? ""; // fallback to empty string if user id is not set, the user id is already overridden in the onMutate function.
+    const user_id = setting?.user_id ?? ""; // fallback to empty string; actual user_id is set by the backend from the session
🧹 Nitpick comments (1)
apps/web/src/components/settings/notification/NotificationSettings.tsx (1)

14-19: Consider moving type aliases before their usage.

The type aliases NotificationType and NotificationChannel are defined after NOTIFICATION_LABEL_MAP uses NotificationType. While TypeScript hoists type declarations, placing the aliases before the map improves readability.

Suggested reordering
+type NotificationType = Enums<"notification_type">;
+type NotificationChannel = Enums<"notification_channel">;
+
 const NOTIFICATION_LABEL_MAP: Record<NotificationType, string> = {
   new_companies: "Receive email updates for new companies added",
 };
-
-type NotificationType = Enums<"notification_type">;
-type NotificationChannel = Enums<"notification_channel">;
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9208822 and b7dd521.

📒 Files selected for processing (1)
  • apps/web/src/components/settings/notification/NotificationSettings.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Web E2E Tests
  • GitHub Check: Cursor Bugbot
🔇 Additional comments (4)
apps/web/src/components/settings/notification/NotificationSettings.tsx (4)

39-43: LGTM!

Clean simplification that passes the settings array with explicit type and channel props. The component now derives the matching setting internally, which is a good separation of concerns.


87-109: Well-designed optimistic update handling.

The logic now correctly handles both update and insert scenarios:

  • Finding existing items by user_id + type + channel (not by ID) ensures proper upsert semantics.
  • New items get a temp-prefixed ID, timestamps, and safe enabled fallback.

This addresses the prior review concern about optimistic updates failing for new notification settings.


135-148: LGTM!

The mutation payload correctly omits id for new settings (allowing server-side ID generation) and includes all necessary fields. The dependency array is complete.


155-168: LGTM!

Deterministic labelId based on type/channel ensures stable accessibility. The setting?.enabled ?? false fallback safely handles cases where the setting doesn't exist yet.

@alexmarqs alexmarqs merged commit 1296e33 into main Dec 29, 2025
4 checks passed
@alexmarqs alexmarqs deleted the chore/fix-notification-settings-for-old-db-entries branch December 30, 2025 11:36
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.

1 participant