Skip to content

Fix org settings modal: use same data source as button for name and i…#1434

Merged
sidneyswift merged 1 commit intomainfrom
fix/orgsettingsmodal
Dec 12, 2025
Merged

Fix org settings modal: use same data source as button for name and i…#1434
sidneyswift merged 1 commit intomainfrom
fix/orgsettingsmodal

Conversation

@sidneyswift
Copy link
Collaborator

@sidneyswift sidneyswift commented Dec 12, 2025

…mage

Summary by CodeRabbit

  • Bug Fixes

    • Fixed organization settings data loading when switching between organizations.
    • Added error handling for account details retrieval to improve reliability.
  • Refactor

    • Optimized organization data synchronization to ensure timely updates when organization information changes.

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

@vercel
Copy link
Contributor

vercel bot commented Dec 12, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
recoup-chat Ready Ready Preview Dec 12, 2025 10:39pm

@supabase
Copy link

supabase bot commented Dec 12, 2025

This pull request has been ignored for the connected project godremdqwajrwazhbrue because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 12, 2025

Walkthrough

The useOrgSettings hook is refactored to integrate useAccountOrganizations and useUserProvider hooks, shifting from direct API calls to consuming pre-fetched organization data. The initialization flow is split into two stages: immediately setting name and image from the organizations list, then fetching account details separately from the API.

Changes

Cohort / File(s) Summary
Hook Integration & Initialization
hooks/useOrgSettings.ts
Adds imports for useAccountOrganizations and useUserProvider; obtains userData and organizations from consumer hooks. Refactors effect logic to initialize org state from the organizations list before making API calls. Splits initialization: name and image are set immediately from the selected organization, while orgData, instruction, and knowledges are populated via API fetch. Updates effect dependencies to include organizations and adds guard for missing selected organization. Includes error handling for account details fetch and adjusts loading state management around the new flow.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

Areas requiring extra attention:

  • Effect dependency logic: Verify the new dependency array (orgId, organizations) correctly triggers re-initialization and doesn't cause unintended re-fetches or infinite loops
  • Data flow split: Ensure the two-stage initialization (org list → name/image, then API → orgData/instruction/knowledges) is idempotent and handles edge cases where the selected organization exists in the list but API call fails
  • Error handling: Confirm error handling for the API fetch doesn't leave the hook in an inconsistent state (e.g., partial data with stale loading flag)
  • Guard condition: Review the guard that stops loading when the selected organization is missing to ensure it's appropriate and doesn't mask real data availability issues

Possibly related PRs

Suggested reviewers

  • sweetmantech

Poem

🔗 Two hooks now dance in harmony,
Name and image set wild and free,
Then API calls for the rest,
A split-stage flow put to the test! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Solid & Clean Code ⚠️ Warning PR violates SOLID principles (SRP, OCP) and Clean Code practices with critical issues: missing AbortController causing race conditions, silent HTTP error handling, unused userData variable, and excessive complexity in single hook. Add AbortController with cleanup, remove unused userData import, implement HTTP error logging, and refactor hook to separate concerns into smaller focused functions.
✨ 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 fix/orgsettingsmodal

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.

Copy link
Contributor

@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

🧹 Nitpick comments (1)
hooks/useOrgSettings.ts (1)

53-56: Redundant setIsLoading(false) call.

At this point in the execution flow, isLoading hasn't been set to true yet (that happens inside fetchOrgDetails). This makes the code harder to reason about and suggests unclear state transitions.

Consider restructuring so loading state is only toggled when an async operation is actually involved, or add a comment explaining the intent:

     if (!selectedOrg) {
-      setIsLoading(false);
       return;
     }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4fbdc77 and 97e1d2b.

📒 Files selected for processing (1)
  • hooks/useOrgSettings.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{tsx,ts,jsx,js}

📄 CodeRabbit inference engine (.cursor/rules/component-design.mdc)

**/*.{tsx,ts,jsx,js}: Use semantic HTML elements appropriate to the component's role
Ensure keyboard navigation and focus management in UI components
Provide proper ARIA roles/states and test with screen readers
Start with semantic HTML first, then augment with ARIA if needed
Support both controlled and uncontrolled state in components
Wrap a single HTML element per component (no multiple root elements)
Favor composition over inheritance in component design
Expose clear APIs via props/slots for component customization
Use asChild pattern for flexible element types in components
Support polymorphism with as prop when appropriate
Use @radix-ui/react-* primitives for behavior and accessibility
Use class-variance-authority (CVA) for component variants
Use @radix-ui/react-slot for implementing asChild pattern
Use @radix-ui/react-use-controllable-state for state management
Follow shadcn/ui component structure and naming conventions
Use cn() utility combining clsx and tailwind-merge for class merging
Export both component and variant functions (e.g., Button, buttonVariants)
Use @radix-ui/react-icons for UI component icons (not Lucide React)
Use lucide-react for application icons and illustrations
Use framer-motion for animations and transitions
Use next-themes for theme management
Use tailwindcss-animate for CSS animations
Use sonner for toast notifications
Use embla-carousel-react for carousels
Use react-resizable-panels for resizable layouts
Provide defaultValue and onValueChange props for state management
Use data-state attribute for visual component states (open/closed, loading, etc.)
Use data-slot attribute for component identification
Use kebab-case naming for data attributes (e.g., data-slot="form-field")
Follow class order in Tailwind: base → variants → conditionals → user overrides
Define component variants outside components to avoid recreation on re-render
Implement focus trapping in modal/dialog components
Store...

Files:

  • hooks/useOrgSettings.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/component-design.mdc)

**/*.{tsx,ts}: Extend native HTML attributes using React.ComponentProps<"element"> pattern
Export component prop types with explicit ComponentNameProps naming convention

Files:

  • hooks/useOrgSettings.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/stagehand.mdc)

**/*.{ts,tsx}: Plan instructions using Stagehand observe method before executing actions (e.g., const results = await page.observe("Click the sign in button");)
Cache the results of observe to avoid unexpected DOM changes
Keep act actions atomic and specific (e.g., "Click the sign in button" not "Sign in to the website"). Avoid actions that are more than one step.
Use variable substitution with the variables parameter in act for dynamic form filling (e.g., action: "Enter Name: %name%", variables: { name: "John Doe" })
Always use Zod schemas for structured data extraction with the extract method (e.g., schema: z.object({ text: z.string() }))
Wrap array extractions in a single object when extracting multiple items using extract (e.g., schema: z.object({ buttons: z.array(z.string()) }))
Use explicit instruction and schema parameters when calling extract method
Import Stagehand types from @browserbasehq/stagehand package (e.g., import { Stagehand, Page, BrowserContext } from "@browserbasehq/stagehand";)
Initialize Stagehand with new Stagehand() constructor and call await stagehand.init() before using page automation methods
Implement main automation logic in functions that accept { page, context, stagehand } parameters
Provide specific instructions to agents instead of vague ones (e.g., "Navigate to products page and filter by 'Electronics'" not "Do some stuff on this page")
Break down complex agent tasks into smaller steps for better execution
Use error handling with try/catch blocks when executing agent tasks
Combine agents for navigation with traditional methods for precise data extraction

**/*.{ts,tsx}: Create single-responsibility components with obvious data flow
Use strict TypeScript types with zero 'any' types
Follow Next.js optimization guides for performance

Files:

  • hooks/useOrgSettings.ts
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{ts,tsx,js}: Write minimal code - use only the absolute minimum code needed
Ensure code is self-documenting through precise naming with verbs for functions and nouns for variables
Add short comments only when necessary to clarify non-obvious logic
Implement built-in security practices for authentication and data handling
Consider if code can be split into smaller functions before implementing
Avoid unnecessary abstractions during implementation
Ensure code clarity is suitable for understanding by junior developers

Files:

  • hooks/useOrgSettings.ts
hooks/**/*.ts

⚙️ CodeRabbit configuration file

hooks/**/*.ts: For custom hooks, ensure:

  • Single responsibility per hook
  • Return consistent interface
  • Handle edge cases and errors
  • Use proper dependency arrays
  • Keep hooks focused and reusable
  • Follow naming convention (use prefix)
  • DRY: Extract common hook logic into shared utilities
  • KISS: Avoid complex hook compositions, prefer simple state management

Files:

  • hooks/useOrgSettings.ts
🧬 Code graph analysis (1)
hooks/useOrgSettings.ts (1)
lib/consts.ts (1)
  • NEW_API_BASE_URL (4-4)
⏰ 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: Vercel Agent Review
  • GitHub Check: Run evaluations
🔇 Additional comments (1)
hooks/useOrgSettings.ts (1)

83-158: LGTM!

The callback functions are well-structured with proper useCallback usage and correct dependency arrays. The hook maintains single responsibility and exposes a clear, consistent interface.

Comment on lines +23 to +24
const { userData } = useUserProvider();
const { data: organizations } = useAccountOrganizations();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unused userData variable.

The userData is destructured from useUserProvider() but is never referenced anywhere in this hook. This violates the clean code principle of avoiding dead code and creates unnecessary coupling to the UserProvider context.

 const useOrgSettings = (orgId: string | null) => {
-  const { userData } = useUserProvider();
   const { data: organizations } = useAccountOrganizations();
📝 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
const { userData } = useUserProvider();
const { data: organizations } = useAccountOrganizations();
const { data: organizations } = useAccountOrganizations();
🤖 Prompt for AI Agents
In hooks/useOrgSettings.ts around lines 23–24, the destructured userData from
useUserProvider() is never used; remove the unused variable by either deleting
the call to useUserProvider() entirely if there are no side effects needed, or
change the line to not destructure userData (e.g., call the hook without
extracting userData) so the dead variable is eliminated and lint warnings are
resolved.

Comment on lines +63 to +81
const fetchOrgDetails = async () => {
setIsLoading(true);
try {
const response = await fetch(`${NEW_API_BASE_URL}/api/accounts/${orgId}`);
if (response.ok) {
const data = await response.json();
setOrgData(data.data);
setName(data.data?.name || "");
setImage(data.data?.image || "");
setInstruction(data.data?.instruction || "");
setKnowledges(data.data?.knowledges || []);
}
} catch (error) {
console.error("Error fetching org details:", error);
} finally {
setIsLoading(false);
}
};

fetchOrg();
}, [orgId]);
fetchOrgDetails();
}, [orgId, organizations]);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing cleanup for async operation creates potential race condition.

If orgId or organizations change while a fetch is in progress, the previous request continues and may complete after a newer request, potentially setting stale data. Consider using an AbortController for cleanup.

Additionally, non-ok responses (e.g., 404, 500) are silently ignored, which can make debugging difficult.

+    const abortController = new AbortController();
+
     const fetchOrgDetails = async () => {
       setIsLoading(true);
       try {
-        const response = await fetch(`${NEW_API_BASE_URL}/api/accounts/${orgId}`);
+        const response = await fetch(`${NEW_API_BASE_URL}/api/accounts/${orgId}`, {
+          signal: abortController.signal,
+        });
         if (response.ok) {
           const data = await response.json();
           setOrgData(data.data);
           setInstruction(data.data?.instruction || "");
           setKnowledges(data.data?.knowledges || []);
+        } else {
+          console.error("Failed to fetch org details:", response.status);
         }
       } catch (error) {
+        if (error instanceof Error && error.name === "AbortError") return;
         console.error("Error fetching org details:", error);
       } finally {
         setIsLoading(false);
       }
     };

     fetchOrgDetails();
+
+    return () => {
+      abortController.abort();
+    };
   }, [orgId, organizations]);
📝 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
const fetchOrgDetails = async () => {
setIsLoading(true);
try {
const response = await fetch(`${NEW_API_BASE_URL}/api/accounts/${orgId}`);
if (response.ok) {
const data = await response.json();
setOrgData(data.data);
setName(data.data?.name || "");
setImage(data.data?.image || "");
setInstruction(data.data?.instruction || "");
setKnowledges(data.data?.knowledges || []);
}
} catch (error) {
console.error("Error fetching org details:", error);
} finally {
setIsLoading(false);
}
};
fetchOrg();
}, [orgId]);
fetchOrgDetails();
}, [orgId, organizations]);
const abortController = new AbortController();
const fetchOrgDetails = async () => {
setIsLoading(true);
try {
const response = await fetch(`${NEW_API_BASE_URL}/api/accounts/${orgId}`, {
signal: abortController.signal,
});
if (response.ok) {
const data = await response.json();
setOrgData(data.data);
setInstruction(data.data?.instruction || "");
setKnowledges(data.data?.knowledges || []);
} else {
console.error("Failed to fetch org details:", response.status);
}
} catch (error) {
if (error instanceof Error && error.name === "AbortError") return;
console.error("Error fetching org details:", error);
} finally {
setIsLoading(false);
}
};
fetchOrgDetails();
return () => {
abortController.abort();
};
}, [orgId, organizations]);

Comment on lines +53 to +56
if (!selectedOrg) {
setIsLoading(false);
return;
}
Copy link
Contributor

@vercel vercel bot Dec 12, 2025

Choose a reason for hiding this comment

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

When a selected organization is not found in the organizations list, only isLoading is reset to false without clearing other state variables, leaving stale organization data (name, image) displayed in the UI.

View Details
📝 Patch Details
diff --git a/hooks/useOrgSettings.ts b/hooks/useOrgSettings.ts
index e6e0504c..870b1f8d 100644
--- a/hooks/useOrgSettings.ts
+++ b/hooks/useOrgSettings.ts
@@ -51,6 +51,11 @@ const useOrgSettings = (orgId: string | null) => {
     );
 
     if (!selectedOrg) {
+      setOrgData(null);
+      setName("");
+      setImage("");
+      setInstruction("");
+      setKnowledges([]);
       setIsLoading(false);
       return;
     }

Analysis

Stale organization data displayed when selected organization not found in list

What fails: When navigating to an organization that's not in the user's organizations list, the useOrgSettings hook clears isLoading but leaves name, image, instruction, and knowledges state intact, causing the UI to display the previously viewed organization's data instead of clearing it.

How to trigger it:

  1. View Organization A settings - loads successfully with name and image populated
  2. Change permissions or context so Organization B is not in the user's organizations list
  3. Navigate to Organization B settings
  4. The component renders Organization A's name and image instead of a clean/empty state

Result: UI displays stale data from Organization A while attempting to load Organization B

Expected: When selectedOrg is not found in the organizations list (lines 52-55), all state variables should be cleared to match the behavior at lines 40-44. This prevents stale data from being displayed.

Root cause: Inconsistent state clearing logic - lines 40-44 clear all state when organizations is null/undefined, but lines 52-55 only reset isLoading when the organization is not found in the list. This asymmetry causes stale data to persist in the UI.

@sidneyswift sidneyswift merged commit 141a01d into main Dec 12, 2025
4 of 6 checks passed
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +39 to +43
if (!orgId || !organizations) {
setOrgData(null);
setName("");
setImage("");
setInstruction("");

Choose a reason for hiding this comment

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

P1 Badge Avoid skipping org fetch when org list is unavailable

The guard now returns when organizations is falsy (lines 39‑43), clearing the form state and leaving isLoading false, so the modal renders an empty, saveable form and never calls /api/accounts/${orgId} whenever the organizations query is still loading or has errored. In those cases org settings can no longer load and a user could overwrite existing data with blanks, whereas previously the hook fetched as soon as orgId was set independent of the org list.

Useful? React with 👍 / 👎.

}

const useOrgSettings = (orgId: string | null) => {
const { userData } = useUserProvider();
Copy link
Collaborator

Choose a reason for hiding this comment

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

YAGNI principle

  • actual: userData is unused in this file.
  • required: delete unused variables.

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