fix(companion): event type links for org user#5
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 <>
There was a problem hiding this comment.
Pull request overview
Updates the companion app/extension to use an API-provided bookingUrl for event type links (to support org/team users where https://cal.com/{username}/{slug} is incorrect).
Changes:
- Add
bookingUrlto theEventTypetype and prefer it when building/copying/opening booking links across the app and extension. - Remove the client-side
buildEventTypeLinkhelper in favor of usingbookingUrl. - Apply various UI/style tweaks (colors, layout alignment) across multiple screens/components.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| companion/services/types/event-types.types.ts | Adds bookingUrl to the EventType contract. |
| companion/services/calcom.ts | Removes buildEventTypeLink; adjusts username helper. |
| companion/extension/lib/linkedin.ts | Prefers eventType.bookingUrl when generating booking links. |
| companion/extension/entrypoints/content.ts | Prefers bookingUrl in some booking link actions within the content script. |
| companion/extension/entrypoints/background/index.ts | Adds a Biome lint suppression for Safari browserAction typing. |
| companion/components/event-type-list-item/EventTypeListItemParts.tsx | Displays a parsed booking URL when available. |
| companion/components/event-type-list-item/EventTypeListItem.tsx | Passes bookingUrl into list item title/link rendering. |
| companion/components/event-type-list-item/EventTypeListItem.ios.tsx | Passes bookingUrl into iOS list item title/link rendering. |
| companion/components/event-type-detail/tabs/RecurringTab.tsx | UI alignment/layout adjustments. |
| companion/components/event-type-detail/tabs/LimitsTab.tsx | UI alignment/layout adjustments. |
| companion/components/event-type-detail/tabs/BasicsTab.tsx | Displays a booking URL-derived prefix for the slug editor; adds bookingUrl prop. |
| companion/components/event-type-detail/tabs/AdvancedTab.tsx | UI alignment/layout adjustments. |
| companion/components/Header.tsx | Changes header colors/styling and adds inline layout styles. |
| companion/app/profile-sheet.tsx | Removes profile header border styling. |
| companion/app/profile-sheet.ios.tsx | Removes profile header border styling (iOS). |
| companion/app/(tabs)/(event-types)/index.tsx | Copy/share/preview now use eventType.bookingUrl (and error if missing). |
| companion/app/(tabs)/(event-types)/index.ios.tsx | Copy/share/preview now use eventType.bookingUrl (and error if missing); trims unused imports. |
| companion/app/(tabs)/(event-types)/event-type-detail.tsx | Attempts to use a bookingUrl state for preview/copy and passes it to Basics tab. |
| companion/app/(tabs)/(bookings)/index.tsx | Styling/color tweaks in bookings filter UI. |
| companion/app/(tabs)/(bookings)/index.ios.tsx | Styling/color tweaks in bookings filter UI (iOS). |
| companion/app/(tabs)/(availability)/availability-detail.tsx | Styling/color tweak for the options icon. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const bookingUrl = `https://cal.com/${ | ||
| eventType.users?.[0]?.username || "user" | ||
| }/${eventType.slug}`; | ||
| const bookingUrl = |
There was a problem hiding this comment.
The copy-link handler constructs a https://cal.com/{username}/{slug} URL and ignores eventType.bookingUrl. For org/team event types this will copy the wrong link even though the preview button correctly prefers bookingUrl. Update this handler to use eventType.bookingUrl when present (same fallback logic as preview).
| const bookingUrl = | |
| const bookingUrl = | |
| eventType.bookingUrl || |
| const [eventTypeData, setEventTypeData] = useState<EventType | null>(null); | ||
| const [bookingUrl, setBookingUrl] = useState<string>(""); | ||
| const [saving, setSaving] = useState(false); |
There was a problem hiding this comment.
bookingUrl state is introduced and then required for preview/copy, but it is never set anywhere (no setBookingUrl(...) calls). As a result, preview/copy will always show the "Booking URL not available" error. Populate this state from the fetched event type (e.g., in applyEventTypeData / fetchEventTypeData) and update it after saving, or avoid the extra state and read from eventTypeData?.bookingUrl directly.
| try { | ||
| const profile = await getUserProfile(); | ||
| return profile.username; | ||
| } catch (error) { |
There was a problem hiding this comment.
getUsername catches and throws a new generic error, which drops the original status/message and makes debugging harder. Consider either letting the original error propagate, or rethrowing with the original error as a cause / including error.message in the thrown error.
| } catch (error) { | |
| } catch (error) { | |
| if (error instanceof Error) { | |
| throw new Error(`Failed to get username: ${error.message}`, { cause: error }); | |
| } |
| {(() => { | ||
| // 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}/`; | ||
| })()} |
There was a problem hiding this comment.
This URL prefix renderer returns url.protocol//url.hostname/... when bookingUrl is present, but the inline comment examples (and the fallback) omit the protocol (cal.com/...). This makes the displayed prefix inconsistent depending on whether bookingUrl exists. Consider returning url.hostname + prefix (or updating the fallback to also include protocol) so the UI is consistent.
| <AppPressable | ||
| className="flex-row items-center gap-1 px-2 py-2" | ||
| style={{ flexDirection: "row", alignItems: "center" }} | ||
| > | ||
| <Text className="text-[16px] font-semibold text-[#000000]"> | ||
| {activeFilterLabel} | ||
| </Text> | ||
| <Ionicons name="chevron-down" size={16} color="#007AFF" /> | ||
| <Ionicons name="chevron-down" size={16} color="#000000" /> |
There was a problem hiding this comment.
The PR title/description is about fixing event type links, but this file includes visual design changes (e.g., swapping the accent color from #007AFF to #000000 and additional inline layout styles). If these UI/style updates are unrelated to the link fix, consider moving them into a separate PR to keep the change focused and easier to review/revert.
Benchmark PR from agentic-review-benchmarks#5