-
Notifications
You must be signed in to change notification settings - Fork 415
UI enhancements #1595
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UI enhancements #1595
Conversation
ComputelessComputer
commented
Oct 23, 2025
- Improved contact header design
- Enhanced floating button functionality
- Polished metadata chip UI
- Added memo field to humans
- Performed minor UI fixes and improvements
- Refined contact UI
📝 WalkthroughWalkthroughRemoves a monolithic calendar module and splits it into focused calendar subcomponents; updates contacts and organizations to inline editable fields and grid layouts; enriches session metadata, participants UI, and overflow menus; adds a human memo field; minor UI/styling tweaks and a notification ignore-list update. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant TabItem as TabItemCalendar
participant Content as TabContentCalendar
participant Day as TabContentCalendarDay
participant Events as TabContentCalendarDayEvents
participant Sessions as TabContentCalendarDaySessions
participant More as TabContentCalendarDayMore
User->>TabItem: select calendars tab
TabItem->>Content: render calendar content
Content->>Content: compute 6x7 grid & selected calendars
loop per day cell
Content->>Day: render day cell (ids, flags)
Day->>Day: measure height → visible/hidden items
alt visible event
Day->>Events: render event trigger (popover)
User->>Events: open popover → open/create session editor
else visible session
Day->>Sessions: render session trigger
User->>Sessions: open session editor
end
alt hidden items
Day->>More: render "+N more"
User->>More: open popover to list hidden items
end
end
User->>Content: toggle sidebar / navigate months
Content->>Content: update state (selectedCalendars, month)
sequenceDiagram
participant User
participant Participants as MeetingParticipants
participant Store as TinyBase
participant Search as SearchInput
participant Chip as ParticipantChip
User->>Participants: view participants
Participants->>Store: fetch & enrich participants
User->>Search: type query
Search->>Store: query humans
Store-->>Search: results
User->>Search: select result
Search->>Participants: create mapping to add participant
Participants->>Participants: re-render chips
User->>Chip: hover → HoverCard shows details
User->>Chip: remove → delete mapping
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx (1)
87-87: Add accessible label to folder icon.The icon lacks an accessible label, making it unclear to screen reader users what it represents.
Apply this diff to improve accessibility:
- <FolderIcon /> + <FolderIcon className="mr-2 h-4 w-4" aria-hidden="true" />Note: Icons used decoratively alongside text should have
aria-hidden="true"since the adjacent text already conveys the meaning.apps/desktop/src/components/main/body/sessions/outer-header/metadata/index.tsx (1)
36-46: Replace invalid Tailwind class "max-w-28" with valid alternative.The max-w-28 utility does not exist in Tailwind's default max-width utilities. Use
max-w-md(28rem),max-w-[7rem], or another valid option from the available utilities.Line 37:
className="max-w-28 text-neutral-700"apps/desktop/src/components/main/body/contacts/details.tsx (2)
340-357: Use a real button for the Popover trigger (keyboard/a11y).A div as an interactive trigger isn’t keyboard-focusable by default. Switch to a button to fix a11y and follow semantics.
- <div className="inline-flex items-center cursor-pointer hover:bg-neutral-50 py-1 rounded-lg transition-colors"> + <button + type="button" + className="inline-flex items-center hover:bg-neutral-50 py-1 rounded-lg transition-colors" + aria-label="Select organization" + > ... - : <span className="text-neutral-400 text-base">Select organization</span>} - </div> + : <span className="text-neutral-400 text-base">Select organization</span>} + </button>
438-454: “Create” row is a no-op; hide or implement to avoid dead UI.The button renders but
onClick={() => {}}does nothing. Either wire it or hide/disable it until ready.Example minimal guard:
- {organizations.length === 0 && ( + {organizations.length === 0 && searchTerm.trim() && ( <button type="button" - className="flex items-center px-3 py-2 text-sm text-left hover:bg-neutral-100 transition-colors w-full" - onClick={() => {}} + className="flex items-center px-3 py-2 text-sm text-left hover:bg-neutral-100 transition-colors w-full disabled:opacity-50 disabled:cursor-not-allowed" + onClick={/* TODO: implement create org */} + disabled >
🧹 Nitpick comments (18)
plugins/notification/src/handler.rs (1)
111-111: LGTM – Appropriate addition to the ignore list.Adding GarageBand to the mic-start ignore list makes sense, as it's a music production application that legitimately uses the microphone for recording and music creation, similar to other creative tools already in the list (e.g., Descript, Loom, OBS Studio).
Optional: Consider externalizing the ignore list.
The hardcoded list now contains 12+ app identifiers and continues to grow. Consider moving this to a configuration file or constant to improve maintainability and allow easier updates without code changes.
Note: Change unrelated to PR objectives.
The PR description focuses on "UI enhancements" (calendar, contacts, metadata UI), but this change modifies notification handling logic. While the change itself is sound, it appears unrelated to the stated PR objectives.
apps/desktop/src/components/main/body/sessions/floating/shared.tsx (1)
37-41: Consider edge case handling for robustness.The core formatting logic is correct. However, consider adding defensive checks for edge cases to prevent unexpected output:
Apply this diff to handle edge cases:
export function formatTime(seconds: number): string { + if (!Number.isFinite(seconds) || seconds < 0) { + return "00:00"; + } const mins = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`; }Additionally, consider adding JSDoc documentation since this is an exported utility function:
/** * Formats seconds into MM:SS string format. * @param seconds - The number of seconds to format (must be non-negative and finite) * @returns A string in MM:SS format (e.g., "03:45") */ export function formatTime(seconds: number): string { // ... }apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx (2)
66-66: Improve type safety for folders parameter.The
anytype reduces TypeScript's ability to catch errors. Based on usage (line 84 accessesfolder.name), define a proper interface for the folder object.Apply this diff to add proper typing:
+interface Folder { + name: string; + // Add other known properties +} + function SearchableFolderContent({ folders, onSelectFolder, setOpen }: { - folders: Record<string, any>; + folders: Record<string, Folder>; onSelectFolder: (folderId: string) => void; setOpen?: (open: boolean) => void; }) {
39-39: Consider extracting duplicate empty state message.The "No folders available" message appears identically on lines 39 and 60. While the duplication is minimal, extracting it to a constant would improve maintainability if the message or styling needs to change.
Example refactor:
const EmptyFoldersMessage = () => ( <div className="py-6 text-center text-sm text-muted-foreground"> No folders available </div> ); // Then use: <EmptyFoldersMessage />Also applies to: 60-60
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
34-35: Remove unnecessary type assertions.The type assertions
as string | null | undefinedon lines 34-35 are unnecessary sincelocationanddescriptionare already declared with the same type in theMeetingMetadatainterface. The type assertions may also hide potential type mismatches.Apply this diff to remove the unnecessary type assertions:
return { tood: eventNote ?? "", meeting_link: meetingLink, title, started_at: startedAt, ended_at: endedAt, - location: location as string | null | undefined, - description: description as string | null | undefined, + location, + description, };apps/desktop/src/components/main/body/calendars/calendar-day.tsx (1)
107-124: Improve Tailwind className grouping withcn.Per coding guidelines, when using
cnfor Tailwind classNames, group classes by logical sections within the array items. The current implementation could be more readable with better grouping.As per coding guidelines.
Consider this improved grouping:
<div className={cn( - ["text-sm size-6 rounded-full flex items-center justify-center mb-1", isToday && "bg-red-500"], + [ + // Layout & sizing + "size-6 rounded-full flex items-center justify-center mb-1", + // Typography + "text-sm", + // Conditional background + isToday && "bg-red-500", + ], )} > <span className={cn( [ + // Conditional text colors based on date state isToday && "text-white font-medium", !isToday && !isCurrentMonth && "text-neutral-400", !isToday && isCurrentMonth && isWeekend && "text-neutral-500", !isToday && isCurrentMonth && !isWeekend && "text-neutral-700", ], )} >apps/desktop/src/components/main/body/sessions/outer-header/metadata/others.tsx (1)
129-134: Implement participant sorting by attendance.The TODO comment indicates that participant sorting based on attendance is not yet implemented. The current implementation returns unsorted participants (sort function returns 0 for all comparisons).
Do you want me to generate an implementation that sorts participants by attendance status, or open a new issue to track this task?
apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx (2)
33-47: Keep selected calendars in sync with store changes.Initializing Set once from calendarIds leaves out calendars added later (or keeps removed ones). Sync via effect.
-const [selectedCalendars, setSelectedCalendars] = useState<Set<string>>(() => new Set(calendarIds)); +const [selectedCalendars, setSelectedCalendars] = useState<Set<string>>(() => new Set(calendarIds)); +useEffect(() => { + setSelectedCalendars(prev => { + const next = new Set<string>(); + // keep only existing ids, add any new ones by default (or choose your policy) + calendarIds.forEach(id => next.add(prev.has(id) ? id : id)); + return next; + }); +}, [calendarIds]);
136-149: Minor: extract static week labels to a module constant.Avoid re-allocating the array each render and makes it easier to localize later.
apps/desktop/src/components/main/body/calendars/day-events.tsx (1)
73-85: Consider creating/linking a session to the event when none exists.openNew creates a note UI, but no mapping to this event is recorded here. If you intend to relate them, insert a mapping row (e.g., mapping_event_session) before opening.
apps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsx (2)
210-215: Search predicate admits rows with neither name nor email; tighten matching.Current condition can include entries lacking both fields. Use a clear OR match.
- if ( - name && !name.toLowerCase().includes(normalizedQuery) - && (!email || !email.toLowerCase().includes(normalizedQuery)) - ) { - return; - } + const matchesName = name?.toLowerCase().includes(normalizedQuery) ?? false; + const matchesEmail = email?.toLowerCase().includes(normalizedQuery) ?? false; + if (!matchesName && !matchesEmail) return;
320-353: Avoid document.getElementById and duplicate input IDs; use a ref.Multiple instances will share id="participant-search-input". Prefer a ref for focusing, and make the id unique if needed.
- <div + const inputRef = useRef<HTMLInputElement>(null); + <div className={cn( "flex flex-wrap items-center w-full px-2 py-1.5 gap-1.5 rounded bg-neutral-50 border border-neutral-200 focus-within:border-neutral-300 min-h-[36px]", isFocused && "border-neutral-300", )} - onClick={() => document.getElementById("participant-search-input")?.focus()} + onClick={() => inputRef.current?.focus()} > ... - <input - id="participant-search-input" + <input + id={`participant-search-input-${sessionId}`} + ref={inputRef} type="text"apps/desktop/src/components/main/body/contacts/details.tsx (4)
264-289: Clarify LinkedIn field semantics (username vs full URL).Field key is
linkedin_usernamebut placeholder suggests a full URL. This mismatch can break lateropenUrl(). Decide on one:
- Store a URL (preferred), or
- Store a username and normalize to a URL on use.
Would you like me to patch both the input help text and the open handler to normalize values?
383-385: Null‑guard org names in filter to avoid crashes.If an org lacks
name,.toLowerCase()throws.- const organizations = searchTerm.trim() - ? allOrganizations.filter((org: any) => org.name.toLowerCase().includes(searchTerm.toLowerCase())) + const organizations = searchTerm.trim() + ? allOrganizations.filter((org: any) => + (org.name ?? "").toLowerCase().includes(searchTerm.toLowerCase()) + ) : allOrganizations;
190-197: Normalize single‑line inputs (trim).Trim leading/trailing spaces for name, job title, email, and LinkedIn. Don’t trim memo.
- (e: React.ChangeEvent<HTMLInputElement>) => e.target.value, + (e: React.ChangeEvent<HTMLInputElement>) => e.target.value.trim(),Apply the above to the handlers for
name,job_title,linkedin_username.Also applies to: 212-219, 239-246, 267-274
134-136: Optional: consistent date format.For reliability across locales, consider a fixed format (e.g.,
toLocaleDateString(undefined, { year:'numeric', month:'short', day:'numeric' })) or a shared formatter.apps/desktop/src/components/main/body/contacts/organization-details.tsx (2)
75-76: Clarify casting precedence for initials.Parenthesize to avoid misreading and make TS intent explicit.
- {getInitials(human.name as string || human.email as string)} + {getInitials((human.name as string) || (human.email as string))}
59-59: Optional: responsive grid.Scale columns with viewport for better density.
- <div className="grid grid-cols-3 gap-4"> + <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (27)
apps/desktop/src/components/main/body/calendars.tsx(0 hunks)apps/desktop/src/components/main/body/calendars/calendar-checkbox-row.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/calendar-day.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-events.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-more.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-sessions.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/index.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/tab-item-calendar.tsx(1 hunks)apps/desktop/src/components/main/body/contacts/details.tsx(9 hunks)apps/desktop/src/components/main/body/contacts/index.tsx(1 hunks)apps/desktop/src/components/main/body/contacts/organization-details.tsx(4 hunks)apps/desktop/src/components/main/body/contacts/organizations.tsx(1 hunks)apps/desktop/src/components/main/body/contacts/shared.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/floating/shared.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/index.tsx(3 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx(2 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/others.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts(3 hunks)apps/desktop/src/components/main/body/sessions/outer-header/share.tsx(2 hunks)apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx(1 hunks)apps/desktop/src/store/tinybase/persisted.ts(2 hunks)plugins/notification/src/handler.rs(1 hunks)
💤 Files with no reviewable changes (1)
- apps/desktop/src/components/main/body/calendars.tsx
🧰 Additional context used
📓 Path-based instructions (1)
apps/desktop/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (apps/desktop/.cursor/rules/style.mdc)
apps/desktop/**/*.{tsx,jsx}: When there are many Tailwind classNames with conditional logic, use the utilitycnimported asimport { cn } from "@hypr/utils"
When usingcnfor Tailwind classNames, always pass an array
Group Tailwind classNames by logical sections when usingcn(split array items by grouping)
Files:
apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsxapps/desktop/src/components/main/body/contacts/index.tsxapps/desktop/src/components/main/body/calendars/tab-item-calendar.tsxapps/desktop/src/components/main/body/calendars/tab-content-calendar.tsxapps/desktop/src/components/main/body/contacts/shared.tsxapps/desktop/src/components/main/body/calendars/day-events.tsxapps/desktop/src/components/main/body/contacts/details.tsxapps/desktop/src/components/main/body/calendars/day-more.tsxapps/desktop/src/components/main/body/calendars/calendar-day.tsxapps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsxapps/desktop/src/components/main/body/calendars/index.tsxapps/desktop/src/components/main/body/contacts/organization-details.tsxapps/desktop/src/components/main/body/calendars/day-sessions.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/index.tsxapps/desktop/src/components/main/body/sessions/floating/shared.tsxapps/desktop/src/components/main/body/contacts/organizations.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsxapps/desktop/src/components/main/body/calendars/calendar-checkbox-row.tsxapps/desktop/src/components/main/body/sessions/outer-header/share.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/others.tsx
🧬 Code graph analysis (14)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx (1)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
useMeetingMetadata(13-37)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (1)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
useMeetingMetadata(13-37)
apps/desktop/src/components/main/body/calendars/tab-item-calendar.tsx (2)
apps/desktop/src/components/main/body/calendars/index.tsx (1)
TabItemCalendar(7-7)apps/desktop/src/components/main/body/shared.tsx (2)
TabItem(26-26)TabItemBase(28-103)
apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx (4)
apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)apps/desktop/src/components/main/body/index.tsx (1)
StandardTabWrapper(272-284)apps/desktop/src/components/main/body/calendars/calendar-checkbox-row.tsx (1)
CalendarCheckboxRow(5-20)apps/desktop/src/components/main/body/calendars/calendar-day.tsx (1)
TabContentCalendarDay(10-144)
apps/desktop/src/components/main/body/calendars/day-events.tsx (2)
apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)packages/utils/src/cn.ts (1)
cn(20-22)
apps/desktop/src/components/main/body/contacts/details.tsx (1)
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
getInitials(7-17)
apps/desktop/src/components/main/body/calendars/day-more.tsx (3)
apps/desktop/src/components/main/body/calendars/day-events.tsx (1)
TabContentCalendarDayEvents(11-89)apps/desktop/src/components/main/body/calendars/day-sessions.tsx (1)
TabContentCalendarDaySessions(8-24)apps/desktop/src/components/main/body/calendars.tsx (1)
TabContentCalendarDayMore(467-502)
apps/desktop/src/components/main/body/calendars/calendar-day.tsx (5)
packages/utils/src/cn.ts (1)
cn(20-22)apps/desktop/src/components/main/body/calendars/day-events.tsx (1)
TabContentCalendarDayEvents(11-89)apps/desktop/src/components/main/body/calendars/day-sessions.tsx (1)
TabContentCalendarDaySessions(8-24)apps/desktop/src/components/main/body/calendars/day-more.tsx (1)
TabContentCalendarDayMore(10-45)apps/desktop/src/components/main/body/calendars.tsx (1)
TabContentCalendarDay(209-322)
apps/desktop/src/components/main/body/contacts/organization-details.tsx (1)
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
getInitials(7-17)
apps/desktop/src/components/main/body/calendars/day-sessions.tsx (2)
apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)apps/desktop/src/components/main/body/calendars.tsx (1)
TabContentCalendarDaySessions(411-465)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/index.tsx (1)
MeetingMetadata(15-91)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/index.tsx (5)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (1)
MeetingLocation(5-20)apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx (1)
MeetingLink(15-54)apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx (1)
MeetingDate(5-13)apps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsx (1)
MeetingParticipants(111-389)apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx (1)
MeetingDescription(3-15)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsx (3)
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
getInitials(7-17)apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)packages/utils/src/cn.ts (1)
cn(20-22)
apps/desktop/src/components/main/body/sessions/outer-header/share.tsx (1)
packages/ui/src/components/ui/popover.tsx (1)
PopoverContent(29-29)
🪛 Biome (2.1.2)
apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx
[error] 29-29: 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] 31-31: 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] 33-33: 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] 35-35: 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). (1)
- GitHub Check: ci (macos, macos-14)
🔇 Additional comments (21)
apps/desktop/src/components/main/body/sessions/floating/shared.tsx (2)
20-21: LGTM! Styling updates are appropriate.The Button styling changes align with the UI enhancement objectives. The single static className doesn't require the
cnutility per coding guidelines (which apply when there are many classNames with conditional logic).
26-31: LGTM! Enhanced visual feedback.The animated ping effect provides better visual feedback than the previous implementation. The nested div structure with absolute positioning is the standard pattern for Tailwind ping animations.
apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx (1)
37-39: LGTM! Clean conditional rendering with proper dropdown closure.The addition of the
setOpenprop ensures the dropdown closes after a folder is selected, improving UX.apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx (2)
8-11: LGTM!The import reordering improves readability without affecting functionality.
25-25: Verify that the negative margin doesn't cause layout issues.The addition of
-ml-2.5(negative left margin) could potentially cause the content to overlap with adjacent elements or break the layout at different viewport sizes. Ensure this adjustment has been tested across various screen sizes and contexts.apps/desktop/src/components/main/body/sessions/outer-header/share.tsx (1)
78-78: LGTM!The addition of
rounded-lgclasses enhances visual consistency across the UI components without affecting functionality.Also applies to: 228-228
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
3-11: LGTM!The export of
MeetingMetadatatype and the addition of optionallocationanddescriptionfields properly extend the metadata schema.apps/desktop/src/store/tinybase/persisted.ts (1)
45-45: LGTM!The addition of the
memofield to both thehumanSchemaandSCHEMA.table.humansfollows the existing pattern for optional fields and is implemented consistently with other optional string fields in the schema.Also applies to: 174-174
apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx (1)
2-2: LGTM!The blank line improves import organization and readability.
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
89-89: Verify that removing text truncation doesn't cause layout issues.The
truncateclass was removed from the column header title, which means long titles will now wrap or potentially overflow instead of being truncated with an ellipsis. Ensure this doesn't break the layout, especially for long organization or contact names.apps/desktop/src/components/main/body/contacts/organizations.tsx (1)
51-56: LGTM!The addition of
truncateto the button text andshrink-0to the icon ensures proper text overflow handling while keeping the icon visible. The use of thecnutility follows the coding guidelines.apps/desktop/src/components/main/body/contacts/index.tsx (1)
132-132: Prop signature verified. TheOrganizationDetailsColumncomponent correctly accepts and handles theonPersonClickprop as an optional callback with signature(personId: string) => void. The component safely invokes it using optional chaining when a person card is clicked, passing the person's ID.apps/desktop/src/components/main/body/calendars/calendar-checkbox-row.tsx (1)
5-20: LGTM!The component is well-structured with proper fallback handling for missing calendar names and correct prop typing.
apps/desktop/src/components/main/body/calendars/tab-item-calendar.tsx (1)
6-28: LGTM!The component correctly implements the
TabIteminterface with proper type extraction and handler forwarding.apps/desktop/src/components/main/body/calendars/day-more.tsx (1)
10-45: LGTM!The component properly handles overflow items with a clean popover UI and correct composition of event and session subcomponents.
apps/desktop/src/components/main/body/sessions/outer-header/metadata/others.tsx (2)
11-21: LGTM on interface refactoring.The decision to make
MeetingParticipantnon-exported and move it to module-internal scope is appropriate, as the type is now encapsulated within this module. The extended fields (job_title, linkedin_username, organization) are properly typed with optional nullable fields.
117-243: Well-structured participant management component.The
ParticipantsSectioncomponent implements comprehensive functionality including:
- Search with keyboard navigation (arrow keys, enter, escape)
- Hover cards with rich participant details
- Inline participant removal
- Backspace to remove last participant
The implementation handles edge cases well and provides good UX.
apps/desktop/src/components/main/body/calendars/index.tsx (1)
1-7: Barrel looks good.Consolidated exports are clear and minimal.
apps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsx (1)
35-63: ParticipantChip onClick is declared but never used.Users can’t open the contact from the chip. Wire the handler to the wrapper.
-<div className="group inline-flex items-center gap-1.5 px-1 py-0.5 bg-neutral-200 rounded-md hover:bg-neutral-200 transition-colors cursor-pointer"> +<div + className="group inline-flex items-center gap-1.5 px-1 py-0.5 bg-neutral-200 rounded-md hover:bg-neutral-200 transition-colors cursor-pointer" + onClick={onClick} +>Likely an incorrect or invalid review comment.
apps/desktop/src/components/main/body/calendars/day-sessions.tsx (2)
1-6: LGTM!Imports are clean and all are used appropriately in the component.
18-23: Nice simplification of the calendar session UI!The refactoring from the Popover-based implementation to a simpler Button component aligns well with the PR's objective of UI enhancements and modularization. The title determination logic correctly prioritizes event titles when available and provides a sensible "Untitled" fallback.
apps/desktop/src/components/main/body/calendars/day-sessions.tsx
Outdated
Show resolved
Hide resolved
apps/desktop/src/components/main/body/contacts/organization-details.tsx
Outdated
Show resolved
Hide resolved
apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx
Show resolved
Hide resolved
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx
Show resolved
Hide resolved
apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx
Show resolved
Hide resolved
There was a problem hiding this 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
♻️ Duplicate comments (1)
apps/desktop/src/components/main/body/contacts/organization-details.tsx (1)
88-100: Handle the promise returned byopenUrl.The
stopPropagation()call correctly prevents event bubbling (addressing a previous concern), but the promise returned byopenUrlat line 95 is not handled. This creates an unhandled promise rejection risk.Apply this diff:
- openUrl(`mailto:${human.email}`); + void openUrl(`mailto:${human.email}`);
🧹 Nitpick comments (8)
apps/desktop/src/components/main/body/contacts/organization-details.tsx (1)
170-190: Consider usingcnutility for improved readability.While the coding guidelines emphasize using
cnfor classNames "with conditional logic" (which doesn't apply here), the long className string at line 187 could benefit from thecnutility for improved readability and maintainability.If you choose to refactor:
- className="border-none shadow-none p-0 h-8 text-lg font-semibold focus-visible:ring-0 focus-visible:ring-offset-0" + className={cn([ + "border-none shadow-none p-0 h-8", + "text-lg font-semibold", + "focus-visible:ring-0 focus-visible:ring-offset-0" + ])}As per coding guidelines
apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx (4)
16-16: Import useEffect for state reconciliation.You’ll need useEffect for the selectedCalendars sync below.
-import { useState } from "react"; +import { useEffect, useState } from "react";
36-40: Reconcile selectedCalendars when calendars are removed.If a calendar is deleted, stale IDs remain selected. Prune on calendarIds change. Decide separately whether to auto-select newly added calendars.
const calendarIds = persisted.UI.useRowIds("calendars", persisted.STORE_ID); const [selectedCalendars, setSelectedCalendars] = useState<Set<string>>(() => new Set(calendarIds)); + + // Keep selection consistent if calendars are removed from the store. + useEffect(() => { + setSelectedCalendars(prev => { + // Remove any IDs no longer present. Do not auto-add new ones. + const next = new Set([...prev].filter(id => calendarIds.includes(id))); + return next; + }); + }, [calendarIds]);Would you prefer auto-selecting newly created calendars? If yes, I can adjust this to only add truly new IDs (and keep user-toggled-off ones off) using a ref to diff previous IDs.
110-117: Add aria-labels to icon-only navigation buttons.Improves screen reader support.
- <Button + <Button variant="outline" size="icon" onClick={handlePreviousMonth} className="shadow-none" + aria-label="Previous month" > <ChevronLeft size={16} /> </Button> @@ - <Button + <Button variant="outline" size="icon" onClick={handleNextMonth} className="shadow-none" + aria-label="Next month" > <ChevronRight size={16} /> </Button>Also applies to: 128-135
80-83: Remove redundant variant condition.Inside the open sidebar, this button is always rendered while sidebarOpen is true.
- <Button size="icon" variant={sidebarOpen ? "default" : "ghost"} onClick={() => setSidebarOpen(false)}> + <Button size="icon" variant="default" onClick={() => setSidebarOpen(false)}>apps/desktop/src/components/main/body/calendars/day-events.tsx (3)
24-25: Avoid subscribing to a “dummy” row if API allows undefined.If persisted.UI.useRow supports an undefined/null id, prefer that to reduce unnecessary subscriptions.
Please confirm the hook signature. If it accepts undefined:
- const linkedSession = persisted.UI.useRow("sessions", linkedSessionId || "dummy", persisted.STORE_ID); + const linkedSession = persisted.UI.useRow("sessions", linkedSessionId, persisted.STORE_ID);If not, consider a dedicated no-op path in the hook to avoid binding to a fake row id.
32-33: crypto.randomUUID environment check.Some Electron/Node targets may lack crypto.randomUUID. Add a safe fallback.
- openNew({ type: "sessions", id: crypto.randomUUID(), state: { editor: "raw" } }); + openNew({ + type: "sessions", + id: (globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(16).slice(2)}`), + state: { editor: "raw" }, + });Confirm minimum Electron/Node versions; if guaranteed, you can keep crypto.randomUUID.
56-64: Add an accessible name to the event trigger.Icon + title is visually clear but add aria-label for SRs.
- <Button + <Button variant="ghost" className={cn( ["w-full justify-start px-1 text-neutral-600 h-6", open && "bg-neutral-100 hover:bg-neutral-100"], )} + aria-label={`Open event: ${title}`} >
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
apps/desktop/src/components/main/body/calendars/calendar-day.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-events.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-sessions.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx(1 hunks)apps/desktop/src/components/main/body/contacts/organization-details.tsx(4 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx(3 hunks)apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx
- apps/desktop/src/components/main/body/calendars/day-sessions.tsx
- apps/desktop/src/components/main/body/calendars/calendar-day.tsx
🧰 Additional context used
📓 Path-based instructions (1)
apps/desktop/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (apps/desktop/.cursor/rules/style.mdc)
apps/desktop/**/*.{tsx,jsx}: When there are many Tailwind classNames with conditional logic, use the utilitycnimported asimport { cn } from "@hypr/utils"
When usingcnfor Tailwind classNames, always pass an array
Group Tailwind classNames by logical sections when usingcn(split array items by grouping)
Files:
apps/desktop/src/components/main/body/calendars/day-events.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsxapps/desktop/src/components/main/body/contacts/organization-details.tsxapps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsxapps/desktop/src/components/main/body/sessions/outer-header/overflow.tsxapps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx
🧬 Code graph analysis (5)
apps/desktop/src/components/main/body/calendars/day-events.tsx (2)
apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)packages/utils/src/cn.ts (1)
cn(20-22)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (1)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
useMeetingMetadata(13-37)
apps/desktop/src/components/main/body/contacts/organization-details.tsx (1)
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
getInitials(7-17)
apps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx (1)
apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx (1)
SearchableFolderSubmenuContent(45-65)
apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx (5)
apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)apps/desktop/src/components/main/body/index.tsx (1)
StandardTabWrapper(272-284)apps/desktop/src/components/main/body/calendars/calendar-checkbox-row.tsx (1)
CalendarCheckboxRow(5-20)packages/utils/src/cn.ts (1)
cn(20-22)apps/desktop/src/components/main/body/calendars/calendar-day.tsx (1)
TabContentCalendarDay(10-143)
⏰ 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). (1)
- GitHub Check: ci (macos, macos-14)
🔇 Additional comments (11)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (2)
5-10: Previous critical issue resolved.The null handling has been properly implemented as suggested in the previous review. The non-null assertion has been removed and optional chaining is now used to safely check for metadata and location, preventing potential runtime errors.
12-19: Clean and well-structured rendering logic.The component properly renders the location with a map pin icon and applies appropriate styling. The
truncateclass prevents text overflow, and the layout is semantic and accessible.apps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx (1)
2-2: LGTM! Controlled dropdown state properly implemented.The changes correctly establish controlled state management for the dropdown menu, enabling it to close after folder selection. The
openstate andsetOpenhandler are properly wired through the component hierarchy:OverflowButton→Folder→SearchableFolderSubmenuContent.Also applies to: 19-19, 22-22, 30-30, 56-56, 63-63
apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx (1)
45-47: LGTM! Previous review feedback addressed.The changes correctly pass
setOpenthrough toSearchableFolderContent, enabling the parent dropdown to close after folder selection. This resolves the UX inconsistency flagged in the previous review where the submenu variant didn't close on selection while the dropdown variant did.Also applies to: 60-62
apps/desktop/src/components/main/body/contacts/organization-details.tsx (5)
4-6: LGTM!The new imports correctly support the enhanced UI features: organization avatar, email/LinkedIn action buttons, and external URL opening.
11-19: LGTM!The new
onPersonClickprop appropriately enables parent components to handle person selection, following standard React callback patterns.
34-51: LGTM! Previous issue resolved.The header section is well-structured, and the optional chaining at line 45 properly guards against
peopleInOrgbeing undefined, resolving the previous critical issue flagged in past reviews.
102-118: LGTM! Previous issues resolved.The LinkedIn button correctly implements all fixes from past reviews:
stopPropagation()prevents event bubbling, thevoidoperator handles the promise, and the URL construction defensively handles both full URLs and username-only formats.
130-155: LGTM!The Danger Zone section appropriately separates the destructive delete action with clear warning UI, and the event handling is defensive with both
preventDefaultandstopPropagation.apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx (1)
24-31: Hooks-order issue resolved.Wrapper + inner component removes conditional hook calls. Good fix.
apps/desktop/src/components/main/body/calendars/day-events.tsx (1)
16-17: Good defensive handling for missing/invalid data.Title fallback and time formatter null/NaN checks prevent crashes; trigger now uses safe title. Nicely done.
Also applies to: 36-51, 63-64
apps/desktop/src/components/main/body/contacts/organization-details.tsx
Outdated
Show resolved
Hide resolved
211459a to
b970ffb
Compare
There was a problem hiding this 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
♻️ Duplicate comments (3)
apps/desktop/src/components/main/body/contacts/organization-details.tsx (1)
93-96: Addvoidprefix to handle the promise consistently.Line 112 correctly uses
void openUrl(href), but line 95 is missing thevoidprefix. This creates an inconsistency and leaves an unhandled promise warning.Apply this diff:
onClick={(e) => { e.stopPropagation(); - openUrl(`mailto:${human.email}`); + void openUrl(`mailto:${human.email}`); }}apps/desktop/src/components/main/body/calendars/day-sessions.tsx (1)
12-12: Good fixes: removed “dummy” fallback and sized icon consistentlyEmpty-string fallback avoids wasted queries; StickyNote size={12} matches surrounding UI. Resolved prior feedback.
Also applies to: 20-20
apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx (1)
24-31: Hooks guard refactor looks correctWrapper returns early; hooks live in TabContentCalendarInner. Fixes Rules of Hooks issue.
🧹 Nitpick comments (7)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx (1)
8-10: Simplify the guard condition for clarity.The guard uses
&&(both fields must be falsy), but sinceuseMeetingMetadatareturnsnullif eitherstartedAtorendedAtis missing, whenmetais non-null, both fields are guaranteed to be present. A simpler check would be more defensive and clearer.Apply this diff to simplify the guard:
- if (!meta?.started_at && !meta?.ended_at) { + if (!meta) { return null; }apps/desktop/src/components/main/body/contacts/organization-details.tsx (2)
75-75: Consider safer type handling for name/email.The type assertion pattern
human.name as string || human.email as stringworks but could be simplified and made more type-safe.Consider this refactor:
- {getInitials(human.name as string || human.email as string)} + {getInitials((human.name || human.email) as string)}Or guard the call:
{getInitials(String(human.name || human.email || ""))}
67-121: Consider adding keyboard navigation support.The person cards use clickable divs without keyboard navigation. Adding
role="button",tabIndex={0}, andonKeyDownhandlers would improve accessibility.Example enhancement:
<div key={humanId} className="p-4 rounded-lg border border-neutral-200 hover:shadow-sm transition-all bg-white cursor-pointer" + role="button" + tabIndex={0} onClick={() => onPersonClick?.(humanId)} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + onPersonClick?.(humanId); + } + }} >apps/desktop/src/components/main/body/calendars/day-sessions.tsx (1)
21-21: Consistent copy suggestion: prefer “Untitled Note”Align with day-events.tsx (“Untitled Note”) for consistency.
- <p className="truncate">{event && eventId ? event.title : session?.title || "Untitled"}</p> + <p className="truncate">{event && eventId ? event.title : session?.title || "Untitled Note"}</p>apps/desktop/src/components/main/body/calendars/calendar-day.tsx (2)
1-1: Parse ISO dates safely to avoid TZ off‑by‑onenew Date("yyyy-MM-dd") is UTC in many engines; use parseISO for stable local-day computations.
-import { cn, format, getDay } from "@hypr/utils"; +import { cn, format, getDay, parseISO } from "@hypr/utils"; @@ - const dayNumber = format(new Date(day), "d"); + const dayNumber = format(parseISO(day), "d"); const isToday = format(new Date(), "yyyy-MM-dd") === day; - const dayOfWeek = getDay(new Date(day)); + const dayOfWeek = getDay(parseISO(day));Also applies to: 46-49
51-73: Recompute layout on container resize, not just window resizeSidebars/panels can change cell height without a window resize. Observe the cell/content with ResizeObserver.
// Measure actual available height and calculate max visible items useEffect(() => { - const measureHeight = () => { + const measureHeight = () => { if (cellRef.current && contentRef.current) { const cellHeight = cellRef.current.clientHeight; const contentTop = contentRef.current.offsetTop; const availableHeight = cellHeight - contentTop; const EVENT_HEIGHT = 20; // height of each event item (h-5) const SPACING = 4; // space-y-1 // Calculate how many items can fit const itemsWithSpacing = Math.floor((availableHeight + SPACING) / (EVENT_HEIGHT + SPACING)); // Reserve space for "+x more" if needed setMaxVisibleItems(Math.max(1, itemsWithSpacing)); } }; measureHeight(); - // Re-measure on window resize - window.addEventListener("resize", measureHeight); - return () => window.removeEventListener("resize", measureHeight); + // Re-measure on window resize and element resize + window.addEventListener("resize", measureHeight); + const ro = new ResizeObserver(() => measureHeight()); + if (cellRef.current) ro.observe(cellRef.current); + if (contentRef.current) ro.observe(contentRef.current); + return () => { + window.removeEventListener("resize", measureHeight); + ro.disconnect(); + }; }, []);apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx (1)
36-39: Keep selectedCalendars in sync when calendars list changesIf calendars are added later, they won’t be auto-selected. Union new IDs to preserve user choices.
const calendarIds = persisted.UI.useRowIds("calendars", persisted.STORE_ID); const [selectedCalendars, setSelectedCalendars] = useState<Set<string>>(() => new Set(calendarIds)); + + // Add newly created calendars to the selection without overwriting user choices. + useEffect(() => { + setSelectedCalendars(prev => { + const next = new Set(prev); + for (const id of calendarIds) next.add(id); + return next; + }); + }, [calendarIds]);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
apps/desktop/src/components/main/body/calendars/calendar-day.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-events.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-sessions.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx(1 hunks)apps/desktop/src/components/main/body/contacts/organization-details.tsx(4 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx(3 hunks)apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx
- apps/desktop/src/components/main/body/calendars/day-events.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx
🧰 Additional context used
📓 Path-based instructions (1)
apps/desktop/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (apps/desktop/.cursor/rules/style.mdc)
apps/desktop/**/*.{tsx,jsx}: When there are many Tailwind classNames with conditional logic, use the utilitycnimported asimport { cn } from "@hypr/utils"
When usingcnfor Tailwind classNames, always pass an array
Group Tailwind classNames by logical sections when usingcn(split array items by grouping)
Files:
apps/desktop/src/components/main/body/calendars/calendar-day.tsxapps/desktop/src/components/main/body/calendars/tab-content-calendar.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsxapps/desktop/src/components/main/body/calendars/day-sessions.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsxapps/desktop/src/components/main/body/contacts/organization-details.tsxapps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx
🧬 Code graph analysis (7)
apps/desktop/src/components/main/body/calendars/calendar-day.tsx (5)
packages/utils/src/cn.ts (1)
cn(20-22)apps/desktop/src/components/main/body/calendars/day-events.tsx (1)
TabContentCalendarDayEvents(11-91)apps/desktop/src/components/main/body/calendars/day-sessions.tsx (1)
TabContentCalendarDaySessions(8-24)apps/desktop/src/components/main/body/calendars/day-more.tsx (1)
TabContentCalendarDayMore(10-45)apps/desktop/src/components/main/body/calendars.tsx (1)
TabContentCalendarDay(209-322)
apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx (4)
apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)apps/desktop/src/components/main/body/index.tsx (1)
StandardTabWrapper(272-284)apps/desktop/src/components/main/body/calendars/calendar-checkbox-row.tsx (1)
CalendarCheckboxRow(5-20)apps/desktop/src/components/main/body/calendars/calendar-day.tsx (1)
TabContentCalendarDay(10-143)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (1)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
useMeetingMetadata(13-37)
apps/desktop/src/components/main/body/calendars/day-sessions.tsx (2)
apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)apps/desktop/src/components/main/body/calendars.tsx (1)
TabContentCalendarDaySessions(411-465)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx (1)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
useMeetingMetadata(13-37)
apps/desktop/src/components/main/body/contacts/organization-details.tsx (1)
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
getInitials(7-17)
apps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx (1)
apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx (1)
SearchableFolderSubmenuContent(45-65)
⏰ 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). (1)
- GitHub Check: ci (macos, macos-14)
🔇 Additional comments (10)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (1)
5-20: Previous null-safety issue successfully resolved.The non-null assertion issue flagged in the previous review has been properly addressed. The code now correctly handles the nullable return from
useMeetingMetadatausing optional chaining on line 8, preventing potential runtime errors when metadata is unavailable.apps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx (2)
2-2: Controlled dropdown pattern implemented correctly.The addition of local state and conversion to a controlled
DropdownMenuis clean and follows React best practices. This enables the dropdown to be closed programmatically after actions like folder selection.Also applies to: 19-22
30-30: Clean prop threading for dropdown control.The
setOpencallback is appropriately threaded through the component hierarchy (Folder→SearchableFolderSubmenuContent), enabling child components to close the dropdown after selection. The optional typing is appropriate and provides flexibility for future use cases.Also applies to: 56-56, 63-63
apps/desktop/src/components/main/body/contacts/organization-details.tsx (7)
1-9: LGTM!All imports are appropriate for the new functionality.
11-28: LGTM!The
onPersonClickprop is correctly typed as optional and properly integrated with the TinyBase store hooks.
35-51: LGTM!The header section correctly guards against undefined
peopleInOrgusing optional chaining, addressing previous review concerns.
53-64: LGTM!The conditional check on line 57 properly guards the
.map()call on line 60, ensuringpeopleInOrgis defined and non-empty.
126-126: LGTM!Clear empty-state message.
130-155: LGTM!The Danger Zone section properly isolates the destructive delete action with appropriate styling, clear warnings, and correct event handling to prevent bubbling.
170-190: LGTM!The editable field component is clean and straightforward. While line 187 has many Tailwind classes, the coding guidelines specify using
cnfor classes "with conditional logic," which is not present here.
apps/desktop/src/components/main/body/calendars/day-sessions.tsx
Outdated
Show resolved
Hide resolved
b970ffb to
87d2b64
Compare
There was a problem hiding this 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
♻️ Duplicate comments (1)
apps/desktop/src/components/main/body/contacts/organization-details.tsx (1)
93-96: Addvoidto handle the promise returned byopenUrl.Line 95 calls
openUrl()without handling the returned promise, while line 112 correctly usesvoid openUrl(...). This inconsistency was flagged in previous reviews.Apply this diff:
onClick={(e) => { e.stopPropagation(); - openUrl(`mailto:${human.email}`); + void openUrl(`mailto:${human.email}`); }}
🧹 Nitpick comments (10)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx (3)
24-26: Refactor guard to enable TypeScript type narrowing.The optional chaining in
!meta?.meeting_linkprevents TypeScript from narrowing the types in subsequent code, forcing non-null assertions later (lines 39, 51).Apply this diff to improve type safety:
- if (!meta?.meeting_link) { + if (!meta || !meta.meeting_link) { return null; }With explicit null checks, TypeScript will correctly narrow both
metaandmeta.meeting_linkto non-null values, eliminating the need for!assertions below.
34-34: Remove redundant condition.The check
meta.meeting_link &&is redundant because the early return at line 24-26 already guaranteesmeta.meeting_linkis truthy at this point.Apply this diff:
- {meta.meeting_link && renderURL(meta.meeting_link)} + {renderURL(meta.meeting_link)}
39-39: Non-null assertions can be avoided.The non-null assertions (
meta.meeting_link!) are safe due to the guard at line 24-26, but are only necessary because TypeScript cannot infer type narrowing from optional chaining. If the guard is refactored as suggested (lines 24-26), these assertions can be removed.After refactoring the guard to use explicit checks, update these lines:
- onClick={() => openUrl(meta.meeting_link!)} + onClick={() => openUrl(meta.meeting_link)}Also applies to: 51-51
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (1)
12-19: Clean rendering implementation.The component structure is well-designed with proper flex layout, icon sizing, and text truncation. The
flex-shrink-0on the icon prevents layout issues, and thetruncateclass handles overflow gracefully.Optionally, you could add
aria-hidden="true"to the icon since it's decorative and the location text provides the semantic meaning:- <MapPinIcon size={16} className="flex-shrink-0 text-neutral-700" /> + <MapPinIcon size={16} className="flex-shrink-0 text-neutral-700" aria-hidden="true" />apps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx (4)
42-54: TODO: Implement copy link functionality.The copy link feature is not yet implemented. This should be tracked and completed.
Do you want me to generate an implementation for the copy link functionality or open a new issue to track this task?
68-80: TODO: Implement export to PDF functionality.The export to PDF feature is not yet implemented. This should be tracked and completed.
Do you want me to generate an implementation for the export to PDF functionality or open a new issue to track this task?
105-120: TODO: Implement delete note functionality.The delete note feature is not yet implemented. This is critical functionality that should be tracked and completed, ideally with a confirmation dialog to prevent accidental deletions.
Do you want me to generate an implementation for the delete note functionality (including confirmation dialog) or open a new issue to track this task?
122-137: TODO: Implement delete recording functionality.The delete recording feature is not yet implemented. This is critical functionality that should be tracked and completed, ideally with a confirmation dialog to prevent accidental deletions.
Do you want me to generate an implementation for the delete recording functionality (including confirmation dialog) or open a new issue to track this task?
apps/desktop/src/components/main/body/contacts/organization-details.tsx (1)
67-71: Consider making person cards keyboard-accessible.The cards use a clickable
divwhich isn't keyboard-navigable. For better accessibility, consider wrapping the card in a button element or addingrole="button",tabIndex={0}, and keyboard event handlers.apps/desktop/src/components/main/body/calendars/day-events.tsx (1)
24-24: Consider using empty string instead of "dummy" for consistency.Line 24 uses
"dummy"as a fallback whenlinkedSessionIdis undefined, which may trigger an unnecessary query for a non-existent row. For consistency with the approach used inday-sessions.tsx(line 12), consider using an empty string fallback instead.Apply this diff for consistency:
- const linkedSession = persisted.UI.useRow("sessions", linkedSessionId || "dummy", persisted.STORE_ID); + const linkedSession = persisted.UI.useRow("sessions", linkedSessionId || "", persisted.STORE_ID);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
apps/desktop/src/components/main/body/calendars/calendar-day.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-events.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-sessions.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx(1 hunks)apps/desktop/src/components/main/body/contacts/organization-details.tsx(4 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx(3 hunks)apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx
🧰 Additional context used
📓 Path-based instructions (1)
apps/desktop/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (apps/desktop/.cursor/rules/style.mdc)
apps/desktop/**/*.{tsx,jsx}: When there are many Tailwind classNames with conditional logic, use the utilitycnimported asimport { cn } from "@hypr/utils"
When usingcnfor Tailwind classNames, always pass an array
Group Tailwind classNames by logical sections when usingcn(split array items by grouping)
Files:
apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsxapps/desktop/src/components/main/body/calendars/calendar-day.tsxapps/desktop/src/components/main/body/calendars/day-sessions.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsxapps/desktop/src/components/main/body/contacts/organization-details.tsxapps/desktop/src/components/main/body/calendars/day-events.tsxapps/desktop/src/components/main/body/calendars/tab-content-calendar.tsxapps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx
🧬 Code graph analysis (8)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (1)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
useMeetingMetadata(13-37)
apps/desktop/src/components/main/body/calendars/calendar-day.tsx (5)
packages/utils/src/cn.ts (1)
cn(20-22)apps/desktop/src/components/main/body/calendars/day-events.tsx (1)
TabContentCalendarDayEvents(11-91)apps/desktop/src/components/main/body/calendars/day-sessions.tsx (1)
TabContentCalendarDaySessions(8-25)apps/desktop/src/components/main/body/calendars/day-more.tsx (1)
TabContentCalendarDayMore(10-45)apps/desktop/src/components/main/body/calendars.tsx (1)
TabContentCalendarDay(209-322)
apps/desktop/src/components/main/body/calendars/day-sessions.tsx (3)
apps/desktop/src/components/main/body/calendars/index.tsx (1)
TabContentCalendarDaySessions(5-5)apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)packages/ui/src/components/ui/button.tsx (1)
Button(53-53)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx (1)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
useMeetingMetadata(13-37)
apps/desktop/src/components/main/body/contacts/organization-details.tsx (1)
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
getInitials(7-17)
apps/desktop/src/components/main/body/calendars/day-events.tsx (2)
apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)packages/utils/src/cn.ts (1)
cn(20-22)
apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx (4)
apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)apps/desktop/src/components/main/body/index.tsx (1)
StandardTabWrapper(272-284)apps/desktop/src/components/main/body/calendars/calendar-checkbox-row.tsx (1)
CalendarCheckboxRow(5-20)apps/desktop/src/components/main/body/calendars/calendar-day.tsx (1)
TabContentCalendarDay(10-143)
apps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx (1)
apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx (1)
SearchableFolderSubmenuContent(45-65)
⏰ 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). (1)
- GitHub Check: ci (macos, macos-14)
🔇 Additional comments (7)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (1)
5-10: Previous critical issue successfully resolved!The non-null assertion and unsafe null handling flagged in the previous review have been properly fixed. The code now safely handles null metadata with optional chaining and no longer uses the dangerous
!operator.apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx (1)
45-47: Previous issue resolved: submenu now closes after folder selection.The addition of the optional
setOpenparameter and its propagation toSearchableFolderContentcorrectly addresses the prior review feedback. When a user selects a folder via the submenu,handleSelectwill invokesetOpen?.(false)(line 74), closing the parent dropdown.Also applies to: 60-62
apps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx (3)
2-2: LGTM: Controlled dropdown state management.Converting to a controlled dropdown with explicit
openstate enables the parent to programmatically close the menu (e.g., after folder selection), which is the correct approach for this use case.Also applies to: 19-19, 22-22
30-30: LGTM: CorrectsetOpenpropagation chain.The threading of
setOpenfrom the parent dropdown throughFoldertoSearchableFolderSubmenuContentis implemented correctly and enables the menu to close after folder selection, maintaining consistent UX.Also applies to: 56-56, 63-63
82-103: Verify if listening toggle should close the dropdown.Unlike folder selection (which now closes the menu via
setOpen), toggling the listening state keeps the dropdown open. This may be intentional to allow users to see the state change, but it creates inconsistent UX compared to other menu actions.If the menu should close after toggling listening, add
setOpen?.(false)after the toggle:-function Listening({ sessionId }: { sessionId: string }) { +function Listening({ sessionId, setOpen }: { sessionId: string; setOpen?: (open: boolean) => void }) { const { stop, isListening } = useListener((state) => ({ stop: state.stop, isListening: state.status === "running_active", })); const startListening = useStartListening(sessionId); const handleToggleListening = () => { if (isListening) { stop(); } else { startListening(); } + setOpen?.(false); };And update the call site:
- <Listening sessionId={sessionId} /> + <Listening sessionId={sessionId} setOpen={setOpen} />apps/desktop/src/components/main/body/contacts/organization-details.tsx (1)
170-189: LGTM!The inline editable field integrates cleanly with the persisted store and handles edge cases properly (fallback to empty string). The styling is appropriate for an inline-edit experience.
apps/desktop/src/components/main/body/calendars/tab-content-calendar.tsx (1)
36-38: Verify behavior when new calendars are added after mount.The
selectedCalendarsstate is initialized with the currentcalendarIdson mount, but the initializer only runs once. If new calendars are added later (causingcalendarIdsto change), they won't be automatically selected.Please verify whether newly added calendars should:
- Option A: Be automatically selected (current behavior may be a bug)
- Option B: Require manual selection (current behavior is correct)
If Option A is desired, consider synchronizing the state when
calendarIdschanges.If automatic selection is desired, you can use an effect to sync new calendars:
useEffect(() => { setSelectedCalendars((prev) => { const next = new Set(prev); calendarIds.forEach((id) => { if (!prev.has(id)) { next.add(id); } }); return next; }); }, [calendarIds]);
87d2b64 to
690dad4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (7)
apps/desktop/src/components/main/body/contacts/organizations.tsx (1)
51-57: Make truncation reliable in flex rowTruncating the button container is brittle. Add min-w-0 to the button and move truncate to the label span to ensure ellipsis with flex.
- className={cn([ - "w-full text-left px-3 py-2 rounded-md text-sm truncate flex items-center gap-2 hover:bg-neutral-100 transition-colors", + className={cn([ + "w-full text-left px-3 py-2 rounded-md text-sm flex items-center gap-2 hover:bg-neutral-100 transition-colors min-w-0", !selectedOrganization && "bg-neutral-100", ])} ... - <User className="h-4 w-4 text-neutral-500 shrink-0" /> - All People + <User className="h-4 w-4 text-neutral-500 shrink-0" /> + <span className="truncate">All People</span>apps/desktop/src/store/tinybase/persisted.ts (1)
45-46: memo field added — confirm query exposure if UI needs itSchema addition looks good. If any UI reads human memos, consider selecting memo in QUERIES.visibleHumans to avoid ad-hoc row reads.
Also applies to: 174-175
apps/desktop/src/components/main/body/calendars/index.tsx (1)
61-75: Keep selected calendars in sync with store changesselectedCalendars is seeded once; new/removed calendars won’t reflect. Reconcile on calendarIds changes.
- const [selectedCalendars, setSelectedCalendars] = useState<Set<string>>(() => new Set(calendarIds)); + const [selectedCalendars, setSelectedCalendars] = useState<Set<string>>( + () => new Set(calendarIds), + ); + useEffect(() => { + setSelectedCalendars((prev) => { + const next = new Set<string>(); + // Keep only ids that still exist + calendarIds.forEach((id) => { + // Auto-add newly discovered calendars by default + next.add(id); + }); + return next; + }); + }, [calendarIds]);apps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsx (1)
321-324: Follow cn array style per repo guidelineUse cn with an array and group logical sections. This keeps consistency with apps/desktop Tailwind conventions. As per coding guidelines.
- className={cn( - "flex flex-wrap ... min-h-[36px]", - isFocused && "border-neutral-300", - )} + className={cn([ + "flex flex-wrap ... min-h-[36px]", + isFocused && "border-neutral-300", + ])} ... - className={cn( - "flex items-center justify-between px-3 py-2 text-sm text-left transition-colors w-full", - selectedIndex === index ? "bg-neutral-200" : "hover:bg-neutral-100", - )} + className={cn([ + "flex items-center justify-between px-3 py-2 text-sm text-left transition-colors w-full", + selectedIndex === index ? "bg-neutral-200" : "hover:bg-neutral-100", + ])}Also applies to: 366-369
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
88-91: Header title truncation removed—verify overflow in small widthsWith h-12, long titles may clip. Parent has min-w-0, but consider responsive truncate to avoid overflow in tight layouts.
- <h3 className="text-sm font-medium">{title}</h3> + <h3 className="text-sm font-medium md:truncate">{title}</h3>apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
34-35: Remove redundant type casting.The explicit
as string | null | undefinedcasts are redundant sinceuseMeetingMetadataalready returnsMeetingMetadata | nulland the interface defines these fields with the same type.Apply this diff:
return { tood: eventNote ?? "", meeting_link: meetingLink, title, started_at: startedAt, ended_at: endedAt, - location: location as string | null | undefined, - description: description as string | null | undefined, + location, + description, };apps/desktop/src/components/main/body/contacts/details.tsx (1)
98-109: AI-generated summary placeholder is well-documented.The placeholder clearly communicates the intended future functionality. Consider tracking this implementation in a TODO or issue.
Would you like me to open an issue to track the implementation of the AI-generated summary feature?
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (27)
apps/desktop/src/components/main/body/calendars.tsx(0 hunks)apps/desktop/src/components/main/body/calendars/calendar-checkbox-row.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/calendar-day.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-events.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-more.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-sessions.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/index.tsx(1 hunks)apps/desktop/src/components/main/body/contacts/details.tsx(9 hunks)apps/desktop/src/components/main/body/contacts/index.tsx(1 hunks)apps/desktop/src/components/main/body/contacts/organization-details.tsx(4 hunks)apps/desktop/src/components/main/body/contacts/organizations.tsx(1 hunks)apps/desktop/src/components/main/body/contacts/shared.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/floating/shared.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/index.tsx(3 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/others.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts(3 hunks)apps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx(3 hunks)apps/desktop/src/components/main/body/sessions/outer-header/share.tsx(2 hunks)apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx(2 hunks)apps/desktop/src/components/settings/calendar.tsx(0 hunks)apps/desktop/src/store/tinybase/persisted.ts(2 hunks)plugins/notification/src/handler.rs(1 hunks)
💤 Files with no reviewable changes (2)
- apps/desktop/src/components/settings/calendar.tsx
- apps/desktop/src/components/main/body/calendars.tsx
🚧 Files skipped from review as they are similar to previous changes (11)
- plugins/notification/src/handler.rs
- apps/desktop/src/components/main/body/sessions/outer-header/share.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx
- apps/desktop/src/components/main/body/calendars/day-sessions.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/metadata/others.tsx
- apps/desktop/src/components/main/body/sessions/floating/shared.tsx
- apps/desktop/src/components/main/body/calendars/calendar-day.tsx
- apps/desktop/src/components/main/body/calendars/day-events.tsx
- apps/desktop/src/components/main/body/calendars/day-more.tsx
🧰 Additional context used
📓 Path-based instructions (1)
apps/desktop/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (apps/desktop/.cursor/rules/style.mdc)
apps/desktop/**/*.{tsx,jsx}: When there are many Tailwind classNames with conditional logic, use the utilitycnimported asimport { cn } from "@hypr/utils"
When usingcnfor Tailwind classNames, always pass an array
Group Tailwind classNames by logical sections when usingcn(split array items by grouping)
Files:
apps/desktop/src/components/main/body/contacts/shared.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsxapps/desktop/src/components/main/body/contacts/organizations.tsxapps/desktop/src/components/main/body/contacts/index.tsxapps/desktop/src/components/main/body/contacts/details.tsxapps/desktop/src/components/main/body/calendars/calendar-checkbox-row.tsxapps/desktop/src/components/main/body/calendars/index.tsxapps/desktop/src/components/main/body/contacts/organization-details.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/index.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsxapps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx
🧬 Code graph analysis (8)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx (1)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
useMeetingMetadata(13-37)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (1)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
useMeetingMetadata(13-37)
apps/desktop/src/components/main/body/contacts/details.tsx (1)
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
getInitials(7-17)
apps/desktop/src/components/main/body/calendars/index.tsx (6)
apps/desktop/src/components/main/body/shared.tsx (2)
TabItem(26-26)TabItemBase(28-103)apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)apps/desktop/src/components/main/body/index.tsx (1)
StandardTabWrapper(272-293)apps/desktop/src/components/main/body/calendars/calendar-checkbox-row.tsx (1)
CalendarCheckboxRow(5-20)packages/utils/src/cn.ts (1)
cn(20-22)apps/desktop/src/components/main/body/calendars/calendar-day.tsx (1)
TabContentCalendarDay(10-143)
apps/desktop/src/components/main/body/contacts/organization-details.tsx (1)
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
getInitials(7-17)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/index.tsx (2)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (1)
MeetingLocation(5-20)apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx (1)
MeetingDescription(3-15)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/index.tsx (1)
MeetingMetadata(15-91)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsx (3)
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
getInitials(7-17)apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)packages/utils/src/cn.ts (1)
cn(20-22)
⏰ 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). (1)
- GitHub Check: ci (macos, macos-14)
🔇 Additional comments (11)
apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx (1)
45-47: Excellent fix! Previous issue resolved with consistent pattern.The changes properly address the previous review comment about the submenu not closing after folder selection. The implementation correctly:
- Accepts the optional
setOpenprop in the function signature- Passes it through to
SearchableFolderContent- Maintains pattern consistency with
SearchableFolderDropdown(lines 37-39)The submenu will now close after folder selection, providing consistent UX across both dropdown and submenu variants.
Also applies to: 60-62
apps/desktop/src/components/main/body/contacts/index.tsx (1)
129-134: Good wiring for per-person selection from org detailsPassing onPersonClick={setSelectedPerson} cleanly switches the right pane to person details. LGTM.
Confirm OrganizationDetailsColumn prop is optional and typed as onPersonClick?: (personId: string) => void.
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (1)
5-20: LGTM! Null handling is correct.The null guard on Line 8 properly prevents runtime errors when metadata is unavailable. The component cleanly renders the location with appropriate styling.
apps/desktop/src/components/main/body/sessions/outer-header/metadata/index.tsx (2)
29-31: Clean conditional rendering logic.Deriving these boolean flags upfront makes the JSX more readable and avoids repeated null checks.
51-54: Correct usage ofcnutility.The
cnutility is properly used with an array to group Tailwind classes, following the coding guidelines.apps/desktop/src/components/main/body/contacts/details.tsx (2)
62-80: Clean header layout with inline editing.The refactor to inline editing with direct persisted data binding improves the UX by removing the separate edit mode. The avatar and initials rendering is well-structured.
291-317: Memo field is properly defined in the schema.Verification confirms the
memofield exists in both the Zod schema (as optional string) and TinyBase schema definitions inapps/desktop/src/store/tinybase/persisted.ts(lines 45, 174). The component's usage is correct.apps/desktop/src/components/main/body/contacts/organization-details.tsx (4)
45-46: Proper null guards applied.The optional chaining and nullish coalescing on
peopleInOrg?.length ?? 0correctly prevent runtime errors when the store value is undefined.
57-127: Grid layout and null handling are well-implemented.The 3-column grid layout provides a clean visual structure, and the consistent null guard on Line 57 prevents crashes. The empty state message is user-friendly.
88-119: Event propagation correctly stopped on action buttons.Both the Mail and LinkedIn buttons properly call
e.stopPropagation()to prevent the parentonPersonClickfrom firing. The LinkedIn URL handling also correctly normalizes the username format.
170-190: Inline editing pattern is consistent.The
EditableOrganizationNameFieldfollows the same pattern as the person detail fields, providing a consistent editing experience across the contacts UI.
apps/desktop/src/components/main/body/calendars/calendar-checkbox-row.tsx
Show resolved
Hide resolved
apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx
Outdated
Show resolved
Hide resolved
apps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsx
Show resolved
Hide resolved
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts
Show resolved
Hide resolved
1dda9b2 to
c56ae7a
Compare
There was a problem hiding this 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 (2)
apps/desktop/src/components/main/body/contacts/details.tsx (1)
319-365: Verify organization selector handles "Create new" action.Lines 438-454 show a "Create" button when no organizations match the search term, but the
onClickhandler is empty (onClick={() => {}}). This means users can see the option but clicking it does nothing.Implement the create functionality or remove the "Create" button to avoid misleading users:
- onClick={() => {}} + onClick={() => { + // TODO: Implement organization creation + // For now, you could create the org and call onChange with the new ID + }}Alternatively, if creation isn't ready yet, remove this button entirely until the functionality is implemented.
apps/desktop/src/components/main/body/sessions/outer-header/metadata/others.tsx (1)
11-105: Significant code duplication with participants.tsx.The
MeetingParticipantinterface andParticipantChipcomponent are nearly identical to those inparticipants.tsx(lines 15-109). This duplication increases maintenance burden and the risk of divergent behavior.Consider extracting the shared types and component to a common module:
// shared-participant-ui.tsx export interface MeetingParticipant { id: string; full_name?: string | null; email?: string | null; job_title?: string | null; linkedin_username?: string | null; organization?: { id: string; name: string; } | null; } export interface ParticipantChipProps { participant: MeetingParticipant; currentUserId?: string; attended?: boolean; onClick?: () => void; onRemove?: () => void; } export function ParticipantChip({ ... }: ParticipantChipProps) { // existing implementation }Then import from both
others.tsxandparticipants.tsx.
♻️ Duplicate comments (3)
apps/desktop/src/components/main/body/calendars/calendar-day.tsx (1)
58-64: Fix EVENT_HEIGHT constant to match actual rendered height.The
EVENT_HEIGHTis set to20, but the actual button components (TabContentCalendarDayEventsandTabContentCalendarDaySessionsin their respective files) use theh-6Tailwind class, which equals 24px. This mismatch will cause incorrect calculation ofmaxVisibleItems, potentially showing the "+X more" indicator prematurely or rendering more items than can fit.Apply this diff to fix the height constant:
- const EVENT_HEIGHT = 20; // height of each event item (h-5) + const EVENT_HEIGHT = 24; // height of each event item (h-6) const SPACING = 4; // space-y-1apps/desktop/src/components/main/body/sessions/outer-header/metadata/others.tsx (1)
38-42: onClick prop not wired to the chip wrapper.The
ParticipantChipreceives anonClickprop but the wrapper div on line 38 never invokes it, making chips non-interactive despite accepting the handler. This is the same issue flagged inparticipants.tsx.Apply this diff to wire the onClick handler:
<HoverCardTrigger asChild> - <div className="group inline-flex items-center gap-1.5 px-1 py-0.5 bg-neutral-200 rounded-md hover:bg-neutral-200 transition-colors cursor-pointer"> + <div + onClick={onClick} + className="group inline-flex items-center gap-1.5 px-1 py-0.5 bg-neutral-200 rounded-md hover:bg-neutral-200 transition-colors cursor-pointer" + >apps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsx (1)
42-63: onClick prop not wired to the chip wrapper.The
ParticipantChipcomponent accepts anonClickprop (line 31) and passes it tohandleParticipantClick(line 332), but the wrapper div on line 42 never invokes it. This makes the chip non-interactive for the intended click action, despite the cursor-pointer styling suggesting it should be clickable.Apply this diff to wire the onClick handler:
<HoverCardTrigger asChild> - <div className="group inline-flex items-center gap-1.5 px-1 py-0.5 bg-neutral-200 rounded-md hover:bg-neutral-200 transition-colors cursor-pointer"> + <div + onClick={onClick} + className="group inline-flex items-center gap-1.5 px-1 py-0.5 bg-neutral-200 rounded-md hover:bg-neutral-200 transition-colors cursor-pointer" + >Note: Ensure the remove button continues to call
stopPropagation()(line 55) to prevent triggering the chip click when removing.
🧹 Nitpick comments (3)
apps/desktop/src/components/main/body/calendars/index.tsx (1)
56-64: Consider syncingselectedCalendarswith new calendars.The
selectedCalendarsstate is initialized once withnew Set(calendarIds), but won't automatically include calendars added after the component mounts. Users would need to manually toggle newly added calendars.Consider using a
useEffectto sync the state when new calendars are added:const [selectedCalendars, setSelectedCalendars] = useState<Set<string>>(() => new Set(calendarIds)); + + useEffect(() => { + setSelectedCalendars(prev => { + const updated = new Set(prev); + calendarIds.forEach(id => updated.add(id)); + return updated; + }); + }, [calendarIds]);This ensures newly created/synced calendars are automatically selected and visible.
apps/desktop/src/components/main/body/contacts/organization-details.tsx (1)
59-59: Consider responsive grid layout.The grid uses a fixed 3-column layout (
grid-cols-3), which may not work well on smaller viewports or when the sidebar is expanded.Consider using responsive grid classes:
- <div className="grid grid-cols-3 gap-4"> + <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">This would adapt the layout to available space, showing 1 column on small screens, 2 on medium, and 3 on large screens.
apps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsx (1)
161-236: Remove unnecessary async modifier from synchronous queryFn.The
queryFnis markedasyncbut performs only synchronous TinyBase store operations. Theasynckeyword adds no value here and may mislead readers into expecting asynchronous behavior.Apply this diff to remove the async modifier:
const participantSearch = useQuery({ enabled: !!store && !!indexes && !!participantSearchQuery.trim(), deps: [store, indexes, participantSearchQuery, sessionId] as const, - queryFn: async (store, indexes, query, sessionId) => { + queryFn: (store, indexes, query, sessionId) => { const results: MeetingParticipant[] = [];
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (27)
apps/desktop/src/components/main/body/calendars.tsx(0 hunks)apps/desktop/src/components/main/body/calendars/calendar-checkbox-row.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/calendar-day.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-events.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-more.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/day-sessions.tsx(1 hunks)apps/desktop/src/components/main/body/calendars/index.tsx(1 hunks)apps/desktop/src/components/main/body/contacts/details.tsx(9 hunks)apps/desktop/src/components/main/body/contacts/index.tsx(1 hunks)apps/desktop/src/components/main/body/contacts/organization-details.tsx(4 hunks)apps/desktop/src/components/main/body/contacts/organizations.tsx(1 hunks)apps/desktop/src/components/main/body/contacts/shared.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/floating/shared.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/index.tsx(3 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/others.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsx(1 hunks)apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts(3 hunks)apps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx(3 hunks)apps/desktop/src/components/main/body/sessions/outer-header/share.tsx(2 hunks)apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx(2 hunks)apps/desktop/src/components/settings/calendar.tsx(0 hunks)apps/desktop/src/store/tinybase/persisted.ts(2 hunks)plugins/notification/src/handler.rs(1 hunks)
💤 Files with no reviewable changes (2)
- apps/desktop/src/components/settings/calendar.tsx
- apps/desktop/src/components/main/body/calendars.tsx
🚧 Files skipped from review as they are similar to previous changes (12)
- plugins/notification/src/handler.rs
- apps/desktop/src/components/main/body/contacts/index.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/share.tsx
- apps/desktop/src/store/tinybase/persisted.ts
- apps/desktop/src/components/main/body/calendars/day-more.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts
- apps/desktop/src/components/main/body/calendars/calendar-checkbox-row.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/overflow.tsx
- apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx
- apps/desktop/src/components/main/body/calendars/day-events.tsx
🧰 Additional context used
📓 Path-based instructions (1)
apps/desktop/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (apps/desktop/.cursor/rules/style.mdc)
apps/desktop/**/*.{tsx,jsx}: When there are many Tailwind classNames with conditional logic, use the utilitycnimported asimport { cn } from "@hypr/utils"
When usingcnfor Tailwind classNames, always pass an array
Group Tailwind classNames by logical sections when usingcn(split array items by grouping)
Files:
apps/desktop/src/components/main/body/contacts/organization-details.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/others.tsxapps/desktop/src/components/main/body/contacts/shared.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/index.tsxapps/desktop/src/components/main/body/sessions/floating/shared.tsxapps/desktop/src/components/main/body/calendars/calendar-day.tsxapps/desktop/src/components/main/body/calendars/day-sessions.tsxapps/desktop/src/components/main/body/contacts/organizations.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsxapps/desktop/src/components/main/body/calendars/index.tsxapps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsxapps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsxapps/desktop/src/components/main/body/contacts/details.tsx
🧬 Code graph analysis (8)
apps/desktop/src/components/main/body/contacts/organization-details.tsx (1)
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
getInitials(7-17)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/index.tsx (4)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (1)
MeetingLocation(5-20)apps/desktop/src/components/main/body/sessions/outer-header/metadata/link.tsx (1)
MeetingLink(15-58)apps/desktop/src/components/main/body/sessions/outer-header/metadata/date.tsx (1)
MeetingDate(5-17)apps/desktop/src/components/main/body/sessions/outer-header/metadata/description.tsx (1)
MeetingDescription(3-15)
apps/desktop/src/components/main/body/calendars/calendar-day.tsx (4)
packages/utils/src/cn.ts (1)
cn(20-22)apps/desktop/src/components/main/body/calendars/day-events.tsx (1)
TabContentCalendarDayEvents(11-91)apps/desktop/src/components/main/body/calendars/day-sessions.tsx (1)
TabContentCalendarDaySessions(8-25)apps/desktop/src/components/main/body/calendars/day-more.tsx (1)
TabContentCalendarDayMore(10-45)
apps/desktop/src/components/main/body/calendars/day-sessions.tsx (1)
apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (1)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/shared.ts (1)
useMeetingMetadata(13-37)
apps/desktop/src/components/main/body/calendars/index.tsx (5)
apps/desktop/src/components/main/body/shared.tsx (2)
TabItem(26-26)TabItemBase(28-103)apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)apps/desktop/src/components/main/body/index.tsx (1)
StandardTabWrapper(272-293)apps/desktop/src/components/main/body/calendars/calendar-checkbox-row.tsx (1)
CalendarCheckboxRow(5-24)apps/desktop/src/components/main/body/calendars/calendar-day.tsx (1)
TabContentCalendarDay(10-143)
apps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsx (3)
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
getInitials(7-17)apps/desktop/src/store/zustand/tabs/index.ts (1)
useTabs(21-30)packages/utils/src/cn.ts (1)
cn(20-22)
apps/desktop/src/components/main/body/contacts/details.tsx (1)
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
getInitials(7-17)
🔇 Additional comments (23)
apps/desktop/src/components/main/body/sessions/outer-header/shared/folder.tsx (1)
45-47: Previous issue successfully resolved!The submenu now correctly accepts and forwards the
setOpenprop toSearchableFolderContent, ensuring the parent menu closes after folder selection. The implementation matches the dropdown variant pattern and maintains consistent UX across both menu types.Also applies to: 60-62
apps/desktop/src/components/main/body/sessions/floating/shared.tsx (3)
20-21: LGTM!The styling enhancements improve the button appearance consistently with the PR's UI polish objectives.
26-31: LGTM! Nice animation enhancement.The two-layer pulsing animation creates a more noticeable visual indicator. The nested
absolute inset-0divs correctly overlap to produce the pulsing effect.
37-41: Verify edge case handling forformatTime.The core logic correctly formats valid positive seconds into MM:SS format. However, consider whether edge cases need handling:
- Negative values would produce unexpected results
NaN,undefined, ornullwould return"NaN:NaN"Infinitywould return"Infinity:NaN"If the function is always called with valid positive numbers (e.g., from a timer), the current implementation is fine. Otherwise, consider adding input validation.
apps/desktop/src/components/main/body/contacts/shared.tsx (1)
89-89: Verify removal oftruncateis intentional.Removing
truncatefrom the title will cause long organization/contact names to wrap or overflow instead of being truncated with an ellipsis. This could impact the layout, especially with lengthy names.Please confirm this change is intentional and that the layout handles long titles appropriately. Consider testing with long organization names to ensure the UI remains usable.
apps/desktop/src/components/main/body/contacts/organizations.tsx (1)
48-57: LGTM! Proper truncation handling.The addition of
truncateto the button andshrink-0to the icon ensures that long labels are properly truncated while keeping the icon visible. This follows Tailwind best practices and the coding guidelines.apps/desktop/src/components/main/body/calendars/day-sessions.tsx (1)
8-24: LGTM! Proper null-safety guards in place.The component correctly guards against missing session data using optional chaining, and the event fetching logic safely handles cases where
event_idis undefined by using the?? ""fallback. The title display logic appropriately cascades through event title, session title, and "Untitled" fallback.apps/desktop/src/components/main/body/calendars/calendar-day.tsx (1)
99-123: LGTM! Proper use ofcnutility.The component correctly uses the
cnutility with arrays and groups Tailwind classes by logical sections (layout, borders, background), which aligns with the coding guidelines for this path pattern.apps/desktop/src/components/main/body/contacts/details.tsx (2)
62-80: LGTM! Clean header layout with inline editing.The header section properly integrates the avatar with the inline editable name field and user badge. The layout is well-structured and guards appropriately check for
selectedPersonDataexistence.
291-317: LGTM! Proper Textarea usage for memo field.The
EditablePersonMemoFieldcorrectly uses the Textarea component from@hypr/uiwith appropriate styling to disable borders and shadows for an inline editing experience. The field properly binds to the persistedmemocell.apps/desktop/src/components/main/body/calendars/index.tsx (1)
162-176: LGTM! Proper use ofcnutility.The weekday header properly uses the
cnutility with an array, grouping classes by logical sections (layout, styling, conditional colors). This follows the coding guidelines.apps/desktop/src/components/main/body/contacts/organization-details.tsx (2)
35-51: LGTM! Clean header with inline editing and proper guards.The header section correctly uses
EditableOrganizationNameFieldfor inline name editing and properly guards the people count with optional chaining (peopleInOrg?.length ?? 0), preventing runtime errors when the data is unavailable.
88-119: LGTM! Proper event handling and URL normalization.The action buttons correctly:
- Stop event propagation with
e.stopPropagation()to prevent triggering the parent card'sonPersonClick- Handle the
openUrlpromise withvoidto avoid unhandled promise warnings- Normalize LinkedIn URLs to handle both full URLs and username-only formats
apps/desktop/src/components/main/body/sessions/outer-header/metadata/others.tsx (1)
177-180: Follow coding guidelines for cn() usage.When using
cnfor Tailwind classNames, always pass an array. The current implementation correctly follows this pattern.Based on coding guidelines.
apps/desktop/src/components/main/body/sessions/outer-header/metadata/location.tsx (2)
5-10: LGTM! Null handling properly implemented.The component correctly handles null metadata by checking
meta?.locationbefore accessing the location property. This addresses the previous review concern about unsafe non-null assertions.
12-19: Clean and accessible UI implementation.The location display with icon and truncation is well-implemented. The flex layout and truncate class ensure the UI degrades gracefully with long location strings.
apps/desktop/src/components/main/body/sessions/outer-header/metadata/index.tsx (3)
29-31: Good use of derived boolean flags.Deriving
hasLocation,hasMeetingLink, andhasDescriptionfrom the metadata makes the conditional rendering logic clearer and more maintainable.
57-86: Conditional rendering structure improves UX.The conditional sections with inline dividers ensure that only relevant metadata is displayed, preventing empty sections and unnecessary dividers. The layout adapts cleanly to available data.
51-54: Proper cn() usage follows coding guidelines.The
cn()utility is correctly invoked with an array, grouping Tailwind classes by logical sections (flex, shadow/size, padding).Based on coding guidelines.
apps/desktop/src/components/main/body/sessions/outer-header/metadata/participants.tsx (4)
321-324: Proper cn() usage follows coding guidelines.The
cn()utility is correctly invoked with an array, and classes are grouped logically (layout, conditional border).Based on coding guidelines.
128-156: Efficient participant data enrichment.The
useMemohook correctly derives participant data from mappings, humans, and organizations tables. The dependency array ensures recomputation only when needed.
238-265: Well-implemented keyboard navigation.The
handleKeyDownfunction provides intuitive keyboard controls: Backspace to remove the last chip, Arrow keys for dropdown navigation, Enter to select, and Escape to dismiss. This enhances accessibility and UX.
289-289: No action needed; review comment is based on incorrect assumptions about application context.This is a Tauri desktop application, not a web browser application. Tauri bundles a controlled Chromium runtime (Windows/macOS) or WebKit (Linux), and
crypto.randomUUID()is fully supported in all modern versions. The TypeScript target is ES2020, which natively supports this API. Browser compatibility concerns about older environments or non-secure origins are not applicable to desktop Tauri applications. The code usescrypto.randomUUID()consistently throughout the codebase without polyfills, confirming it's safe for this platform.Likely an incorrect or invalid review comment.