fix(companion): event type links for org user#116
Conversation
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 <>
Review Summary by QodoAdd bookingUrl field to event types and simplify URL handling
WalkthroughsDescription• 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 Diagramflowchart 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
File Changes1. companion/extension/entrypoints/background/index.ts
|
Code Review by Qodo
1. getUsername() throws generic Error
|
| // 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"); | ||
| } | ||
| } |
There was a problem hiding this comment.
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
| 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!"); | ||
| }; |
There was a problem hiding this comment.
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
| 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 |
There was a problem hiding this comment.
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
Benchmark PR from agentic-review-benchmarks#5