Skip to content

fix(companion): event type links for org user#5

Open
tomerqodo wants to merge 7 commits intoqodo_full_base_fixcompanion_event_type_links_for_org_user_pr5from
qodo_full_head_fixcompanion_event_type_links_for_org_user_pr5
Open

fix(companion): event type links for org user#5
tomerqodo wants to merge 7 commits intoqodo_full_base_fixcompanion_event_type_links_for_org_user_pr5from
qodo_full_head_fixcompanion_event_type_links_for_org_user_pr5

Conversation

@tomerqodo
Copy link
Copy Markdown

Benchmark PR from agentic-review-benchmarks#5

dhairyashiil and others added 7 commits January 25, 2026 12:01
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 <>
@qodo-code-review
Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (2) 📎 Requirement gaps (0)

Grey Divider


Action required

1. getUsername() throws generic Error 📘 Rule violation ⛯ Reliability
Description
getUsername() catches any failure from getUserProfile() and throws a plain Error with a
  generic message, losing the original cause and any structured context.
• This violates the requirement for hierarchical, typed custom errors with context, and will make
  downstream error handling/debugging inconsistent.
• It also prevents callers from distinguishing auth/network failures vs. unexpected data issues.
Code

companion/services/calcom.ts[R1655-1661]

+async function getUsername(): Promise<string> {
+  try {
+    const profile = await getUserProfile();
+    return profile.username;
+  } catch (error) {
+    throw new Error("Failed to get username");
+  }
Evidence
PR Compliance ID 15 requires custom errors to be structured with typed codes and context; the new
getUsername() implementation throws a generic Error and discards the caught error, providing
no code/status/context.

AGENTS.md
companion/services/calcom.ts[1654-1662]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`getUsername()` throws a generic `Error(&quot;Failed to get username&quot;)` and drops the original exception/context, violating the requirement for hierarchical custom errors with typed codes and structured context.

## Issue Context
This function wraps `getUserProfile()` and is likely used in multiple user-facing flows; without typed codes/context (and ideally `cause`), downstream error handling and debugging becomes unreliable.

## Fix Focus Areas
- companion/services/calcom.ts[1654-1662]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Detail link always missing 🐞 Bug ✓ Correctness
Description
EventTypeDetail now gates Preview/Copy on a local bookingUrl state, but that state is
  initialized to "" and never set from fetched EventType data.
• This causes Preview and Copy Link to always show “Booking URL not available…” even when the event
  type has a valid slug/username.
• Users lose core functionality (preview/copy) in the event type detail screen.
Code

companion/app/(tabs)/(event-types)/event-type-detail.tsx[R949-953]

+    if (!bookingUrl) {
+      showErrorAlert("Error", "Booking URL not available. Please save the event type first.");
      return;
    }
-    await openInAppBrowser(link, "event type preview");
+    await openInAppBrowser(bookingUrl, "event type preview");
Evidence
bookingUrl is created as local state, but it is never populated in applyEventTypeData or
elsewhere; meanwhile Preview/Copy now rely exclusively on that state, so they always fail when it
remains empty.

companion/app/(tabs)/(event-types)/event-type-detail.tsx[174-183]
companion/app/(tabs)/(event-types)/event-type-detail.tsx[948-963]
companion/app/(tabs)/(event-types)/event-type-detail.tsx[451-464]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`EventTypeDetail` uses a local `bookingUrl` state for preview/copy, but it is never set from the fetched event type. This makes preview/copy always fail.

### Issue Context
`CalComAPIService.getEventTypeById(...)` returns an `EventType` object which can contain `bookingUrl` (optional). Even when `bookingUrl` is missing, the screen already has enough info (username + slug) to build a fallback URL.

### Fix Focus Areas
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[174-183]
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[451-470]
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[948-963]

### Suggested approach
- Prefer removing the separate `bookingUrl` state entirely and compute it via `useMemo` from `eventTypeData?.bookingUrl` with a fallback `https://cal.com/${username}/${eventSlug}` when possible.
- If keeping state, set it in `applyEventTypeData` (e.g., `setBookingUrl(eventType.bookingUrl ?? &quot;&quot;)`) and/or add an effect to recompute when `username`/`eventSlug` change.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Extension copies wrong URL 🐞 Bug ✓ Correctness
Description
• In the content script, Preview now uses eventType.bookingUrl || fallback, but the Copy button in
  the same UI still copies only the hardcoded https://cal.com/{username}/{slug}.
• This creates an inconsistent UX (Preview opens one URL, Copy copies another) and breaks copy for
  users on custom booking domains.
• A later section in the same file already uses the correct bookingUrl || fallback for copy,
  suggesting this is an accidental missed update.
Code

companion/extension/entrypoints/content.ts[R1122-1129]

                  copyBtn.addEventListener("click", (e) => {
                    e.stopPropagation();
                    // Copy to clipboard
-                    const bookingUrl = `https://cal.com/${
-                      eventType.users?.[0]?.username || "user"
-                    }/${eventType.slug}`;
+                    const bookingUrl =
+                      `https://cal.com/${
+                        eventType.users?.[0]?.username || "user"
+                      }/${eventType.slug}`;
                    navigator.clipboard
Evidence
The first UI block’s Preview button uses eventType.bookingUrl (with fallback), but its Copy button
ignores eventType.bookingUrl. Later in the file, copy correctly uses `eventType.bookingUrl ||
fallback`, demonstrating intended behavior.

companion/extension/entrypoints/content.ts[1079-1087]
companion/extension/entrypoints/content.ts[1122-1131]
companion/extension/entrypoints/content.ts[1868-1874]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The extension content script’s first event type UI block opens `eventType.bookingUrl` for Preview but copies a hardcoded `https://cal.com/...` URL for Copy. This breaks copying for custom domains and is inconsistent within the same UI.

### Issue Context
A later section in the same file already uses `eventType.bookingUrl || fallback` for copy, so the fix should align the first copy handler.

### Fix Focus Areas
- companion/extension/entrypoints/content.ts[1079-1087]
- companion/extension/entrypoints/content.ts[1122-1131]

### Suggested approach
Change the first copy handler’s `bookingUrl` assignment to:
```ts
const bookingUrl = eventType.bookingUrl || `https://cal.com/${eventType.users?.[0]?.username || &quot;user&quot;}/${eventType.slug}`;
```
so both Preview and Copy use the same source of truth.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. BasicsTab URL parse ignores errors 📘 Rule violation ⛯ Reliability
Description
• The inline booking URL prefix computation in BasicsTab silently ignores URL parsing errors
  (catch {}), which can mask bad bookingUrl values.
• This is a silent failure at a known failure point (new URL(...)), reducing the ability to debug
  edge cases in production.
• Prefer explicit validation and/or internal logging (redacting as needed) when parsing fails, then
  fall back deterministically.
Code

companion/components/event-type-detail/tabs/BasicsTab.tsx[R257-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}/`;
+                })()}
Evidence
PR Compliance ID 3 requires identifying and handling failure points with meaningful context; the
added URL parsing logic catches errors but provides no logging/context, resulting in an ignored
error path.

Rule 3: Generic: Robust Error Handling and Edge Case Management
companion/components/event-type-detail/tabs/BasicsTab.tsx[257-276]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`BasicsTab` parses `props.bookingUrl` with `new URL(...)` but swallows parsing failures without any logging/context, which is a silent failure.

## Issue Context
`bookingUrl` is likely API-provided; parsing failures should be diagnosable (internally) and handled explicitly.

## Fix Focus Areas
- companion/components/event-type-detail/tabs/BasicsTab.tsx[257-276]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Link actions too strict 🐞 Bug ⛯ Reliability
Description
• EventTypes list screens (iOS and cross-platform) now hard-require eventType.bookingUrl and show
  an error when it’s missing.
• bookingUrl is explicitly typed as optional, and other parts of the codebase handle its absence
  via fallback URL construction.
• If the API omits bookingUrl in some responses, share/copy/preview will fail even though the URL
  can be derived from username + slug.
Code

companion/app/(tabs)/(event-types)/index.tsx[R136-142]

+    if (!eventType.bookingUrl) {
+      showErrorAlert("Error", "Booking URL not available for this event type.");
+      return;
+    }
    try {
-      const link = await CalComAPIService.buildEventTypeLink(eventType.slug);
-      await Clipboard.setStringAsync(link);
-
+      await Clipboard.setStringAsync(eventType.bookingUrl);
      showSuccessAlert("Link Copied", "Event type link copied!");
Evidence
The EventTypes screens now bail out when bookingUrl is falsy, but the type definition indicates it
may be absent. Other integrations (e.g., LinkedIn) already use bookingUrl || fallback, implying
that absence is expected/handled elsewhere.

companion/app/(tabs)/(event-types)/index.tsx[135-146]
companion/services/types/event-types.types.ts[279-284]
companion/extension/lib/linkedin.ts[667-672]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
EventTypes screens now require `eventType.bookingUrl`, but the field is optional. If it’s missing in API responses, users can’t share/copy/preview even though the URL can be derived.

### Issue Context
Other parts of the code (e.g., extension LinkedIn integration) treat `bookingUrl` as optional and build a fallback from username + slug.

### Fix Focus Areas
- companion/app/(tabs)/(event-types)/index.tsx[135-161]
- companion/app/(tabs)/(event-types)/index.tsx[287-301]
- companion/app/(tabs)/(event-types)/index.ios.tsx[113-139]

### Suggested approach
Option A (UI-level fallback):
- Replace the early `if (!eventType.bookingUrl) return` with:
 - `const url = eventType.bookingUrl ?? derivedUrlFromUsernameAndSlug;`
 - Only error if neither is possible.

Option B (data-level normalization):
- In the service layer or hook that returns event types, ensure `bookingUrl` is always populated (compute fallback once) so the UI can treat it as required.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



ⓘ The new review experience is currently in Beta. Learn more

Qodo Logo

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

Choose a reason for hiding this comment

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

Action required

1. getusername() throws generic error 📘 Rule violation ⛯ Reliability

getUsername() catches any failure from getUserProfile() and throws a plain Error with a
  generic message, losing the original cause and any structured context.
• This violates the requirement for hierarchical, typed custom errors with context, and will make
  downstream error handling/debugging inconsistent.
• It also prevents callers from distinguishing auth/network failures vs. unexpected data issues.
Agent prompt
## Issue description
`getUsername()` throws a generic `Error("Failed to get username")` and drops the original exception/context, violating the requirement for hierarchical custom errors with typed codes and structured context.

## Issue Context
This function wraps `getUserProfile()` and is likely used in multiple user-facing flows; without typed codes/context (and ideally `cause`), downstream error handling and debugging becomes unreliable.

## Fix Focus Areas
- companion/services/calcom.ts[1654-1662]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

2. Basicstab url parse ignores errors 📘 Rule violation ⛯ Reliability

• The inline booking URL prefix computation in BasicsTab silently ignores URL parsing errors
  (catch {}), which can mask bad bookingUrl values.
• This is a silent failure at a known failure point (new URL(...)), reducing the ability to debug
  edge cases in production.
• Prefer explicit validation and/or internal logging (redacting as needed) when parsing fails, then
  fall back deterministically.
Agent prompt
## Issue description
`BasicsTab` parses `props.bookingUrl` with `new URL(...)` but swallows parsing failures without any logging/context, which is a silent failure.

## Issue Context
`bookingUrl` is likely API-provided; parsing failures should be diagnosable (internally) and handled explicitly.

## Fix Focus Areas
- companion/components/event-type-detail/tabs/BasicsTab.tsx[257-276]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +949 to +953
if (!bookingUrl) {
showErrorAlert("Error", "Booking URL not available. Please save the event type first.");
return;
}
await openInAppBrowser(link, "event type preview");
await openInAppBrowser(bookingUrl, "event type preview");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

3. Detail link always missing 🐞 Bug ✓ Correctness

EventTypeDetail now gates Preview/Copy on a local bookingUrl state, but that state is
  initialized to "" and never set from fetched EventType data.
• This causes Preview and Copy Link to always show “Booking URL not available…” even when the event
  type has a valid slug/username.
• Users lose core functionality (preview/copy) in the event type detail screen.
Agent prompt
### Issue description
`EventTypeDetail` uses a local `bookingUrl` state for preview/copy, but it is never set from the fetched event type. This makes preview/copy always fail.

### Issue Context
`CalComAPIService.getEventTypeById(...)` returns an `EventType` object which can contain `bookingUrl` (optional). Even when `bookingUrl` is missing, the screen already has enough info (username + slug) to build a fallback URL.

### Fix Focus Areas
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[174-183]
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[451-470]
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[948-963]

### Suggested approach
- Prefer removing the separate `bookingUrl` state entirely and compute it via `useMemo` from `eventTypeData?.bookingUrl` with a fallback `https://cal.com/${username}/${eventSlug}` when possible.
- If keeping state, set it in `applyEventTypeData` (e.g., `setBookingUrl(eventType.bookingUrl ?? "")`) and/or add an effect to recompute when `username`/`eventSlug` change.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines 1122 to 1129
copyBtn.addEventListener("click", (e) => {
e.stopPropagation();
// Copy to clipboard
const bookingUrl = `https://cal.com/${
eventType.users?.[0]?.username || "user"
}/${eventType.slug}`;
const bookingUrl =
`https://cal.com/${
eventType.users?.[0]?.username || "user"
}/${eventType.slug}`;
navigator.clipboard
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

4. Extension copies wrong url 🐞 Bug ✓ Correctness

• In the content script, Preview now uses eventType.bookingUrl || fallback, but the Copy button in
  the same UI still copies only the hardcoded https://cal.com/{username}/{slug}.
• This creates an inconsistent UX (Preview opens one URL, Copy copies another) and breaks copy for
  users on custom booking domains.
• A later section in the same file already uses the correct bookingUrl || fallback for copy,
  suggesting this is an accidental missed update.
Agent prompt
### Issue description
The extension content script’s first event type UI block opens `eventType.bookingUrl` for Preview but copies a hardcoded `https://cal.com/...` URL for Copy. This breaks copying for custom domains and is inconsistent within the same UI.

### Issue Context
A later section in the same file already uses `eventType.bookingUrl || fallback` for copy, so the fix should align the first copy handler.

### Fix Focus Areas
- companion/extension/entrypoints/content.ts[1079-1087]
- companion/extension/entrypoints/content.ts[1122-1131]

### Suggested approach
Change the first copy handler’s `bookingUrl` assignment to:
```ts
const bookingUrl = eventType.bookingUrl || `https://cal.com/${eventType.users?.[0]?.username || "user"}/${eventType.slug}`;
```
so both Preview and Copy use the same source of truth.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +136 to 142
if (!eventType.bookingUrl) {
showErrorAlert("Error", "Booking URL not available for this event type.");
return;
}
try {
const link = await CalComAPIService.buildEventTypeLink(eventType.slug);
await Clipboard.setStringAsync(link);

await Clipboard.setStringAsync(eventType.bookingUrl);
showSuccessAlert("Link Copied", "Event type link copied!");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

5. Link actions too strict 🐞 Bug ⛯ Reliability

• EventTypes list screens (iOS and cross-platform) now hard-require eventType.bookingUrl and show
  an error when it’s missing.
• bookingUrl is explicitly typed as optional, and other parts of the codebase handle its absence
  via fallback URL construction.
• If the API omits bookingUrl in some responses, share/copy/preview will fail even though the URL
  can be derived from username + slug.
Agent prompt
### Issue description
EventTypes screens now require `eventType.bookingUrl`, but the field is optional. If it’s missing in API responses, users can’t share/copy/preview even though the URL can be derived.

### Issue Context
Other parts of the code (e.g., extension LinkedIn integration) treat `bookingUrl` as optional and build a fallback from username + slug.

### Fix Focus Areas
- companion/app/(tabs)/(event-types)/index.tsx[135-161]
- companion/app/(tabs)/(event-types)/index.tsx[287-301]
- companion/app/(tabs)/(event-types)/index.ios.tsx[113-139]

### Suggested approach
Option A (UI-level fallback):
- Replace the early `if (!eventType.bookingUrl) return` with:
  - `const url = eventType.bookingUrl ?? derivedUrlFromUsernameAndSlug;`
  - Only error if neither is possible.

Option B (data-level normalization):
- In the service layer or hook that returns event types, ensure `bookingUrl` is always populated (compute fallback once) so the UI can treat it as required.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants