Skip to content

Minor fixes 1012#1561

Merged
duckduckhero merged 26 commits intomainfrom
minor-fixes-1012
Oct 12, 2025
Merged

Minor fixes 1012#1561
duckduckhero merged 26 commits intomainfrom
minor-fixes-1012

Conversation

@duckduckhero
Copy link
Contributor

No description provided.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 12, 2025

📝 Walkthrough

Walkthrough

Refactors Contacts to derive data from persisted TinyBase IDs/hooks instead of props, removes several contacts fields from the tabs state, adds a TinyBase index sessionsByHuman, replaces participant click logging with useTabs.openNew, and applies multiple presentational and header/sorting UI tweaks.

Changes

Cohort / File(s) Summary of changes
VCS ignore
\.gitignore
Added CLAUDE.md to ignore patterns.
Folder tab container sizing
apps/desktop2/src/components/main/body/folders.tsx
Added h-full to the outer container in TabContentFolderTopLevel.
Session participant → open contacts
apps/desktop2/src/components/main/body/sessions/outer-header/participant.tsx
Imported useTabs and replaced a console.log with openNew(...) to open contacts pre-filled with the clicked participant id and UI state.
Contacts root / wiring
apps/desktop2/src/components/main/body/contacts/index.tsx
Rewrote ContactView to use useTabs.openNew, memoized callbacks, removed many prop/state fields (editingPerson/editingOrg/showNewOrg/sortOption), and simplified selection/creation/session-opening handlers.
Contacts — Details (contact view)
apps/desktop2/src/components/main/body/contacts/details.tsx
Converted DetailsColumn to accept selectedHumanId, derive person data/sessions/mappings from persisted tables, moved editing into internal state, and changed EditPersonForm and child fields to accept personId.
Contacts — Organizations column
apps/desktop2/src/components/main/body/contacts/organizations.tsx
Moved organization UI state internal, added useSortedOrganizationIds, introduced OrganizationItem and EditOrganizationForm keyed by organizationId, and switched to id-based rendering with ColumnHeader sorting/add controls.
Contacts — People column
apps/desktop2/src/components/main/body/contacts/people.tsx
Replaced prop-driven people list with useSortedHumanIds(currentOrgId), added PersonItem, internal sort state, ColumnHeader header, and id-based rendering; removed external display/sort/getInitials props.
Contacts — Shared utilities & UI
apps/desktop2/src/components/main/body/contacts/shared.tsx
Added getInitials, SortOption type, SortDropdown, and ColumnHeader components used by people/orgs.
Contacts — index/store integration
apps/desktop2/src/store/tinybase/persisted.ts
Added new TinyBase index sessionsByHuman on mapping_session_participant and exported INDEXES.sessionsByHuman.
Zustand tabs schema
apps/desktop2/src/store/zustand/tabs.ts
Removed contacts-related fields from tab state defaults: editingPerson, editingOrg, showNewOrg, and sortOption.
Sidebar profile styling
apps/desktop2/src/components/main/sidebar/profile/index.tsx, .../profile/shared.tsx
Removed several contact-related state keys in profile init; adjusted styling: switched some text to black, added rounded-lg, changed badge/background/icon colors, simplified label classes.
Sidebar timeline
apps/desktop2/src/components/main/sidebar/timeline.tsx
Defaulted item.data.title to "Untitled" instead of an empty string.
Cursor rules
apps/desktop2/.cursor/rules/correctness.mdc
Added front-matter alwaysApply: true and removed a trailing note line.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ParticipantComp as Participant component
    participant TabsStore as useTabs store
    participant ContactsView as Contacts dialog/view
    participant Persisted as TinyBase persisted store

    User->>ParticipantComp: Click participant row
    ParticipantComp->>TabsStore: openNew({ type: "contacts", selectedPerson: id, selectedOrganization: null, active: true })
    TabsStore-->>ContactsView: open Contacts with selectedHumanId
    ContactsView->>Persisted: query INDEXES.sessionsByHuman for selectedHumanId
    Persisted-->>ContactsView: return mapping ids → sessions
    ContactsView->>TabsStore: openNew({ type: "sessions", raw: sessionState }) on session click
    ContactsView-->>User: render contact details and sessions list
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 2 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The pull request title “Minor fixes 1012” is too generic and does not convey the primary changes or affected areas in the branch, using a non‐descriptive term and a number without context. It fails to summarize the key modifications made to the contacts components and UI updates. Please replace the title with a concise, descriptive summary of the main changes, for example “Refactor contacts view to use zustand tabs and simplify state management.”
Description Check ❓ Inconclusive The pull request description is effectively empty and only notes that no description was provided, offering no information about the scope or purpose of the changes. This absence of detail hinders reviewers from understanding what the PR aims to achieve. Please add a brief summary of the key changes, their intent, and any important context to help reviewers quickly grasp the goals and impact of this pull request.
✨ 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 minor-fixes-1012

📜 Recent 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 19cf339 and 9ce2805.

📒 Files selected for processing (1)
  • apps/desktop2/src/components/main/body/contacts/organizations.tsx (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
apps/desktop2/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/desktop2/.cursor/rules/style.mdc)

apps/desktop2/**/*.{tsx,jsx}: When there are many Tailwind classNames with conditional logic, use the cn utility imported as import { cn } from "@hypr/ui/lib/utils"
Always pass an array to cn when composing Tailwind classNames
Split cn array entries by logical grouping when composing Tailwind classNames

Files:

  • apps/desktop2/src/components/main/body/contacts/organizations.tsx
**/*.{js,ts,tsx,rs}

⚙️ CodeRabbit configuration file

**/*.{js,ts,tsx,rs}: 1. Do not add any error handling. Keep the existing one.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

Files:

  • apps/desktop2/src/components/main/body/contacts/organizations.tsx
🧬 Code graph analysis (1)
apps/desktop2/src/components/main/body/contacts/organizations.tsx (2)
apps/desktop2/src/components/main/body/contacts/shared.tsx (2)
  • ColumnHeader (49-74)
  • SortOption (17-17)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
⏰ 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: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-14)

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

Caution

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

⚠️ Outside diff range comments (1)
apps/desktop2/src/components/main/body/contacts/index.tsx (1)

34-112: Critical: Hooks called after conditional return.

All hooks in the ContactView component are called after the early return at lines 35-36. React requires hooks to be called unconditionally at the top level of the component to maintain consistent ordering across renders.

Move all hooks before the conditional return:

 function ContactView({ tab }: { tab: Tab }) {
-  if (tab.type !== "contacts") {
-    return null;
-  }
-
   const updateContactsTabState = useTabs((state) => state.updateContactsTabState);
   const { openNew } = useTabs();
-
-  const { selectedOrganization, selectedPerson, editingPerson, editingOrg, showNewOrg, sortOption } = tab.state;
-
   const setSelectedOrganization = (value: string | null) => {
     updateContactsTabState(tab, { ...tab.state, selectedOrganization: value });
   };
-
   const setSelectedPerson = (value: string | null) => {
     updateContactsTabState(tab, { ...tab.state, selectedPerson: value });
   };
-
   const setEditingPerson = (value: string | null) => {
     updateContactsTabState(tab, { ...tab.state, editingPerson: value });
   };
-
   const setEditingOrg = (value: string | null) => {
     updateContactsTabState(tab, { ...tab.state, editingOrg: value });
   };
-
   const setShowNewOrg = (value: boolean) => {
     updateContactsTabState(tab, { ...tab.state, showNewOrg: value });
   };
-
   const setSortOption = (value: "alphabetical" | "oldest" | "newest") => {
     updateContactsTabState(tab, { ...tab.state, sortOption: value });
   };
-
   const organizationsData = persisted.UI.useResultTable(persisted.QUERIES.visibleOrganizations, persisted.STORE_ID);
   const humansData = persisted.UI.useResultTable(persisted.QUERIES.visibleHumans, persisted.STORE_ID);
-  const selectedPersonData = persisted.UI.useRow("humans", selectedPerson ?? "", persisted.STORE_ID);
+  const selectedPersonData = persisted.UI.useRow("humans", tab.type === "contacts" ? tab.state.selectedPerson ?? "" : "", persisted.STORE_ID);
   const allSessions = persisted.UI.useTable("sessions", persisted.STORE_ID);
-
-  // Get humans by organization if one is selected
   const humanIdsByOrg = persisted.UI.useSliceRowIds(
     persisted.INDEXES.humansByOrg,
-    selectedOrganization ?? "",
+    tab.type === "contacts" ? tab.state.selectedOrganization ?? "" : "",
     persisted.STORE_ID,
   );
-
   const mappingIdsByHuman = persisted.UI.useSliceRowIds(
     persisted.INDEXES.sessionsByHuman,
-    selectedPerson ?? "",
+    tab.type === "contacts" ? tab.state.selectedPerson ?? "" : "",
     persisted.STORE_ID,
   );
-
   const allMappings = persisted.UI.useTable("mapping_session_participant", persisted.STORE_ID);
-
   const personSessions = useMemo(() => {
     if (!mappingIdsByHuman || mappingIdsByHuman.length === 0) {
       return [];
     }
 
     return mappingIdsByHuman
       .map((mappingId: string) => {
         const mapping = allMappings[mappingId];
         if (!mapping || !mapping.session_id) {
           return null;
         }
 
         const sessionId = mapping.session_id as string;
         const session = allSessions[sessionId];
         if (!session) {
           return null;
         }
 
         return {
           id: sessionId,
           ...session,
         };
       })
       .filter((session: any): session is NonNullable<typeof session> => session !== null);
   }, [mappingIdsByHuman, allMappings, allSessions]);
-
-  console.log("personSessions", personSessions);
+
+  if (tab.type !== "contacts") {
+    return null;
+  }
+
+  const { selectedOrganization, selectedPerson, editingPerson, editingOrg, showNewOrg, sortOption } = tab.state;
 
   // Convert to arrays for rendering
📜 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 0325b62 and ec4a719.

📒 Files selected for processing (2)
  • apps/desktop2/src/components/main/body/contacts/index.tsx (5 hunks)
  • apps/desktop2/src/store/tinybase/persisted.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
apps/desktop2/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop2/.cursor/rules/style.mdc)

apps/desktop2/**/*.{ts,tsx,js,jsx}: Use the cn utility for conditional Tailwind classNames, importing it as: import { cn } from "@hypr/ui/lib/utils"; avoid using clsx/classnames directly.
When calling cn, always pass an array of class segments (e.g., cn(["base", condition && "modifier"]))

Files:

  • apps/desktop2/src/components/main/body/contacts/index.tsx
  • apps/desktop2/src/store/tinybase/persisted.ts
**/*.{js,ts,tsx,rs}

⚙️ CodeRabbit configuration file

**/*.{js,ts,tsx,rs}: 1. Do not add any error handling. Keep the existing one.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

Files:

  • apps/desktop2/src/components/main/body/contacts/index.tsx
  • apps/desktop2/src/store/tinybase/persisted.ts
🧬 Code graph analysis (1)
apps/desktop2/src/components/main/body/contacts/index.tsx (1)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • useTabs (31-121)
🪛 Biome (2.1.2)
apps/desktop2/src/components/main/body/contacts/index.tsx

[error] 40-40: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 71-71: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 80-80: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 86-86: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 88-88: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

⏰ 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: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-14)
🔇 Additional comments (2)
apps/desktop2/src/store/tinybase/persisted.ts (1)

436-436: LGTM!

The new sessionsByHuman index is correctly defined and enables efficient lookup of sessions by participant. The implementation follows the established pattern for index definitions.

Also applies to: 520-520

apps/desktop2/src/components/main/body/contacts/index.tsx (1)

40-40: Confirm session click opens in a new tab
contacts/index.tsx:144 now calls openNew (always new) instead of openCurrent (replace current tab); ensure this aligns with the intended UX.

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

Caution

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

⚠️ Outside diff range comments (1)
apps/desktop2/src/components/main/body/contacts/index.tsx (1)

34-40: Move early return after all hook calls.

All hooks (lines 40, 71, 80, 86, 88) are called after the early return on lines 35-37, which violates the Rules of Hooks. Hooks must be called unconditionally and in the same order on every render.

Move the type guard check to after all hook calls:

 function ContactView({ tab }: { tab: Tab }) {
-  if (tab.type !== "contacts") {
-    return null;
-  }
-
   const updateContactsTabState = useTabs((state) => state.updateContactsTabState);
   const { openNew } = useTabs();
+
+  if (tab.type !== "contacts") {
+    return null;
+  }

Then move all remaining hook calls (lines 68-112) above the type guard as well.

🧹 Nitpick comments (1)
apps/desktop2/src/components/main/body/contacts/index.tsx (1)

88-112: Consider a more specific type annotation.

The memoization logic correctly maps session data through the mapping table and filters out nulls. However, the type annotation on line 111 uses any.

If the session shape is defined elsewhere, consider using it:

-      .filter((session: any): session is NonNullable<typeof session> => session !== null);
+      .filter((session): session is NonNullable<typeof session> => session !== null);

Or define an explicit return type for the useMemo callback.

📜 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 ec4a719 and 9dcd8dc.

📒 Files selected for processing (1)
  • apps/desktop2/src/components/main/body/contacts/index.tsx (5 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
apps/desktop2/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop2/.cursor/rules/style.mdc)

apps/desktop2/**/*.{ts,tsx,js,jsx}: Use the cn utility for conditional Tailwind classNames, importing it as: import { cn } from "@hypr/ui/lib/utils"; avoid using clsx/classnames directly.
When calling cn, always pass an array of class segments (e.g., cn(["base", condition && "modifier"]))

Files:

  • apps/desktop2/src/components/main/body/contacts/index.tsx
**/*.{js,ts,tsx,rs}

⚙️ CodeRabbit configuration file

**/*.{js,ts,tsx,rs}: 1. Do not add any error handling. Keep the existing one.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

Files:

  • apps/desktop2/src/components/main/body/contacts/index.tsx
🧬 Code graph analysis (1)
apps/desktop2/src/components/main/body/contacts/index.tsx (1)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • useTabs (31-121)
🪛 Biome (2.1.2)
apps/desktop2/src/components/main/body/contacts/index.tsx

[error] 40-40: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 71-71: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 80-80: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 86-86: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 88-88: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

⏰ 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: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-14)
🔇 Additional comments (1)
apps/desktop2/src/components/main/body/contacts/index.tsx (1)

142-142: LGTM!

The implementation correctly uses openNew to open the session in a new tab with the raw editor state. This properly replaces the previous debug console.log.

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

Caution

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

⚠️ Outside diff range comments (1)
apps/desktop2/src/components/main/body/contacts/organizations.tsx (1)

15-66: Sorting option is never applied

sortOption/setSortOption are wired into the header, but the list rendering still iterates the raw organizationIds array. Changing the dropdown has no effect, so the sort control is now a dead UI element. Please either drive the query/input that feeds organizationIds with sortOption, or locally reorder the IDs before rendering so the list reflects the selected sort.

📜 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 9dcd8dc and 711b31e.

📒 Files selected for processing (9)
  • apps/desktop2/.cursor/rules/correctness.mdc (1 hunks)
  • apps/desktop2/src/components/main/body/contacts/details.tsx (5 hunks)
  • apps/desktop2/src/components/main/body/contacts/index.tsx (2 hunks)
  • apps/desktop2/src/components/main/body/contacts/organizations.tsx (3 hunks)
  • apps/desktop2/src/components/main/body/contacts/people.tsx (1 hunks)
  • apps/desktop2/src/components/main/body/contacts/shared.tsx (1 hunks)
  • apps/desktop2/src/components/main/body/sessions/outer-header/participant.tsx (3 hunks)
  • apps/desktop2/src/components/main/sidebar/profile/index.tsx (1 hunks)
  • apps/desktop2/src/store/zustand/tabs.ts (0 hunks)
💤 Files with no reviewable changes (1)
  • apps/desktop2/src/store/zustand/tabs.ts
✅ Files skipped from review due to trivial changes (1)
  • apps/desktop2/.cursor/rules/correctness.mdc
🧰 Additional context used
📓 Path-based instructions (2)
apps/desktop2/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/desktop2/.cursor/rules/style.mdc)

apps/desktop2/**/*.{tsx,jsx}: When there are many Tailwind classNames with conditional logic, use the cn utility imported as import { cn } from "@hypr/ui/lib/utils"
Always pass an array to cn when composing Tailwind classNames
Split cn array entries by logical grouping when composing Tailwind classNames

Files:

  • apps/desktop2/src/components/main/body/sessions/outer-header/participant.tsx
  • apps/desktop2/src/components/main/body/contacts/organizations.tsx
  • apps/desktop2/src/components/main/body/contacts/shared.tsx
  • apps/desktop2/src/components/main/sidebar/profile/index.tsx
  • apps/desktop2/src/components/main/body/contacts/people.tsx
  • apps/desktop2/src/components/main/body/contacts/index.tsx
  • apps/desktop2/src/components/main/body/contacts/details.tsx
**/*.{js,ts,tsx,rs}

⚙️ CodeRabbit configuration file

**/*.{js,ts,tsx,rs}: 1. Do not add any error handling. Keep the existing one.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

Files:

  • apps/desktop2/src/components/main/body/sessions/outer-header/participant.tsx
  • apps/desktop2/src/components/main/body/contacts/organizations.tsx
  • apps/desktop2/src/components/main/body/contacts/shared.tsx
  • apps/desktop2/src/components/main/sidebar/profile/index.tsx
  • apps/desktop2/src/components/main/body/contacts/people.tsx
  • apps/desktop2/src/components/main/body/contacts/index.tsx
  • apps/desktop2/src/components/main/body/contacts/details.tsx
🧬 Code graph analysis (4)
apps/desktop2/src/components/main/body/sessions/outer-header/participant.tsx (1)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • useTabs (31-121)
apps/desktop2/src/components/main/body/contacts/organizations.tsx (2)
apps/desktop2/src/components/main/body/contacts/shared.tsx (2)
  • SortOption (17-17)
  • ColumnHeader (49-74)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop2/src/components/main/body/contacts/people.tsx (2)
apps/desktop2/src/components/main/body/contacts/shared.tsx (3)
  • SortOption (17-17)
  • ColumnHeader (49-74)
  • getInitials (5-15)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop2/src/components/main/body/contacts/index.tsx (4)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • useTabs (31-121)
apps/desktop2/src/components/main/body/contacts/organizations.tsx (1)
  • OrganizationsColumn (8-71)
apps/desktop2/src/components/main/body/contacts/people.tsx (1)
  • PeopleColumn (7-50)
apps/desktop2/src/components/main/body/contacts/details.tsx (1)
  • DetailsColumn (10-162)
🪛 Biome (2.1.2)
apps/desktop2/src/components/main/body/contacts/index.tsx

[error] 41-41: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 45-45: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 49-49: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 53-53: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 57-57: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

🔇 Additional comments (1)
apps/desktop2/src/components/main/sidebar/profile/index.tsx (1)

127-127: LGTM! Presentational update aligns with PR objectives.

The styling change from text-slate-900 font-semibold to text-black is a deliberate presentational polish that removes font weight and adjusts color. This aligns with similar updates across the profile UI mentioned in the PR summary.

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

Caution

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

⚠️ Outside diff range comments (1)
apps/desktop2/src/components/main/body/contacts/index.tsx (1)

35-61: Move hooks above the early return; avoid conditional hooks

Hooks are called after an early return, violating rules-of-hooks and flagged by the linter. Also select openNew via a selector to avoid extra re-renders.

 function ContactView({ tab }: { tab: Tab }) {
-  if (tab.type !== "contacts") {
-    return null;
-  }
-
-  const updateContactsTabState = useTabs((state) => state.updateContactsTabState);
-  const { openNew } = useTabs();
+  const updateContactsTabState = useTabs((state) => state.updateContactsTabState);
+  const openNew = useTabs((state) => state.openNew);
+
+  if (tab.type !== "contacts") {
+    return null;
+  }
@@
-  const handleSessionClick = useCallback((id: string) => {
-    openNew({ type: "sessions", id, active: true, state: { editor: "raw" } });
-  }, [openNew]);
+  const handleSessionClick = useCallback(
+    (id: string) => {
+      openNew({ type: "sessions", id, active: true, state: { editor: "raw" } });
+    },
+    [openNew],
+  );

As per coding guidelines

🧹 Nitpick comments (7)
apps/desktop2/src/components/main/body/contacts/shared.tsx (3)

27-33: Fix Select onValueChange typing

Select’s onValueChange typically passes a string. Narrowing the param to SortOption can cause TS incompatibility. Cast inside the handler.

-    <Select
-      value={sortOption}
-      onValueChange={(value: SortOption) => setSortOption(value)}
-    >
+    <Select
+      value={sortOption}
+      onValueChange={(value) => setSortOption(value as SortOption)}
+    >

5-15: Make getInitials resilient to extra whitespace

Trim and split on whitespace; filter empties. Same output, safer for inputs like " Ada Lovelace ".

-export const getInitials = (name?: string | null) => {
+export const getInitials = (name?: string | null) => {
   if (!name) {
     return "?";
   }
-  return name
-    .split(" ")
-    .map(n => n[0])
+  return name
+    .trim()
+    .split(/\s+/)
+    .filter(Boolean)
+    .map((n) => n[0])
     .join("")
     .toUpperCase()
     .slice(0, 2);
 };

49-73: Consider making onAdd optional to hide the Add button when not needed

PeopleColumn currently passes a no-op onAdd. Allow ColumnHeader to omit the Add button unless onAdd is provided.

 export function ColumnHeader({
   title,
   sortOption,
   setSortOption,
   onAdd,
 }: {
   title: string;
   sortOption?: SortOption;
   setSortOption?: (option: SortOption) => void;
-  onAdd: () => void;
+  onAdd?: () => void;
 }) {
   return (
     <div className="px-3 py-2 border-b border-neutral-200 flex items-center justify-between h-12">
       <h3 className="text-xs font-medium text-neutral-600">{title}</h3>
       <div className="flex items-center gap-1">
         {sortOption && setSortOption && <SortDropdown sortOption={sortOption} setSortOption={setSortOption} />}
-        <button
-          onClick={onAdd}
-          className="p-0.5 rounded hover:bg-neutral-100 transition-colors"
-        >
-          <Plus className="h-3 w-3 text-neutral-500" />
-        </button>
+        {onAdd && (
+          <button
+            onClick={onAdd}
+            className="p-0.5 rounded hover:bg-neutral-100 transition-colors"
+          >
+            <Plus className="h-3 w-3 text-neutral-500" />
+          </button>
+        )}
       </div>
     </div>
   );
 }
apps/desktop2/src/components/main/body/contacts/organizations.tsx (1)

112-118: Align edit handler prop with actual usage

The handler ignores the id argument at call site. Simplify type to () => void and call without args.

 function OrganizationItem({
@@
-  handleEditOrganization: (id: string) => void;
+  handleEditOrganization: () => void;
 }) {
@@
-        onClick={(e) => {
+        onClick={(e) => {
           e.stopPropagation();
-          handleEditOrganization(organizationId);
+          handleEditOrganization();
         }}

Also applies to: 136-141

apps/desktop2/src/components/main/body/contacts/people.tsx (2)

20-26: Avoid rendering an inert Add button

onAdd is a no-op; hide the button by omitting onAdd if not used (pairs with making onAdd optional in ColumnHeader).

-      <ColumnHeader
-        title="People"
-        sortOption={sortOption}
-        setSortOption={setSortOption}
-        onAdd={() => {
-        }}
-      />
+      <ColumnHeader
+        title="People"
+        sortOption={sortOption}
+        setSortOption={setSortOption}
+      />

71-88: Optimize filter to O(n) using a Set

includes in a loop is O(n^2). Use a Set for thisOrgHumanIds.

   const thisOrgHumanIds = persisted.UI.useSliceRowIds(
     persisted.INDEXES.humansByOrg,
     currentOrgId ?? "",
     persisted.STORE_ID,
   );
 
-  const humanIds = currentOrgId
-    ? (sortOption === "alphabetical"
-      ? allAlphabeticalIds
-      : sortOption === "newest"
-      ? allNewestIds
-      : allOldestIds).filter((id) => thisOrgHumanIds.includes(id))
-    : (sortOption === "alphabetical"
-      ? allAlphabeticalIds
-      : sortOption === "newest"
-      ? allNewestIds
-      : allOldestIds);
+  const humanIds = currentOrgId
+    ? (() => {
+        const set = new Set(thisOrgHumanIds);
+        const base =
+          sortOption === "alphabetical"
+            ? allAlphabeticalIds
+            : sortOption === "newest"
+            ? allNewestIds
+            : allOldestIds;
+        return base.filter((id) => set.has(id));
+      })()
+    : sortOption === "alphabetical"
+    ? allAlphabeticalIds
+    : sortOption === "newest"
+    ? allNewestIds
+    : allOldestIds;
apps/desktop2/src/components/main/body/contacts/details.tsx (1)

476-492: Remove or implement the “Create” action (currently a no‑op)

The button does nothing; this confuses users. Either wire it to an add‑org callback or hide it until implemented.

-              {organizations.length === 0 && (
-                <button
-                  type="button"
-                  className="flex items-center px-3 py-2 text-sm text-left hover:bg-gray-100 transition-colors w-full"
-                  onClick={() => {}}
-                >
-                  <span className="flex-shrink-0 size-5 flex items-center justify-center mr-2 bg-gray-200 rounded-full">
-                    <span className="text-xs">+</span>
-                  </span>
-                  <span className="flex items-center gap-1 font-medium text-gray-600">
-                    Create
-                    <span className="text-gray-900 truncate max-w-[140px]">
-                      &quot;{searchTerm.trim()}&quot;
-                    </span>
-                  </span>
-                </button>
-              )}
+              {/* Intentionally hide Create action until implemented */}
📜 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 9dcd8dc and 39f770b.

📒 Files selected for processing (9)
  • apps/desktop2/.cursor/rules/correctness.mdc (1 hunks)
  • apps/desktop2/src/components/main/body/contacts/details.tsx (5 hunks)
  • apps/desktop2/src/components/main/body/contacts/index.tsx (2 hunks)
  • apps/desktop2/src/components/main/body/contacts/organizations.tsx (3 hunks)
  • apps/desktop2/src/components/main/body/contacts/people.tsx (1 hunks)
  • apps/desktop2/src/components/main/body/contacts/shared.tsx (1 hunks)
  • apps/desktop2/src/components/main/body/sessions/outer-header/participant.tsx (3 hunks)
  • apps/desktop2/src/components/main/sidebar/profile/index.tsx (1 hunks)
  • apps/desktop2/src/store/zustand/tabs.ts (0 hunks)
💤 Files with no reviewable changes (1)
  • apps/desktop2/src/store/zustand/tabs.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/desktop2/src/components/main/body/sessions/outer-header/participant.tsx
  • apps/desktop2/src/components/main/sidebar/profile/index.tsx
🧰 Additional context used
📓 Path-based instructions (2)
apps/desktop2/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/desktop2/.cursor/rules/style.mdc)

apps/desktop2/**/*.{tsx,jsx}: When there are many Tailwind classNames with conditional logic, use the cn utility imported as import { cn } from "@hypr/ui/lib/utils"
Always pass an array to cn when composing Tailwind classNames
Split cn array entries by logical grouping when composing Tailwind classNames

Files:

  • apps/desktop2/src/components/main/body/contacts/organizations.tsx
  • apps/desktop2/src/components/main/body/contacts/details.tsx
  • apps/desktop2/src/components/main/body/contacts/people.tsx
  • apps/desktop2/src/components/main/body/contacts/index.tsx
  • apps/desktop2/src/components/main/body/contacts/shared.tsx
**/*.{js,ts,tsx,rs}

⚙️ CodeRabbit configuration file

**/*.{js,ts,tsx,rs}: 1. Do not add any error handling. Keep the existing one.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

Files:

  • apps/desktop2/src/components/main/body/contacts/organizations.tsx
  • apps/desktop2/src/components/main/body/contacts/details.tsx
  • apps/desktop2/src/components/main/body/contacts/people.tsx
  • apps/desktop2/src/components/main/body/contacts/index.tsx
  • apps/desktop2/src/components/main/body/contacts/shared.tsx
🧬 Code graph analysis (4)
apps/desktop2/src/components/main/body/contacts/organizations.tsx (2)
apps/desktop2/src/components/main/body/contacts/shared.tsx (2)
  • ColumnHeader (49-74)
  • SortOption (17-17)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop2/src/components/main/body/contacts/people.tsx (1)
apps/desktop2/src/components/main/body/contacts/shared.tsx (3)
  • ColumnHeader (49-74)
  • SortOption (17-17)
  • getInitials (5-15)
apps/desktop2/src/components/main/body/contacts/index.tsx (4)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • useTabs (31-121)
apps/desktop2/src/components/main/body/contacts/organizations.tsx (1)
  • OrganizationsColumn (8-69)
apps/desktop2/src/components/main/body/contacts/people.tsx (1)
  • PeopleColumn (7-41)
apps/desktop2/src/components/main/body/contacts/details.tsx (1)
  • DetailsColumn (10-162)
apps/desktop2/src/components/main/body/contacts/shared.tsx (1)
packages/ui/src/components/ui/select.tsx (5)
  • Select (174-174)
  • SelectTrigger (174-174)
  • SelectValue (174-174)
  • SelectContent (174-174)
  • SelectItem (174-174)
🪛 Biome (2.1.2)
apps/desktop2/src/components/main/body/contacts/index.tsx

[error] 41-41: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 45-45: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 49-49: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 53-53: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 57-57: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

🔇 Additional comments (1)
apps/desktop2/src/components/main/body/contacts/people.tsx (1)

101-125: Guard against missing person row

Directly reading person.name/email may throw if the row is undefined.

 function PersonItem({
@@
 }) {
-  const person = persisted.UI.useRow("humans", humanId, persisted.STORE_ID);
+  const person = persisted.UI.useRow("humans", humanId, persisted.STORE_ID);
+  if (!person) {
+    return null;
+  }
@@
-          {getInitials(person.name || person.email)}
+          {getInitials(person.name || person.email)}
@@
-          {person.name || person.email || "Unnamed"}
+          {person.name || person.email || "Unnamed"}
-          {person.is_user && <span className="text-xs bg-blue-100 text-blue-700 px-1.5 py-0.5 rounded-full">You</span>}
+          {person.is_user && <span className="text-xs bg-blue-100 text-blue-700 px-1.5 py-0.5 rounded-full">You</span>}

Likely an incorrect or invalid review comment.

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

🧹 Nitpick comments (1)
apps/desktop2/src/components/main/body/sessions/outer-header/participant.tsx (1)

8-8: Prefer a selector to avoid unnecessary re-renders.

Destructuring { openNew } = useTabs() subscribes the component to the entire tabs store, causing re-renders whenever any part of the store changes (e.g., currentTab, tabs array). Since the component only needs openNew, use a selector instead.

Based on learnings

Apply this diff to use a selector:

-import { useTabs } from "../../../../../store/zustand/tabs";
+import { useTabs } from "../../../../../store/zustand/tabs";
-  const { openNew } = useTabs();
+  const openNew = useTabs((state) => state.openNew);

Also applies to: 18-18

📜 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 39f770b and 7558301.

📒 Files selected for processing (3)
  • apps/desktop2/src/components/main/body/sessions/outer-header/participant.tsx (3 hunks)
  • apps/desktop2/src/components/main/sidebar/timeline.tsx (1 hunks)
  • apps/desktop2/src/store/tinybase/persisted.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop2/src/store/tinybase/persisted.ts
🧰 Additional context used
📓 Path-based instructions (2)
apps/desktop2/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/desktop2/.cursor/rules/style.mdc)

apps/desktop2/**/*.{tsx,jsx}: When there are many Tailwind classNames with conditional logic, use the cn utility imported as import { cn } from "@hypr/ui/lib/utils"
Always pass an array to cn when composing Tailwind classNames
Split cn array entries by logical grouping when composing Tailwind classNames

Files:

  • apps/desktop2/src/components/main/body/sessions/outer-header/participant.tsx
  • apps/desktop2/src/components/main/sidebar/timeline.tsx
**/*.{js,ts,tsx,rs}

⚙️ CodeRabbit configuration file

**/*.{js,ts,tsx,rs}: 1. Do not add any error handling. Keep the existing one.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

Files:

  • apps/desktop2/src/components/main/body/sessions/outer-header/participant.tsx
  • apps/desktop2/src/components/main/sidebar/timeline.tsx
🧬 Code graph analysis (1)
apps/desktop2/src/components/main/body/sessions/outer-header/participant.tsx (1)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • useTabs (31-121)
⏰ 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: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-14)
🔇 Additional comments (2)
apps/desktop2/src/components/main/sidebar/timeline.tsx (1)

55-55: LGTM! Good UX improvement.

Defaulting to "Untitled" instead of an empty string improves the user experience by ensuring timeline items and newly created sessions always display a meaningful title.

apps/desktop2/src/components/main/body/sessions/outer-header/participant.tsx (1)

197-206: LGTM!

The implementation correctly replaces the console.log with proper navigation logic. Opening a new contacts tab with the selected participant is the right UX pattern, and the state structure matches the expected contacts tab schema.

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

📜 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 7558301 and 19cf339.

📒 Files selected for processing (1)
  • apps/desktop2/src/components/main/body/contacts/organizations.tsx (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
apps/desktop2/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/desktop2/.cursor/rules/style.mdc)

apps/desktop2/**/*.{tsx,jsx}: When there are many Tailwind classNames with conditional logic, use the cn utility imported as import { cn } from "@hypr/ui/lib/utils"
Always pass an array to cn when composing Tailwind classNames
Split cn array entries by logical grouping when composing Tailwind classNames

Files:

  • apps/desktop2/src/components/main/body/contacts/organizations.tsx
**/*.{js,ts,tsx,rs}

⚙️ CodeRabbit configuration file

**/*.{js,ts,tsx,rs}: 1. Do not add any error handling. Keep the existing one.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

Files:

  • apps/desktop2/src/components/main/body/contacts/organizations.tsx
🧬 Code graph analysis (1)
apps/desktop2/src/components/main/body/contacts/organizations.tsx (2)
apps/desktop2/src/components/main/body/contacts/shared.tsx (2)
  • ColumnHeader (49-74)
  • SortOption (17-17)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
⏰ 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: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-14)

@duckduckhero duckduckhero merged commit 4156b12 into main Oct 12, 2025
6 checks passed
@ComputelessComputer ComputelessComputer deleted the minor-fixes-1012 branch December 14, 2025 15:20
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