Skip to content

fix: Add mobile app rules covering hybrid frontend (React Native).#9

Open
sagarkoshti1990 wants to merge 3 commits intotekdi:mainfrom
sagarkoshti1990:main
Open

fix: Add mobile app rules covering hybrid frontend (React Native).#9
sagarkoshti1990 wants to merge 3 commits intotekdi:mainfrom
sagarkoshti1990:main

Conversation

@sagarkoshti1990
Copy link

No description provided.

@coderabbitai
Copy link

coderabbitai bot commented Jul 28, 2025

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Tooling: Added mobile-app project support (languages/frameworks) and a debug mode to the copy script for faster local workflows.
  • Documentation

    • Introduced comprehensive hybrid mobile and React Native guidelines covering architecture, UI patterns, data/state, API integration, performance, security, accessibility, and testing.
    • Minor formatting cleanup in existing docs.
  • Chores

    • Enhanced script UX with improved prompts, input handling, repository validation, and clearer output.
    • Refined cloning/cleanup behavior based on debug mode.

Walkthrough

Adds extensive mobile-app guidance (hybrid frontend and React Native) as new markdown rules and examples, and enhances copy-cursor-rules.sh with mobile-app support, argument parsing, a debug/local-repo mode, and expanded language/framework selection. Also inserts a single empty line in a common markdown file.

Changes

Cohort / File(s) Change Summary
Hybrid Frontend Guidelines
6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-1-architecture-rules.mdc, 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-2-ui-patterns-rules.mdc, 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-3-data-state-rules.mdc, 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-4-api-integration-service-layer.mdc, 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-5-performance-rules.mdc, 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-6-security-rules.mdc, 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-7-accessibility-rules.mdc, 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-8-testing-rules.mdc
Added comprehensive hybrid frontend documentation covering architecture, UI/UX patterns, data/state, API/service layer, performance, security, accessibility, and testing rules.
React Native Guidelines & Examples
6-mobile-app/javascript/react-native/react-native-1-architecture-rules.mdc, 6-mobile-app/javascript/react-native/react-native-2-ui-patterns-rules.mdc, 6-mobile-app/javascript/react-native/react-native-3-data-state-rules.mdc, 6-mobile-app/javascript/react-native/react-native-4-api-integration-rules.mdc, 6-mobile-app/javascript/react-native/react-native-5-performance-rules.mdc, 6-mobile-app/javascript/react-native/react-native-6-security-rules.mdc, 6-mobile-app/javascript/react-native/react-native-7-accessibility-rules.mdc, 6-mobile-app/javascript/react-native/react-native-8-testing-rules.mdc
Added detailed React Native guidance and example code (components, hooks, services, utilities) across architecture, UI patterns, state management, API integration (React Query), performance, security, accessibility, and testing.
Script: mobile-app support & debug
copy-cursor-rules.sh
Refactored and extended script: added argument parsing, --debug mode to use local repo, mobile-app project type, expanded language/framework menus (mobile languages/frameworks), repo structure validation, and mobile-app copying logic (including special React Native handling).
Minor formatting
2-common/common-mobile-app.md
Inserted an empty line; no behavioral changes.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Script
    participant Repo as Repo(Local/Remote)
    participant FS as FileSystem

    User->>Script: run copy-cursor-rules.sh [args]
    Script->>Script: parse arguments (help, --debug)
    alt debug mode
        Script->>Repo: locate local repository path
    else
        Script->>Repo: clone repository from remote
    end
    Script->>Script: validate repo structure (expect 1-tekdi)
    Script->>User: prompt for project type
    User->>Script: select project type (backend/frontend/mobile-app)
    Script->>User: prompt for language
    User->>Script: select language
    Script->>User: prompt for framework
    User->>Script: select framework
    Script->>FS: copy common rules
    Script->>FS: copy language rules
    Script->>FS: copy framework rules
    alt framework == react-native
        Script->>FS: also copy hybrid-frontend rules
    end
    Script->>User: print completion (suppress cleanup note if debug)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45–90 minutes

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbit in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbit in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbit gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbit read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbit help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbit ignore or @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbit summary or @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbit or @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 14

🧹 Nitpick comments (20)
2-common/common-mobile-app.md (1)

1-1: Remove the no-op newline to avoid noisy blame.

The commit only adds an empty line, creating needless churn in git blame. If the file intentionally remains empty, delete the newline and add a short comment explaining why the file exists.

6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-4-api-integration-service-layer.mdc (1)

2-2: Fix typo in front-matter description.

intergratingintegrating.

-description: USE WHEN intergrating APIs
+description: USE WHEN integrating APIs
6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-7-accessibility-rules.mdc (1)

2-2: Polish front-matter grammar for clarity.

Current text is missing a plural and reads awkwardly.

-description: USE WHEN creating inclusive, accessible web applications to ensure application work for all users, including those with disabilities
+description: USE WHEN creating inclusive, accessible applications to ensure they work for all users, including those with disabilities
6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-8-testing-rules.mdc (1)

2-2: Tighten description wording.

Small grammar tweaks improve readability.

-description: USE WHEN writing test for ensuring testing and quality principles to build reliable, maintainable frontend applications with comprehensive test coverage and robust error handling
+description: USE WHEN writing tests to uphold quality principles and build reliable, maintainable frontend applications with comprehensive coverage and robust error handling
6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-6-security-rules.mdc (1)

2-2: Deduplicate and shorten the security description.

The sentence repeats itself; tightening it improves comprehension.

-description: USE WHEN securing frontend applications that protect both your users and your systems from common web security threats protect your applications and users from common security vulnerabilities
+description: USE WHEN securing frontend applications to protect users and systems from common web security threats
6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-3-data-state-rules.mdc (1)

13-14: Clarify platform-specific storage APIs

localStorage is unavailable in React Native. Add explicit guidance for native equivalents (AsyncStorage, SecureStore) to avoid confusion for hybrid teams.

- - Store session state in client-side or shared backing services (localStorage, SecureStore, etc.)
+ - Store session state in client-side or shared backing services  
+   - Web: `localStorage`, `sessionStorage`  
+   - React Native: `AsyncStorage`, `SecureStore` (for sensitive data)
6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-1-architecture-rules.mdc (1)

44-52: Recommend an “index” barrel guideline

To reinforce the File Organization section, consider adding a rule on optional index.{ts,js} barrels for feature folders, clarifying when they are helpful vs. when they hide structure.

6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-2-ui-patterns-rules.mdc (1)

24-28: Define design-token source for breakpoints

The rule advises avoiding “magic numbers” but doesn’t specify where breakpoint constants live. Point readers to a central design-token file or theme object to keep implementations consistent.

6-mobile-app/javascript/react-native/react-native-3-data-state-rules.mdc (1)

284-303: Harden useAsyncStorage against JSON-parse failures & race conditions

  1. JSON.parse may throw – wrap it.
  2. Multiple quick setValue calls can suffer lost updates because the await is outside setStoredValue.
-      const item = await AsyncStorage.getItem(key);
-      if (item) setStoredValue(JSON.parse(item));
+      const item = await AsyncStorage.getItem(key);
+      if (item) {
+        try {
+          setStoredValue(JSON.parse(item));
+        } catch {
+          // silently ignore corrupt value
+        }
+      }
-  const setValue = async (value) => {
-    const valueToStore = value instanceof Function ? value(storedValue) : value;
-    setStoredValue(valueToStore);
-    await AsyncStorage.setItem(key, JSON.stringify(valueToStore));
-  };
+  const setValue = (value) => {
+    setStoredValue(prev => {
+      const valueToStore = value instanceof Function ? value(prev) : value;
+      AsyncStorage.setItem(key, JSON.stringify(valueToStore)).catch(() => {});
+      return valueToStore;
+    });
+  };
6-mobile-app/javascript/react-native/react-native-5-performance-rules.mdc (1)

46-53: React.memo custom comparer ignores other user fields – potential stale renders

Only id, firstName, lastName, isSelected, and onEdit are compared.
If user.avatar, createdAt, or any later-added field changes, the card will not re-render, showing stale data.

Consider either:

-}, (prevProps, nextProps) => {
-  return (
-    prevProps.user.id === nextProps.user.id &&
-    prevProps.user.firstName === nextProps.user.firstName &&
-    prevProps.user.lastName === nextProps.user.lastName &&
-    prevProps.isSelected === nextProps.isSelected &&
-    prevProps.onEdit === nextProps.onEdit
-  );
-});
+}, (p, n) =>
+  p.user === n.user &&           // pointer compare (user object replaced on updates)
+  p.isSelected === n.isSelected &&
+  p.onEdit === n.onEdit);

or drop the custom comparer and rely on shallow compare if the parent already replaces the user object when it mutates.

copy-cursor-rules.sh (3)

61-66: Avoid masking subshell exit status; declare variables separately
Assigning current_dir in the same line where the subshell is executed (local current_dir="$(cd ... && pwd)") hides a possible cd failure and triggers SC2155. Split the declaration from the assignment.

-        local current_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+        local current_dir
+        current_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

189-198: Duplicate mobile-app pattern in case block
mobile-app|mobile-app|… contains the same token twice, producing ShellCheck SC2221/SC2222. Remove the duplicate to keep the pattern list intentional.

-            3|mobile-app|mobile-app|Mobile-app|Mobile-app|MOBILE-APP|MOBILE-APP)
+            3|mobile-app|Mobile-app|MOBILE-APP)

360-387: Consider normalising framework input once instead of huge pattern lists
Long, repetitive case patterns make maintenance hard and trigger multiple SC2221 warnings. Lower-case the input and replace underscores with dashes before the case, then keep a single canonical token per framework.

6-mobile-app/javascript/react-native/react-native-6-security-rules.mdc (1)

118-130: Access tokens stored in plain AsyncStorage are vulnerable
AsyncStorage is unencrypted; malicious apps, backups or rooted devices can read it. Recommend Keychain/SecureStore or an encrypted wrapper.

6-mobile-app/javascript/react-native/react-native-1-architecture-rules.mdc (1)

135-147: Duplicate Button example may confuse readers
A Button component is already defined earlier (lines 37-54). Redefining it here with different props could mislead implementers. Consider renaming the atom or referencing the initial definition.

6-mobile-app/javascript/react-native/react-native-4-api-integration-rules.mdc (5)

2-2: Fix typo in front-matter description.

intergratingintegrating.

-description: USE WHEN intergrating APIs
+description: USE WHEN integrating APIs

16-30: Clarify ApiResponse shape & optional fields.

status duplicates HTTP status and inflates every in-memory payload, and message is not always present. Consider:

-interface ApiResponse<T> {
-  data: T;
-  status: number;
-  message?: string;
-}
+interface ApiResponse<T> {
+  data: T;
+  message?: string; // omit if you never rely on it
+}

50-62: Pagination default should be 1-based or explicit.

Most APIs start pages at 1; starting at 0 silently creates an off-by-one gap. At minimum, add a comment or make the default 1.


89-102: PATCH helper duplicates createUser logic—extract DRY error handler.

Both methods share identical fetch/error/parse boilerplate. A tiny generic helper improves maintainability.

-const apiResponse: ApiResponse<User> = await response.json();
-return apiResponse.data;
+return handleJson<User>(response);

(where handleJson wraps the pattern above)


142-145: Redundant cache set followed by invalidate.

You setQueryData then immediately invalidateQueries(['users']), nullifying the optimistic benefit. Drop the explicit invalidate unless stale persistence is required.

-      queryClient.setQueryData(['users'], (oldUsers: User[] | undefined) => {
-        return oldUsers ? [...oldUsers, newUser] : [newUser];
-      });
-      queryClient.invalidateQueries(['users']);
+      queryClient.setQueryData(['users'], (old: User[] | undefined) =>
+        old ? [...old, newUser] : [newUser],
+      );
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 05d0677 and 9164af2.

📒 Files selected for processing (18)
  • 2-common/common-mobile-app.md (1 hunks)
  • 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-1-architecture-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-2-ui-patterns-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-3-data-state-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-4-api-integration-service-layer.mdc (1 hunks)
  • 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-5-performance-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-6-security-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-7-accessibility-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-8-testing-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-1-architecture-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-2-ui-patterns-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-3-data-state-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-4-api-integration-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-5-performance-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-6-security-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-7-accessibility-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-8-testing-rules.mdc (1 hunks)
  • copy-cursor-rules.sh (12 hunks)
🧰 Additional context used
🪛 Shellcheck (0.10.0)
copy-cursor-rules.sh

[warning] 61-61: Declare and assign separately to avoid masking return values.

(SC2155)


[warning] 192-192: This pattern always overrides a later one on line 192.

(SC2221)


[warning] 192-192: This pattern never matches because of a previous pattern on line 192.

(SC2222)


[warning] 192-192: This pattern always overrides a later one on line 192.

(SC2221)


[warning] 192-192: This pattern never matches because of a previous pattern on line 192.

(SC2222)


[warning] 192-192: This pattern always overrides a later one on line 192.

(SC2221)


[warning] 192-192: This pattern never matches because of a previous pattern on line 192.

(SC2222)

🔇 Additional comments (4)
6-mobile-app/javascript/hybrid-frontend/hybrid-frontend-5-performance-rules.mdc (1)

1-107: Comprehensive & coherent – no blocking issues spotted

Content aligns with established best practices; reads well and complements the RN ruleset.

copy-cursor-rules.sh (1)

657-667: Hybrid-frontend rules copied for Ionic unintentionally
The guard includes "$framework" == "ionic" which results in React-Native-specific hybrid rules being copied into Ionic projects. Verify Ionic actually re-uses those rules; otherwise restrict the check to react-native only.

6-mobile-app/javascript/react-native/react-native-1-architecture-rules.mdc (1)

268-291: AbortController requires RN ≥ 0.64 or a polyfill
Older RN versions running on JSC lack AbortController. Add a compatibility note or import a polyfill to keep the example production-ready.

6-mobile-app/javascript/react-native/react-native-4-api-integration-rules.mdc (1)

265-274: getNextPageParam logic mis-aligns with 0-based pages.

You return allPages.length which equals the current page count, not pageParam + 1, causing duplicate fetch of page 0 on first fetchNextPage(). Quick fix:

-return lastPage.length === pageSize ? allPages.length : undefined;
+return lastPage.length === pageSize ? allPages.length : undefined; // assumes 1-based

or compute pageParam + 1 when your API is 0-based.

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: 13

♻️ Duplicate comments (8)
6-mobile-app/javascript/react-native/react-native-8-testing-rules.mdc (2)

18-25: Good: RN Testing Library imports are correct (no web-only userEvent).


120-121: Good: Using RN-specific renderHook import (hooks package deprecated).

6-mobile-app/javascript/react-native/react-native-4-api-integration-rules.mdc (3)

87-96: Good fix on non‑JSON error bodies.

The safe JSON parse with fallback resolves the previous double‑throw/swallow issue.


40-44: Config.API_HOST used but not imported. Add import and brief note.

Add react-native-config import at the top of the TSX block and note its source.

 ```tsx
+import Config from 'react-native-config';
 interface ApiResponse<T> {
Add a sentence near this snippet: “Config.API_HOST is provided by react-native-config.”

---

`205-207`: **Import `NetInfo` and remove unused handlers.**

Without the import, the example won’t compile; the local `handleOnline/handleOffline` vars are unused.


```diff
 import { useEffect, useState, useCallback } from "react";
 import { useQuery } from "@tanstack/react-query";
+import NetInfo from "@react-native-community/netinfo";

   useEffect(() => {
-    const handleOnline = () => setIsOnline(true);
-    const handleOffline = () => setIsOnline(false);
-
     const unsubscribe = NetInfo.addEventListener((state) =>
       setIsOnline(state.isConnected ?? true)
     );
 
     return unsubscribe;
   }, []);

Also applies to: 234-242

6-mobile-app/javascript/react-native/react-native-6-security-rules.mdc (3)

13-16: Good: RN does not render HTML; no DOM-based sanitizers imported.

Resolves prior concern about DOMPurify import breaking Metro.


92-105: Good: Hermes/JSC note with fallback for URL usage.

The explanatory comments and fallback parser address runtime crashes on older engines.


290-302: Missing imports for useMemo and useAuth in useSecureApi snippet.

Without imports, copy/paste fails at runtime.

+import { useMemo } from "react";
+import { useAuth } from "./useAuth"; // adjust path as applicable
 export const useSecureApi = () => {
   const { accessToken } = useAuth();
🧹 Nitpick comments (8)
6-mobile-app/javascript/react-native/react-native-8-testing-rules.mdc (4)

2-2: Polish the front-matter description (grammar/clarity).

-description: USE WHEN writing test for ensuring testing and quality principles to build reliable, maintainable frontend applications with comprehensive test coverage and robust error handling
+description: USE WHEN writing tests to ensure testing and quality principles for reliable, maintainable frontend apps with comprehensive coverage and robust error handling

74-76: Assert loading state clears after data loads.

Add a quick regression check so examples don’t leave stale loaders:

   await screen.findByText("John Doe");
+  expect(screen.queryByText(/loading/i)).toBeNull();

100-107: Clarify accessibility requirement for alert role.

getByRole('alert') will only work if your component sets role="alert" or accessibilityRole="alert". Add a note to prevent copy-paste confusion. The role and query are supported in RNTL. (callstack.github.io)

   await waitFor(() => {
-      expect(screen.getByRole("alert")).toHaveTextContent(
+      // Ensure the error element has role/ accessibilityRole "alert" in the component under test.
+      expect(screen.getByRole("alert")).toHaveTextContent(
         /failed to load user/i
       );
   });

223-229: Tighten console.error spy lifecycle (avoid type casts).

-describe("ErrorBoundary", () => {
-  beforeEach(() => {
-    jest.spyOn(console, "error").mockImplementation(() => {});
-  });
-
-  afterEach(() => {
-    (console.error as jest.Mock).mockRestore();
-  });
+describe("ErrorBoundary", () => {
+  let consoleSpy: jest.SpyInstance;
+  beforeEach(() => {
+    consoleSpy = jest.spyOn(console, "error").mockImplementation(() => {});
+  });
+  afterEach(() => {
+    consoleSpy.mockRestore();
+  });
6-mobile-app/javascript/react-native/react-native-4-api-integration-rules.mdc (3)

43-50: Harden error messages: include status code; avoid empty statusText.

Improves diagnostics across all service methods.

-throw new Error(`Failed to fetch users: ${response.statusText}`);
+throw new Error(`Failed to fetch users (${response.status}${response.statusText ? ' ' + response.statusText : ''}).`);

-`Failed to fetch paginated users: ${response.statusText}`
+`Failed to fetch paginated users (${response.status}${response.statusText ? ' ' + response.statusText : ''})`

-`Failed to fetch user: ${response.statusText}`
+`Failed to fetch user (${response.status}${response.statusText ? ' ' + response.statusText : ''})`

-`Failed to update user: ${response.statusText}`
+`Failed to update user (${response.status}${response.statusText ? ' ' + response.statusText : ''})`

Also applies to: 61-69, 71-78, 102-115


164-166: Use TanStack Query v4 object signatures for invalidate/cancel.

Aligns with current API and improves type hints.

-      queryClient.invalidateQueries(["users"]);
+      queryClient.invalidateQueries({ queryKey: ["users"] });

-      await queryClient.cancelQueries(["users", id]);
+      await queryClient.cancelQueries({ queryKey: ["users", id] });

-      queryClient.invalidateQueries(["users", id]);
-      queryClient.invalidateQueries(["users"]);
+      queryClient.invalidateQueries({ queryKey: ["users", id] });
+      queryClient.invalidateQueries({ queryKey: ["users"] });

Also applies to: 176-177, 188-191


287-287: Export or remove unused requestDeduplicator.

It’s declared but not used in examples.

-const requestDeduplicator = new RequestDeduplicator();
+export const requestDeduplicator = new RequestDeduplicator();

If intentionally unused here, consider removing to avoid dead code in docs.

6-mobile-app/javascript/react-native/react-native-6-security-rules.mdc (1)

106-113: Tighten protocol parse in JSC fallback.

Use the capture group (without colon) to avoid edge-cases and normalize once.

-  const protocolMatch = url.match(/^([^:]+):/);
+  const protocolMatch = url.match(/^([^:]+):/);
   if (!protocolMatch) return false;
-  const protocol = protocolMatch[0].toLowerCase();
-  return ["http:", "https:", "mailto:"].includes(protocol);
+  const proto = `${protocolMatch[1].toLowerCase()}:`;
+  return ["http:", "https:", "mailto:"].includes(proto);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9164af2 and 73706a7.

📒 Files selected for processing (6)
  • 6-mobile-app/javascript/react-native/react-native-2-ui-patterns-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-3-data-state-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-4-api-integration-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-6-security-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-7-accessibility-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-8-testing-rules.mdc (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • 6-mobile-app/javascript/react-native/react-native-2-ui-patterns-rules.mdc
  • 6-mobile-app/javascript/react-native/react-native-7-accessibility-rules.mdc
  • 6-mobile-app/javascript/react-native/react-native-3-data-state-rules.mdc
🔇 Additional comments (1)
6-mobile-app/javascript/react-native/react-native-6-security-rules.mdc (1)

224-243: Rate-limit hook looks good.

Clear windowing logic and memoization.

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 (4)
6-mobile-app/javascript/react-native/react-native-4-api-integration-rules.mdc (4)

18-25: Add the missing Config import to make the snippet copy‑pasteable.

Without importing Config, the service example won’t run as-is.

 ```tsx
+import Config from 'react-native-config';
+
 interface ApiResponse<T> {

Also add a one-liner in the doc that API_HOST is provided via react-native-config (or your env system).


40-45: Add a fetchWithTimeout helper and use it to actually cancel slow requests.

Promise.race doesn’t abort RN fetches; AbortController does. Provide a default timeout and reuse everywhere.

 interface CreateUserRequest {
   email: string;
   firstName: string;
   lastName: string;
   password: string;
 }
 
+const fetchWithTimeout = (
+  input: RequestInfo | URL,
+  init: RequestInit = {},
+  timeoutMs = 15000
+) => {
+  const controller = new AbortController();
+  const id = setTimeout(() => controller.abort(), timeoutMs);
+  const signal = init.signal ?? controller.signal;
+  return fetch(input, { ...init, signal }).finally(() => clearTimeout(id));
+};
+
 class UserService {
   private baseURL = `${Config.API_HOST}/users`;

And replace bare fetch calls with fetchWithTimeout (e.g., in getUsers):

-    const response = await fetch(this.baseURL);
+    const response = await fetchWithTimeout(this.baseURL);

(Apply similarly in other methods.)


205-208: Import NetInfo for the network-aware hook.

Missing import breaks the snippet.

 import { useEffect, useState, useCallback } from "react";
 import { useQuery } from "@tanstack/react-query";
+import NetInfo from "@react-native-community/netinfo";

276-281: Fix accidental diff markers in code block.

Leading “+” chars make the snippet invalid when copied.

-    const timeout = new Promise<never>((_, reject) =>
-+      setTimeout(() => reject(new Error(`Request timed out after ${timeoutMs}ms`)), timeoutMs)
-+    );
-+    const request = Promise.race([requestFn(), timeout])
-+      .finally(() => this.pendingRequests.delete(key)) as Promise<T>;
+    const timeout = new Promise<never>((_, reject) =>
+      setTimeout(() => reject(new Error(`Request timed out after ${timeoutMs}ms`)), timeoutMs)
+    );
+    const request = Promise.race([requestFn(), timeout])
+      .finally(() => this.pendingRequests.delete(key)) as Promise<T>;

Also note: Promise.race doesn’t cancel the underlying fetch on RN—pair with AbortController/timeouts.

🧹 Nitpick comments (3)
6-mobile-app/javascript/react-native/react-native-4-api-integration-rules.mdc (3)

154-167: Avoid redundant refetch right after local cache insert.

You already merge the new user into ["users"]; invalidating immediately refetches and can cause flicker/duplication. Either keep setQueryData OR invalidate; not both.

       queryClient.setQueryData(["users"], (oldUsers: User[] | undefined) => {
         return oldUsers ? [...oldUsers, newUser] : [newUser];
       });
-      queryClient.invalidateQueries(["users"]);

(If server is source of truth, drop setQueryData and keep invalidate instead.)


234-236: Remove unused handlers.

handleOnline/handleOffline are declared but never used.

-    const handleOnline = () => setIsOnline(true);
-    const handleOffline = () => setIsOnline(false);

268-285: Consider type safety and eviction in RequestDeduplicator.

Map<string, Promise> can mix types under the same key across call sites; add a convention that keys include the resource type or store a typed wrapper. Also consider a max size/LRU to prevent unbounded growth under churn.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 73706a7 and fefbafe.

📒 Files selected for processing (3)
  • 6-mobile-app/javascript/react-native/react-native-4-api-integration-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-6-security-rules.mdc (1 hunks)
  • 6-mobile-app/javascript/react-native/react-native-8-testing-rules.mdc (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • 6-mobile-app/javascript/react-native/react-native-6-security-rules.mdc
  • 6-mobile-app/javascript/react-native/react-native-8-testing-rules.mdc
🔇 Additional comments (1)
6-mobile-app/javascript/react-native/react-native-4-api-integration-rules.mdc (1)

118-119: Nice: centralizing service instance for hooks.

Exported userService keeps the examples tidy and consistent.

Comment on lines +61 to +69
const response = await fetch(`${this.baseURL}?${params}`);
if (!response.ok) {
throw new Error(
`Failed to fetch paginated users: ${response.statusText}`
);
}
const apiResponse: ApiResponse<User[]> = await response.json();
return apiResponse.data;
}
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

Confirm URLSearchParams availability on your RN targets or add a safe fallback.

Older RN apps/environments may lack URLSearchParams without polyfills. Verify your minimum RN version or add a tiny helper to build the query string.


🌐 Web query:

Does React Native (0.72 and later) include a global URLSearchParams implementation by default on Hermes/JSC?

💡 Result:

Short answer: No. React Native (including 0.72+) does not reliably provide a full global URLSearchParams implementation on Hermes or JSC — the built-in URL support is lightweight/incomplete and many apps use react-native-url-polyfill (or similar) to get URLSearchParams. [1][2][3]

Sources:

  • react-native-url-polyfill README (notes React Native's URL is incomplete; recommends the polyfill). [1]
  • Hermes issue discussing lack of full URL/Web API support and recommending polyfills. [2]
  • npm / package docs for react-native-url-polyfill (installation and usage). [3]

Add URLSearchParams polyfill or manual query builder
React Native’s built-in URL support is minimal and does not reliably include URLSearchParams on Hermes/JSC (RN 0.72+) (github.com). Import a polyfill (e.g., react-native-url-polyfill or react-native-fast-url) in your app’s entry file or replace new URLSearchParams() with a small helper to build the ?key=value… string before lines 61–69.

🤖 Prompt for AI Agents
In 6-mobile-app/javascript/react-native/react-native-4-api-integration-rules.mdc
around lines 61–69, the code relies on URLSearchParams which is not guaranteed
in React Native (Hermes/JSC); either import a URLSearchParams polyfill at the
app entry (e.g., add `import 'react-native-url-polyfill/auto'` or similar to
index.js/App.tsx) or replace the URLSearchParams usage with a small helper that
URL-encodes keys and values and concatenates them into a query string
(encodeURIComponent for keys/values, join with & and prefix with ?), then use
that string in the fetch call so the request works consistently on RN runtimes.

Comment on lines +109 to +115
if (!response.ok) {
throw new Error(`Failed to update user: ${response.statusText}`);
}

const apiResponse: ApiResponse<User> = await response.json();
return apiResponse.data;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Unify error parsing with createUser; preserve server message for updateUser.

Mirror the defensive JSON parsing used in createUser so non‑JSON bodies don’t mask the failure reason.

-    if (!response.ok) {
-      throw new Error(`Failed to update user: ${response.statusText}`);
-    }
+    if (!response.ok) {
+      let detail = 'Failed to update user';
+      try {
+        const body = await response.json();
+        detail = body?.message ?? detail;
+      } catch {}
+      throw new Error(detail);
+    }
📝 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
if (!response.ok) {
throw new Error(`Failed to update user: ${response.statusText}`);
}
const apiResponse: ApiResponse<User> = await response.json();
return apiResponse.data;
}
if (!response.ok) {
let detail = 'Failed to update user';
try {
const body = await response.json();
detail = body?.message ?? detail;
} catch {}
throw new Error(detail);
}
const apiResponse: ApiResponse<User> = await response.json();
return apiResponse.data;
}
🤖 Prompt for AI Agents
In 6-mobile-app/javascript/react-native/react-native-4-api-integration-rules.mdc
around lines 109 to 115, the updateUser branch throws a generic Error using
response.statusText and then parses JSON normally, which can lose
server-provided error details when the body is non-JSON; change to mirror
createUser’s defensive parsing: when response.ok is false, read the raw response
body (e.g., response.text()), attempt to JSON.parse it to extract a server
message field, and if parsing fails fall back to the raw text or
response.statusText, then throw a new Error that includes the HTTP status plus
the preserved server message so callers get the original failure reason.

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