Skip to content

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

Open
tomerqodo wants to merge 7 commits intoqodo_claude_vs_qodo_base_fixcompanion_event_type_links_for_org_user_pr5from
qodo_claude_vs_qodo_head_fixcompanion_event_type_links_for_org_user_pr5
Open

fix(companion): event type links for org user#116
tomerqodo wants to merge 7 commits intoqodo_claude_vs_qodo_base_fixcompanion_event_type_links_for_org_user_pr5from
qodo_claude_vs_qodo_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

Review Summary by Qodo

Add bookingUrl field to event types and simplify URL handling

✨ Enhancement 🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Add bookingUrl field to event type data structures across extension and mobile app
• Use pre-computed bookingUrl from API instead of constructing URLs client-side
• Remove buildEventTypeLink() helper function, simplify URL handling logic
• Fix iOS UI colors from blue (#007AFF) to black (#000000) for consistency
• Improve layout stability with explicit flexbox properties on iOS components
• Remove unused imports and add biome lint ignore comment for Safari API compatibility
Diagram
flowchart LR
  API["API Response<br/>with bookingUrl"] -->|"includes bookingUrl field"| EventType["EventType<br/>Data Structure"]
  EventType -->|"used directly"| Preview["Preview/Copy<br/>Link Actions"]
  EventType -->|"displayed in UI"| ListItem["Event Type<br/>List Items"]
  OldLogic["Old: Construct URL<br/>from username+slug"] -->|"removed"| Cleanup["Simplified<br/>Code"]
  Preview --> Cleanup
  ListItem --> Cleanup
Loading

Grey Divider

File Changes

1. companion/extension/entrypoints/background/index.ts Error handling +1/-0

Add biome lint ignore for Safari API compatibility

companion/extension/entrypoints/background/index.ts


2. companion/extension/entrypoints/content.ts ✨ Enhancement +33/-21

Add bookingUrl field to event type interfaces throughout

companion/extension/entrypoints/content.ts


3. companion/services/calcom.ts ✨ Enhancement +10/-13

Remove buildEventTypeLink, relocate getUsername helper

companion/services/calcom.ts


View more (18)
4. companion/services/types/event-types.types.ts ✨ Enhancement +3/-0

Add optional bookingUrl field to EventType interface

companion/services/types/event-types.types.ts


5. companion/app/(tabs)/(availability)/availability-detail.tsx 🐞 Bug fix +1/-1

Change icon color from blue to black

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


6. companion/app/(tabs)/(bookings)/index.ios.tsx 🐞 Bug fix +2/-2

Change filter menu color from blue to black

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


7. companion/app/(tabs)/(bookings)/index.tsx 🐞 Bug fix +7/-2

Add explicit flexbox styles and change color to black

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


8. companion/app/(tabs)/(event-types)/event-type-detail.tsx ✨ Enhancement +21/-24

Use bookingUrl state, simplify preview/copy link logic

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


9. companion/app/(tabs)/(event-types)/index.ios.tsx ✨ Enhancement +18/-10

Remove buildEventTypeLink calls, use bookingUrl directly

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


10. companion/app/(tabs)/(event-types)/index.tsx ✨ Enhancement +19/-11

Remove buildEventTypeLink calls, add bookingUrl validation

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


11. companion/app/profile-sheet.ios.tsx 🐞 Bug fix +1/-1

Remove border-bottom from profile header

companion/app/profile-sheet.ios.tsx


12. companion/app/profile-sheet.tsx 🐞 Bug fix +1/-1

Remove border-bottom from profile header

companion/app/profile-sheet.tsx


13. companion/components/Header.tsx 🐞 Bug fix +26/-23

Change all accent colors from blue to black throughout

companion/components/Header.tsx


14. companion/components/event-type-detail/tabs/AdvancedTab.tsx 🐞 Bug fix +2/-2

Add explicit flexbox and justify-content styles

companion/components/event-type-detail/tabs/AdvancedTab.tsx


15. companion/components/event-type-detail/tabs/BasicsTab.tsx ✨ Enhancement +23/-3

Parse bookingUrl for URL display, add explicit flexbox styles

companion/components/event-type-detail/tabs/BasicsTab.tsx


16. companion/components/event-type-detail/tabs/LimitsTab.tsx 🐞 Bug fix +2/-2

Add explicit flexbox and justify-content styles

companion/components/event-type-detail/tabs/LimitsTab.tsx


17. companion/components/event-type-detail/tabs/RecurringTab.tsx 🐞 Bug fix +2/-2

Add explicit flexbox and justify-content styles

companion/components/event-type-detail/tabs/RecurringTab.tsx


18. companion/components/event-type-list-item/EventTypeListItem.ios.tsx ✨ Enhancement +1/-0

Pass bookingUrl prop to EventTypeTitle component

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


19. companion/components/event-type-list-item/EventTypeListItem.tsx ✨ Enhancement +1/-0

Pass bookingUrl prop to EventTypeTitle component

companion/components/event-type-list-item/EventTypeListItem.tsx


20. companion/components/event-type-list-item/EventTypeListItemParts.tsx ✨ Enhancement +23/-4

Add getDisplayUrl helper to parse bookingUrl for display

companion/components/event-type-list-item/EventTypeListItemParts.tsx


21. companion/extension/lib/linkedin.ts Additional files +5/-1

...

companion/extension/lib/linkedin.ts


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Mar 10, 2026

Code Review by Qodo

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

Grey Divider


Action required

1. getUsername() throws generic Error 📘 Rule violation ⛯ Reliability
Description
The new getUsername() implementation catches an error and rethrows a generic Error without a
typed code/status or preserving context/cause. This reduces debuggability and violates the required
structured error hierarchy for domain/API errors.
Code

companion/services/calcom.ts[R1654-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");
+  }
+}
Evidence
PR Compliance ID 9 disallows throwing generic Error where structured/typed errors are expected.
The added getUsername() catches error and throws new Error("Failed to get username"), dropping
the original error context and any typed categorization.

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()` currently catches an error and throws a generic `Error(&quot;Failed to get username&quot;)`, which violates the requirement to use structured/typed error classes (with typed codes/status when applicable) and to include debugging context/cause.

## Issue Context
This function is part of `CalComAPIService` and failures should be categorized with a typed code and should preserve the original error (`cause`) for troubleshooting.

## 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. bookingUrl never populated 🐞 Bug ✓ Correctness
Description
EventTypeDetail's handlePreview/handleCopyLink now require bookingUrl, but bookingUrl state is
initialized to an empty string and is never set from fetched event type data, so preview/copy always
show an error. The BasicsTab also receives the empty bookingUrl, so org/custom-domain URL prefix
display is wrong.
Code

companion/app/(tabs)/(event-types)/event-type-detail.tsx[R948-963]

  const handlePreview = async () => {
-    const eventTypeSlug = eventSlug || "preview";
-    let link: string;
-    try {
-      link = await CalComAPIService.buildEventTypeLink(eventTypeSlug);
-    } catch (error) {
-      safeLogError("Failed to generate preview link:", error);
-      showErrorAlert("Error", "Failed to generate preview link. Please try again.");
+    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");
  };

  const handleCopyLink = async () => {
-    const eventTypeSlug = eventSlug || "event-link";
-    let link: string;
-    try {
-      link = await CalComAPIService.buildEventTypeLink(eventTypeSlug);
-    } catch (error) {
-      safeLogError("Failed to copy link:", error);
-      showErrorAlert("Error", "Failed to copy link. Please try again.");
+    if (!bookingUrl) {
+      showErrorAlert("Error", "Booking URL not available. Please save the event type first.");
      return;
    }
-    await Clipboard.setStringAsync(link);
+    await Clipboard.setStringAsync(bookingUrl);
    showSuccessAlert("Success", "Link copied!");
  };
Evidence
The screen introduces a bookingUrl state and then gates preview/copy on it, but the code that
populates screen state from the fetched EventType (applyEventTypeData) never assigns bookingUrl. As
a result, bookingUrl remains the initial empty string and the new preview/copy handlers always fail
the availability check; the empty value is also passed down to BasicsTab even though EventType
supports a bookingUrl field.

companion/app/(tabs)/(event-types)/event-type-detail.tsx[172-183]
companion/app/(tabs)/(event-types)/event-type-detail.tsx[948-963]
companion/app/(tabs)/(event-types)/event-type-detail.tsx[451-460]
companion/app/(tabs)/(event-types)/event-type-detail.tsx[1423-1431]
companion/services/types/event-types.types.ts[276-284]

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 to power preview/copy and to render the URL prefix in `BasicsTab`, but that state is never set from the fetched event type. This causes preview/copy to always error and prevents showing org/custom-domain links.

### Issue Context
The API `EventType` type includes `bookingUrl?: string`, and `getEventTypeById()` returns an `EventType` object. The detail screen already has a centralized `applyEventTypeData(eventType)` function to populate state from the fetched object; `bookingUrl` should be set there (and refreshed after saves/fetches).

### Fix Focus Areas
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[451-468]
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[948-963]
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[1423-1431]

### Implementation notes
- In `applyEventTypeData`, set `bookingUrl` from `eventType.bookingUrl` (e.g., `setBookingUrl(eventType.bookingUrl ?? &quot;&quot;)`).
- Consider a fallback computation if `bookingUrl` is missing (e.g., derive from `username` + `eventType.slug`) to avoid breaking preview/copy when the field is absent.
- Ensure `bookingUrl` is refreshed after `fetchEventTypeData()` post-save (already called) so it stays in sync with slug changes.

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


3. Copy ignores bookingUrl 🐞 Bug ✓ Correctness
Description
In the extension content script, the Preview button correctly prefers eventType.bookingUrl, but the
adjacent Copy Link button always copies a hardcoded https://cal.com/{username}/{slug} URL.
Org/custom-domain event types will therefore copy the wrong link.
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 content script’s event type objects now include a bookingUrl field, and the Preview handler uses
it. However, the Copy Link handler right below still builds the URL only from username/slug and
ignores bookingUrl, creating inconsistent behavior and incorrect links for org users.

companion/extension/entrypoints/content.ts[827-837]
companion/extension/entrypoints/content.ts[1079-1086]
companion/extension/entrypoints/content.ts[1122-1129]

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’s event type action buttons are inconsistent: Preview uses `eventType.bookingUrl` when present, but Copy Link always copies a hardcoded `https://cal.com/{username}/{slug}` URL. For org/custom-domain event types, users will copy an incorrect booking link.

### Issue Context
`bookingUrl?: string` is already present on the event type objects in the content script, and Preview already uses it.

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

### Implementation notes
- Update the Copy Link handler to:
 - prefer `eventType.bookingUrl`
 - otherwise fall back to the existing `https://cal.com/${username}/${slug}` construction
- Keep behavior identical to the Preview handler to avoid future drift.

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


Grey Divider

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

Grey Divider

Qodo Logo

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

The new getUsername() implementation catches an error and rethrows a generic Error without a
typed code/status or preserving context/cause. This reduces debuggability and violates the required
structured error hierarchy for domain/API errors.
Agent Prompt
## Issue description
`getUsername()` currently catches an error and throws a generic `Error("Failed to get username")`, which violates the requirement to use structured/typed error classes (with typed codes/status when applicable) and to include debugging context/cause.

## Issue Context
This function is part of `CalComAPIService` and failures should be categorized with a typed code and should preserve the original error (`cause`) for troubleshooting.

## 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 948 to 963
const handlePreview = async () => {
const eventTypeSlug = eventSlug || "preview";
let link: string;
try {
link = await CalComAPIService.buildEventTypeLink(eventTypeSlug);
} catch (error) {
safeLogError("Failed to generate preview link:", error);
showErrorAlert("Error", "Failed to generate preview link. Please try again.");
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");
};

const handleCopyLink = async () => {
const eventTypeSlug = eventSlug || "event-link";
let link: string;
try {
link = await CalComAPIService.buildEventTypeLink(eventTypeSlug);
} catch (error) {
safeLogError("Failed to copy link:", error);
showErrorAlert("Error", "Failed to copy link. Please try again.");
if (!bookingUrl) {
showErrorAlert("Error", "Booking URL not available. Please save the event type first.");
return;
}
await Clipboard.setStringAsync(link);
await Clipboard.setStringAsync(bookingUrl);
showSuccessAlert("Success", "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.

Action required

2. Bookingurl never populated 🐞 Bug ✓ Correctness

EventTypeDetail's handlePreview/handleCopyLink now require bookingUrl, but bookingUrl state is
initialized to an empty string and is never set from fetched event type data, so preview/copy always
show an error. The BasicsTab also receives the empty bookingUrl, so org/custom-domain URL prefix
display is wrong.
Agent Prompt
### Issue description
`EventTypeDetail` uses a local `bookingUrl` state to power preview/copy and to render the URL prefix in `BasicsTab`, but that state is never set from the fetched event type. This causes preview/copy to always error and prevents showing org/custom-domain links.

### Issue Context
The API `EventType` type includes `bookingUrl?: string`, and `getEventTypeById()` returns an `EventType` object. The detail screen already has a centralized `applyEventTypeData(eventType)` function to populate state from the fetched object; `bookingUrl` should be set there (and refreshed after saves/fetches).

### Fix Focus Areas
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[451-468]
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[948-963]
- companion/app/(tabs)/(event-types)/event-type-detail.tsx[1423-1431]

### Implementation notes
- In `applyEventTypeData`, set `bookingUrl` from `eventType.bookingUrl` (e.g., `setBookingUrl(eventType.bookingUrl ?? "")`).
- Consider a fallback computation if `bookingUrl` is missing (e.g., derive from `username` + `eventType.slug`) to avoid breaking preview/copy when the field is absent.
- Ensure `bookingUrl` is refreshed after `fetchEventTypeData()` post-save (already called) so it stays in sync with slug changes.

ⓘ 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

3. Copy ignores bookingurl 🐞 Bug ✓ Correctness

In the extension content script, the Preview button correctly prefers eventType.bookingUrl, but the
adjacent Copy Link button always copies a hardcoded https://cal.com/{username}/{slug} URL.
Org/custom-domain event types will therefore copy the wrong link.
Agent Prompt
### Issue description
The extension’s event type action buttons are inconsistent: Preview uses `eventType.bookingUrl` when present, but Copy Link always copies a hardcoded `https://cal.com/{username}/{slug}` URL. For org/custom-domain event types, users will copy an incorrect booking link.

### Issue Context
`bookingUrl?: string` is already present on the event type objects in the content script, and Preview already uses it.

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

### Implementation notes
- Update the Copy Link handler to:
  - prefer `eventType.bookingUrl`
  - otherwise fall back to the existing `https://cal.com/${username}/${slug}` construction
- Keep behavior identical to the Preview handler to avoid future drift.

ⓘ 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