Skip to content

Conversation

@tomerqodo
Copy link

@tomerqodo tomerqodo commented Jan 22, 2026

Benchmark PR from qodo-benchmark#706

Summary by CodeRabbit

  • New Features

    • Event type booking URLs are now stored and utilized throughout the app for streamlined event management.
  • Style

    • Updated active element colors from blue to black for improved visual consistency across menus and filters.
    • Removed bottom borders from profile headers.
  • Bug Fixes

    • Fixed layout alignment issues in event type details, booking screens, and settings tabs.

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

dhairyashiil and others added 7 commits January 21, 2026 15:42
Addresses Cubic AI review feedback (confidence 9/10): The username was
hardcoded to 'username' but still used by BasicsTab as a fallback for
URL display when bookingUrl is unavailable. This restores the useEffect
that fetches the actual username from CalComAPIService.getUsername().

Co-Authored-By: unknown <>
@coderabbitai
Copy link

coderabbitai bot commented Jan 22, 2026

Walkthrough

This PR introduces a bookingUrl field to event type definitions, enabling direct booking URL usage throughout the application. It removes reliance on CalComAPIService.buildEventTypeLink for URL construction, updating components and handlers accordingly. Concurrent styling updates shift interface colors from blue to black and refine layout alignments across multiple UI components.

Changes

Cohort / File(s) Summary
Color Styling Updates (Blue → Black)
companion/app/(tabs)/(availability)/availability-detail.tsx, companion/app/(tabs)/(bookings)/index.ios.tsx, companion/app/(tabs)/(bookings)/index.tsx, companion/components/Header.tsx
Dropdown triggers, filter labels, and menu icons changed from #007AFF (blue) to #000000 (black) for active/selected states while maintaining gray (#666) for inactive states.
Layout Alignment Adjustments
companion/app/(tabs)/(bookings)/index.tsx, companion/app/(tabs)/(event-types)/event-type-detail.tsx, companion/components/event-type-detail/tabs/AdvancedTab.tsx, companion/components/event-type-detail/tabs/BasicsTab.tsx, companion/components/event-type-detail/tabs/LimitsTab.tsx, companion/components/event-type-detail/tabs/RecurringTab.tsx
Added explicit flexDirection: "row" and alignItems: "center" to SettingRow containers and switch wrappers for consistent vertical alignment and centering.
bookingUrl Field Introduction
companion/services/types/event-types.types.ts, companion/extension/lib/linkedin.ts, companion/extension/entrypoints/content.ts
Added optional bookingUrl?: string field to EventType interface and type definitions across services and extension entry points with supporting comments.
bookingUrl Propagation
companion/app/(tabs)/(event-types)/event-type-detail.tsx, companion/components/event-type-list-item/EventTypeListItem.tsx, companion/components/event-type-list-item/EventTypeListItem.ios.tsx, companion/components/event-type-list-item/EventTypeListItemParts.tsx
Added bookingUrl prop passing through component trees (event type detail, list items, and title components) with optional parameter acceptance.
URL Construction Logic Replacement
companion/app/(tabs)/(event-types)/index.ios.tsx, companion/app/(tabs)/(event-types)/index.tsx, companion/extension/entrypoints/content.ts, companion/extension/lib/linkedin.ts, companion/components/event-type-list-item/EventTypeListItemParts.tsx
Replaced CalComAPIService.buildEventTypeLink calls with direct eventType.bookingUrl usage in copy, share, and preview handlers; added fallback logic for URL parsing and display.
Service API Changes
companion/services/calcom.ts
Removed buildEventTypeLink method and added new getUsername() async method with error handling to CalComAPIService exports.
Border and Visual Cleanup
companion/app/profile-sheet.ios.tsx, companion/app/profile-sheet.tsx
Removed bottom border styling (border-b border-gray-200) from profile header containers while preserving padding and layout.
Extension Background Script
companion/extension/entrypoints/background/index.ts
Added type-checking bypass comment for Safari's browserAction API usage without functional changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A booking URL hops through the code,
From service to component in a steady mode,
Colors shift from blue to black so fine,
Alignments centered, everything in line—
No more building links from parts askew,
Now every booking knows its proper URL! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(companion): event type links for org user' directly addresses the main change: enabling the companion app to properly handle event type booking URLs for organization users by adding a bookingUrl field and updating URL construction logic across multiple components.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (3)
companion/extension/lib/linkedin.ts (1)

109-119: Validate bookingUrl scheme before use.
bookingUrl is now used directly in window.open/clipboard flows. If it ever contains a non-http(s) scheme (e.g., javascript:), it can become a security footgun. Consider whitelisting http/https (and optionally custom-domain logic) before using it.

🔒 Suggested guard for URL scheme
 function buildBookingUrl(eventType: EventType): string {
-  return (
-    eventType.bookingUrl ||
-    `https://cal.com/${eventType.users?.[0]?.username || "user"}/${eventType.slug}`
-  );
+  const bookingUrl = eventType.bookingUrl;
+  if (bookingUrl) {
+    try {
+      const parsed = new URL(bookingUrl);
+      if (parsed.protocol === "http:" || parsed.protocol === "https:") {
+        return bookingUrl;
+      }
+    } catch {
+      // Fall through to default URL
+    }
+  }
+  return `https://cal.com/${eventType.users?.[0]?.username || "user"}/${eventType.slug}`;
 }

Also applies to: 667-671

companion/components/event-type-list-item/EventTypeListItemParts.tsx (1)

7-62: Handle scheme-less bookingUrl in display helper.

new URL(bookingUrl) throws on values like cal.com/org/slug or /org/slug, causing the fallback to return /{username}/{slug} instead of attempting to display the actual bookingUrl. If a scheme-less bookingUrl reaches this function, consider normalizing it with https:// prefix before parsing, or falling back to the raw bookingUrl string for display.

🔧 Suggested normalization approach
 function getDisplayUrl(bookingUrl?: string, username?: string, slug?: string): string {
   if (bookingUrl) {
     try {
+      const normalized =
+        /^https?:\/\//i.test(bookingUrl) ? bookingUrl : `https://${bookingUrl.replace(/^\/+/, "")}`;
+      const url = new URL(normalized);
       // Return domain + pathname (e.g., "i.cal.com/keith/30min")
       return url.hostname + url.pathname;
     } catch {
-      // fallback if URL parsing fails
+      return bookingUrl;
     }
   }
-  return username ? `/${username}/${slug}` : `/${slug}`;
+  return username && slug ? `/${username}/${slug}` : slug ? `/${slug}` : "";
 }
companion/app/(tabs)/(event-types)/index.tsx (1)

40-157: Validate bookingUrl scheme before copy/share/preview operations.

The handlers use bookingUrl directly from the API without validating the scheme. A malformed or non-http(s) URL could fail or expose security issues. Centralize validation using a helper that checks URL format and scheme.

🔧 Suggested fix (centralize validation)
+  const getSafeBookingUrl = (bookingUrl?: string): string | null => {
+    if (!bookingUrl) return null;
+    try {
+      const url = new URL(bookingUrl);
+      if (!["http:", "https:"].includes(url.protocol)) return null;
+      return url.toString();
+    } catch {
+      return null;
+    }
+  };
+
   const handleCopyLink = async (eventType: EventType) => {
-    if (!eventType.bookingUrl) {
+    const safeUrl = getSafeBookingUrl(eventType.bookingUrl);
+    if (!safeUrl) {
       showErrorAlert("Error", "Booking URL not available for this event type.");
       return;
     }
     try {
-      await Clipboard.setStringAsync(eventType.bookingUrl);
+      await Clipboard.setStringAsync(safeUrl);
       showSuccessAlert("Link Copied", "Event type link copied!");
     } catch {
       showErrorAlert("Error", "Failed to copy link. Please try again.");
     }
   };
 
   const _handleShare = async (eventType: EventType) => {
-    if (!eventType.bookingUrl) {
+    const safeUrl = getSafeBookingUrl(eventType.bookingUrl);
+    if (!safeUrl) {
       showErrorAlert("Error", "Booking URL not available for this event type.");
       return;
     }
     try {
       await Share.share({
         message: `Book a meeting: ${eventType.title}`,
-        url: eventType.bookingUrl,
+        url: safeUrl,
       });
     } catch {
       showErrorAlert("Error", "Failed to share link. Please try again.");
     }
   };
 
   const handlePreview = async (eventType: EventType) => {
-    if (!eventType.bookingUrl) {
+    const safeUrl = getSafeBookingUrl(eventType.bookingUrl);
+    if (!safeUrl) {
       showErrorAlert("Error", "Booking URL not available for this event type.");
       return;
     }
     try {
       if (Platform.OS === "web") {
-        window.open(eventType.bookingUrl, "_blank");
+        window.open(safeUrl, "_blank");
       } else {
-        await openInAppBrowser(eventType.bookingUrl, "event type preview");
+        await openInAppBrowser(safeUrl, "event type preview");
       }
     } catch {
       console.error("Failed to open preview");
       showErrorAlert("Error", "Failed to open preview. Please try again.");
     }
   };
🤖 Fix all issues with AI agents
In `@companion/app/`(tabs)/(event-types)/event-type-detail.tsx:
- Around line 180-181: The bookingUrl state is never set from the API payload so
guards always fall back to the default prefix; inside applyEventTypeData,
extract the booking URL (or its components) from the incoming eventType data and
call setBookingUrl(...) with that value (use the same key the API provides on
eventType), ensuring preview/copy and any guards use that populated bookingUrl
instead of defaulting to "cal.com/{username}".

In `@companion/components/event-type-detail/tabs/BasicsTab.tsx`:
- Around line 257-276: The displayed booking URL prefix in BasicsTab.tsx
currently uses url.hostname which drops ports (so http://localhost:3000 becomes
http://localhost); update the logic inside the IIFE that reads props.bookingUrl
to use url.host instead of url.hostname so ports are preserved, keeping the rest
of the logic (pathParts building, prefix construction, fallback to
`cal.com/${props.username}/`) intact and ensuring the returned string uses
`${url.protocol}//${url.host}${prefix}`.

In `@companion/extension/entrypoints/content.ts`:
- Around line 1125-1128: The copy button currently reconstructs the URL from
eventType.users?.[0]?.username and eventType.slug instead of reusing the
already-built bookingUrl; update the copy action (the copy button click handler
/ copy function in content.ts) to use the bookingUrl variable when writing to
the clipboard or setting the copied text so org/custom URLs are preserved,
rather than re-building via username/slug.

In `@companion/services/calcom.ts`:
- Around line 1654-1662: getUsername currently assumes profile.username exists
and can return undefined; modify getUsername to validate profile and
profile.username after calling getUserProfile() and throw a descriptive Error if
username is missing (e.g., "Missing username on user profile") instead of
returning undefined. Reference the getUsername function and the getUserProfile()
call and the profile.username property when adding the guard and error throw so
callers always receive a non-empty string or a clear failure.
🧹 Nitpick comments (2)
companion/components/event-type-detail/tabs/LimitsTab.tsx (1)

125-128: Redundant styling between className and inline style.

The flex-row items-center classes in className already provide flexDirection: "row" and alignItems: "center". The inline style prop duplicates these values. Consider removing the redundant properties from the inline style to keep a single source of truth:

♻️ Suggested fix
       <View
         className={`flex-row items-center pr-4 ${!isLast ? "border-b border-[`#E5E5E5`]" : ""}`}
-        style={{ height: 44, flexDirection: "row", alignItems: "center" }}
+        style={{ height: 44 }}
       >
companion/components/event-type-detail/tabs/RecurringTab.tsx (1)

90-93: Redundant styling between className and inline style.

Similar to LimitsTab.tsx, the flex-row items-center classes already provide flexDirection: "row" and alignItems: "center". Consider removing the duplicates from the inline style:

♻️ Suggested fix
       <View
         className={`flex-row items-center pr-4 ${!isLast ? "border-b border-[`#E5E5E5`]" : ""}`}
-        style={{ minHeight: 44, flexDirection: "row", alignItems: "center" }}
+        style={{ minHeight: 44 }}
       >

Note: Using minHeight here (vs height: 44 in LimitsTab.tsx) is appropriate since SettingRow content here may vary in height.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30371b0 and 4f49041.

📒 Files selected for processing (21)
  • companion/app/(tabs)/(availability)/availability-detail.tsx
  • companion/app/(tabs)/(bookings)/index.ios.tsx
  • companion/app/(tabs)/(bookings)/index.tsx
  • companion/app/(tabs)/(event-types)/event-type-detail.tsx
  • companion/app/(tabs)/(event-types)/index.ios.tsx
  • companion/app/(tabs)/(event-types)/index.tsx
  • companion/app/profile-sheet.ios.tsx
  • companion/app/profile-sheet.tsx
  • companion/components/Header.tsx
  • companion/components/event-type-detail/tabs/AdvancedTab.tsx
  • companion/components/event-type-detail/tabs/BasicsTab.tsx
  • companion/components/event-type-detail/tabs/LimitsTab.tsx
  • companion/components/event-type-detail/tabs/RecurringTab.tsx
  • companion/components/event-type-list-item/EventTypeListItem.ios.tsx
  • companion/components/event-type-list-item/EventTypeListItem.tsx
  • companion/components/event-type-list-item/EventTypeListItemParts.tsx
  • companion/extension/entrypoints/background/index.ts
  • companion/extension/entrypoints/content.ts
  • companion/extension/lib/linkedin.ts
  • companion/services/calcom.ts
  • companion/services/types/event-types.types.ts
🧰 Additional context used
🧬 Code graph analysis (7)
companion/components/event-type-detail/tabs/RecurringTab.tsx (1)
packages/features/calendars/weeklyview/types/state.ts (1)
  • View (7-7)
companion/app/profile-sheet.ios.tsx (1)
packages/features/calendars/weeklyview/types/state.ts (1)
  • View (7-7)
companion/app/profile-sheet.tsx (1)
packages/features/calendars/weeklyview/types/state.ts (1)
  • View (7-7)
companion/components/Header.tsx (1)
companion/components/AppPressable.tsx (1)
  • AppPressable (48-104)
companion/app/(tabs)/(event-types)/index.ios.tsx (3)
companion/utils/alerts.ts (2)
  • showErrorAlert (36-51)
  • showSuccessAlert (67-74)
companion/utils/index.ts (3)
  • showErrorAlert (14-14)
  • showSuccessAlert (14-14)
  • openInAppBrowser (16-16)
companion/services/types/event-types.types.ts (1)
  • EventType (173-284)
companion/app/(tabs)/(event-types)/event-type-detail.tsx (3)
companion/utils/alerts.ts (1)
  • showErrorAlert (36-51)
companion/utils/index.ts (2)
  • showErrorAlert (14-14)
  • openInAppBrowser (16-16)
companion/components/AppPressable.tsx (1)
  • AppPressable (48-104)
companion/app/(tabs)/(event-types)/index.tsx (3)
companion/utils/alerts.ts (2)
  • showErrorAlert (36-51)
  • showSuccessAlert (67-74)
companion/services/types/event-types.types.ts (1)
  • EventType (173-284)
companion/utils/browser.ts (1)
  • openInAppBrowser (44-68)
🔇 Additional comments (25)
companion/components/event-type-detail/tabs/LimitsTab.tsx (1)

143-150: LGTM on Switch alignment fix.

Adding justifyContent: "center" alongside alignSelf: "center" ensures proper vertical centering of the Switch control within its container. This is a reasonable approach for cross-platform consistency.

companion/app/profile-sheet.tsx (1)

127-127: LGTM on border removal.

Removing the bottom border from the profile header aligns with the iOS-specific version and creates a cleaner visual presentation.

companion/app/profile-sheet.ios.tsx (1)

150-150: LGTM on border removal.

Consistent with the change in profile-sheet.tsx, maintaining visual parity across platform-specific implementations.

companion/extension/entrypoints/background/index.ts (1)

278-283: LGTM on lint suppression documentation.

The biome-ignore comment appropriately documents why the any cast is necessary—Safari's browserAction API (Manifest V2) isn't represented in Chrome's type definitions. This is a valid cross-browser compatibility pattern.

companion/services/types/event-types.types.ts (1)

281-283: LGTM on bookingUrl field addition.

The new optional bookingUrl field is properly typed and documented. This enables direct booking URL usage throughout the application, replacing the need for programmatic URL construction via CalComAPIService.buildEventTypeLink.

companion/components/event-type-detail/tabs/RecurringTab.tsx (1)

107-114: LGTM on Switch alignment fix.

Consistent with the LimitsTab.tsx change, ensuring proper vertical centering of the Switch control.

companion/components/Header.tsx (1)

106-114: Consistent active-state styling update.
The black active/selected treatment and trigger layout tweaks look consistent with the broader UI refresh.

Also applies to: 149-154, 171-176, 212-218, 234-240, 256-262, 292-299, 313-320, 336-342, 361-369, 388-394

companion/extension/entrypoints/content.ts (1)

835-837: bookingUrl propagation looks good.
Types and URL construction now consistently prefer bookingUrl with safe fallbacks elsewhere.

Also applies to: 878-879, 894-895, 1081-1086, 1291-1299, 1322-1327, 1585-1586, 1627-1628, 1643-1644, 1829-1832, 1871-1874, 2036-2044

companion/app/(tabs)/(availability)/availability-detail.tsx (1)

85-92: Simple styling update looks good.
Color change is consistent with the new active-state palette.

companion/components/event-type-detail/tabs/AdvancedTab.tsx (1)

140-142: Layout alignment tweaks look solid.
Explicit row alignment/centering should improve cross-platform consistency.

Also applies to: 157-158

companion/components/event-type-list-item/EventTypeListItem.ios.tsx (1)

99-104: bookingUrl propagation on iOS looks good.

Cleanly forwards item.bookingUrl to the title for consistent URL display.

companion/app/(tabs)/(bookings)/index.ios.tsx (1)

63-66: Menu label color update looks good.

Consistent with the black-on-active styling update.

Also applies to: 124-127

companion/app/(tabs)/(bookings)/index.tsx (1)

64-75: Filter trigger layout/text styling update looks good.

Improves alignment while keeping behavior unchanged.

companion/components/event-type-list-item/EventTypeListItem.tsx (1)

50-55: bookingUrl propagation on list item (non‑iOS) looks good.

Keeps URL display logic centralized in the title component.

companion/app/(tabs)/(event-types)/index.tsx (1)

450-453: “New” button alignment tweak looks good.

The inline flex alignment is consistent and harmless.

Also applies to: 516-518

companion/components/event-type-detail/tabs/BasicsTab.tsx (2)

40-40: Optional bookingUrl prop is a safe API extension.


204-210: Row alignment tweak looks good.

companion/app/(tabs)/(event-types)/event-type-detail.tsx (4)

948-962: Preview/copy guards are sensible.


1273-1276: Header trigger alignment looks good.


1430-1430: bookingUrl propagation into BasicsTab is correct.


2339-2350: Hidden switch centering is a nice polish.

companion/app/(tabs)/(event-types)/index.ios.tsx (4)

1-3: Import cleanup aligns with direct bookingUrl usage.

Also applies to: 31-31


113-120: Copy link now correctly guards on bookingUrl.


127-135: Share action uses bookingUrl directly — good.


235-241: Preview action now opens the bookingUrl — good.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +180 to 181
const [bookingUrl, setBookingUrl] = useState<string>("");
const [saving, setSaving] = useState(false);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Populate bookingUrl from API data; otherwise preview/copy always fail.
bookingUrl is initialized but never set from eventType data, so the new guards will always fire and the URL prefix falls back to cal.com/{username}.

🛠️ Suggested fix (add inside applyEventTypeData)
 const applyEventTypeData = useCallback((eventType: EventType) => {
   setEventTypeData(eventType);
+  setBookingUrl(eventType.bookingUrl ?? "");
🤖 Prompt for AI Agents
In `@companion/app/`(tabs)/(event-types)/event-type-detail.tsx around lines 180 -
181, The bookingUrl state is never set from the API payload so guards always
fall back to the default prefix; inside applyEventTypeData, extract the booking
URL (or its components) from the incoming eventType data and call
setBookingUrl(...) with that value (use the same key the API provides on
eventType), ensuring preview/copy and any guards use that populated bookingUrl
instead of defaulting to "cal.com/{username}".

Comment on lines +257 to +276
{(() => {
// Parse bookingUrl to get domain prefix (e.g., "i.cal.com/" or "cal.com/username/")
if (props.bookingUrl) {
try {
const url = new URL(props.bookingUrl);
// Get path without the last segment (slug)
const pathParts = url.pathname.split("/").filter(Boolean);
pathParts.pop(); // Remove slug
// Compute prefix outside try/catch for React Compiler
let prefix = "/";
if (pathParts.length > 0) {
prefix = `/${pathParts.join("/")}/`;
}
return `${url.protocol}//${url.hostname}${prefix}`;
} catch {
// fallback
}
}
return `cal.com/${props.username}/`;
})()}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

node <<'EOF'
// Test URL.hostname vs URL.host behavior
const testUrls = [
  "http://localhost:3000/i/username/",
  "https://cal.com/username/",
  "http://example.com:8080/path/",
  "http://localhost/path/"
];

testUrls.forEach(urlStr => {
  const url = new URL(urlStr);
  console.log(`URL: ${urlStr}`);
  console.log(`  .hostname: ${url.hostname}`);
  console.log(`  .host: ${url.host}`);
  console.log(`  .protocol: ${url.protocol}`);
  console.log("");
});
EOF

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 477


🏁 Script executed:

# Find the file and examine its context
fd "BasicsTab.tsx" --type f

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 143


🏁 Script executed:

# Search for any tests related to booking URL handling
fd "\.test\." --type f | head -20

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 1188


🏁 Script executed:

# Look for other uses of bookingUrl in the codebase
rg "bookingUrl" -A 2 -B 2

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 48236


Preserve ports in the displayed booking URL prefix.

Using url.hostname drops ports (e.g., http://localhost:3000/... renders as http://localhost/...), breaking consistency with the actual booking URL. Switch to url.host to preserve ports.

🛠️ Suggested fix
-                      return `${url.protocol}//${url.hostname}${prefix}`;
+                      return `${url.protocol}//${url.host}${prefix}`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{(() => {
// Parse bookingUrl to get domain prefix (e.g., "i.cal.com/" or "cal.com/username/")
if (props.bookingUrl) {
try {
const url = new URL(props.bookingUrl);
// Get path without the last segment (slug)
const pathParts = url.pathname.split("/").filter(Boolean);
pathParts.pop(); // Remove slug
// Compute prefix outside try/catch for React Compiler
let prefix = "/";
if (pathParts.length > 0) {
prefix = `/${pathParts.join("/")}/`;
}
return `${url.protocol}//${url.hostname}${prefix}`;
} catch {
// fallback
}
}
return `cal.com/${props.username}/`;
})()}
{(() => {
// Parse bookingUrl to get domain prefix (e.g., "i.cal.com/" or "cal.com/username/")
if (props.bookingUrl) {
try {
const url = new URL(props.bookingUrl);
// Get path without the last segment (slug)
const pathParts = url.pathname.split("/").filter(Boolean);
pathParts.pop(); // Remove slug
// Compute prefix outside try/catch for React Compiler
let prefix = "/";
if (pathParts.length > 0) {
prefix = `/${pathParts.join("/")}/`;
}
return `${url.protocol}//${url.host}${prefix}`;
} catch {
// fallback
}
}
return `cal.com/${props.username}/`;
})()}
🤖 Prompt for AI Agents
In `@companion/components/event-type-detail/tabs/BasicsTab.tsx` around lines 257 -
276, The displayed booking URL prefix in BasicsTab.tsx currently uses
url.hostname which drops ports (so http://localhost:3000 becomes
http://localhost); update the logic inside the IIFE that reads props.bookingUrl
to use url.host instead of url.hostname so ports are preserved, keeping the rest
of the logic (pathParts building, prefix construction, fallback to
`cal.com/${props.username}/`) intact and ensuring the returned string uses
`${url.protocol}//${url.host}${prefix}`.

Comment on lines +1125 to +1128
const bookingUrl =
`https://cal.com/${
eventType.users?.[0]?.username || "user"
}/${eventType.slug}`;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use bookingUrl for copy action (currently ignored).
The copy button still constructs the URL from username/slug only, so org/custom URLs won’t be copied even though preview uses bookingUrl.

🛠️ Proposed fix
-const bookingUrl =
-  `https://cal.com/${eventType.users?.[0]?.username || "user"}/${eventType.slug}`;
+const bookingUrl =
+  eventType.bookingUrl ||
+  `https://cal.com/${eventType.users?.[0]?.username || "user"}/${eventType.slug}`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const bookingUrl =
`https://cal.com/${
eventType.users?.[0]?.username || "user"
}/${eventType.slug}`;
const bookingUrl =
eventType.bookingUrl ||
`https://cal.com/${
eventType.users?.[0]?.username || "user"
}/${eventType.slug}`;
🤖 Prompt for AI Agents
In `@companion/extension/entrypoints/content.ts` around lines 1125 - 1128, The
copy button currently reconstructs the URL from eventType.users?.[0]?.username
and eventType.slug instead of reusing the already-built bookingUrl; update the
copy action (the copy button click handler / copy function in content.ts) to use
the bookingUrl variable when writing to the clipboard or setting the copied text
so org/custom URLs are preserved, rather than re-building via username/slug.

Comment on lines +1654 to +1662
// Helper to get username
async function getUsername(): Promise<string> {
try {
const profile = await getUserProfile();
return profile.username;
} catch (error) {
throw new Error("Failed to get username");
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard against missing username before returning.
getUsername() returns Promise<string> but can currently return undefined if the profile lacks a username. This can lead to malformed URLs or runtime surprises.

✅ Suggested fix
 async function getUsername(): Promise<string> {
-  try {
-    const profile = await getUserProfile();
-    return profile.username;
-  } catch (error) {
-    throw new Error("Failed to get username");
-  }
+  const profile = await getUserProfile();
+  if (!profile?.username) {
+    throw new Error("Username missing in profile response");
+  }
+  return profile.username;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Helper to get username
async function getUsername(): Promise<string> {
try {
const profile = await getUserProfile();
return profile.username;
} catch (error) {
throw new Error("Failed to get username");
}
}
async function getUsername(): Promise<string> {
const profile = await getUserProfile();
if (!profile?.username) {
throw new Error("Username missing in profile response");
}
return profile.username;
}
🤖 Prompt for AI Agents
In `@companion/services/calcom.ts` around lines 1654 - 1662, getUsername currently
assumes profile.username exists and can return undefined; modify getUsername to
validate profile and profile.username after calling getUserProfile() and throw a
descriptive Error if username is missing (e.g., "Missing username on user
profile") instead of returning undefined. Reference the getUsername function and
the getUserProfile() call and the profile.username property when adding the
guard and error throw so callers always receive a non-empty string or a clear
failure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants