Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export default function AvailabilityDetail() {
marginRight: -8,
}}
>
<Ionicons name="ellipsis-horizontal-circle" size={24} color="#007AFF" />
<Ionicons name="ellipsis-horizontal-circle" size={24} color="#000000" />
</TouchableOpacity>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-56">
Expand Down
4 changes: 2 additions & 2 deletions companion/app/(tabs)/(bookings)/index.ios.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default function Bookings() {
label: currentFilterOption?.label || "Filter",
labelStyle: {
fontWeight: "600",
color: "#007AFF",
color: "#000000",
},
menu: {
title: "Filter by Status",
Expand Down Expand Up @@ -123,7 +123,7 @@ export default function Bookings() {
},
labelStyle: {
fontWeight: "600",
color: "#007AFF",
color: "#000000",
},
menu: {
title: menuItems.length > 0 ? "Filter by Event Type" : "No Event Types",
Expand Down
9 changes: 7 additions & 2 deletions companion/app/(tabs)/(bookings)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,16 @@ export default function Bookings() {
<DropdownMenuTrigger asChild>
<AppPressable
className="flex-row items-center rounded-lg border border-gray-200 bg-white"
style={{ paddingHorizontal: 8, paddingVertical: 6 }}
style={{
paddingHorizontal: 8,
paddingVertical: 6,
flexDirection: "row",
alignItems: "center",
}}
>
<Ionicons name="options-outline" size={14} color="#333" />
<Text
className={`text-sm ${selectedEventTypeId !== null ? "text-[#007AFF] font-semibold" : "text-[#333]"}`}
className={`text-sm ${selectedEventTypeId !== null ? "text-[#000000] font-semibold" : "text-[#333]"}`}
style={{ marginLeft: 4 }}
numberOfLines={1}
>
Expand Down
45 changes: 21 additions & 24 deletions companion/app/(tabs)/(event-types)/event-type-detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ export default function EventTypeDetail() {
const [conferencingOptions, setConferencingOptions] = useState<ConferencingOption[]>([]);
const [conferencingLoading, setConferencingLoading] = useState(false);
const [eventTypeData, setEventTypeData] = useState<EventType | null>(null);
const [bookingUrl, setBookingUrl] = useState<string>("");
const [saving, setSaving] = useState(false);
const [beforeEventBuffer, setBeforeEventBuffer] = useState("No buffer time");
const [afterEventBuffer, setAfterEventBuffer] = useState("No buffer time");
Expand Down Expand Up @@ -945,29 +946,19 @@ export default function EventTypeDetail() {
};

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!");
};
Comment on lines 948 to 963
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


Expand Down Expand Up @@ -1279,7 +1270,10 @@ export default function EventTypeDetail() {
{/* Tab Navigation Dropdown Menu */}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<AppPressable className="flex-row items-center gap-1 px-2 py-2">
<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]" numberOfLines={1}>
{tabs.find((tab) => tab.id === activeTab)?.label ?? "Basics"}
</Text>
Expand Down Expand Up @@ -1433,6 +1427,7 @@ export default function EventTypeDetail() {
onUpdateLocation={handleUpdateLocation}
locationOptions={getLocationOptionsForDropdown()}
conferencingLoading={conferencingLoading}
bookingUrl={bookingUrl}
/>
) : null}

Expand Down Expand Up @@ -2342,15 +2337,17 @@ export default function EventTypeDetail() {
<View className="bg-white pl-4">
<View
className="flex-row items-center justify-between pr-4"
style={{ height: 44 }}
style={{ height: 44, flexDirection: "row", alignItems: "center" }}
>
<Text className="text-[17px] text-black">Hidden</Text>
<Switch
value={isHidden}
onValueChange={setIsHidden}
trackColor={{ false: "#E5E5EA", true: "#000000" }}
thumbColor="#FFFFFF"
/>
<View style={{ justifyContent: "center", height: "100%" }}>
<Switch
value={isHidden}
onValueChange={setIsHidden}
trackColor={{ false: "#E5E5EA", true: "#000000" }}
thumbColor="#FFFFFF"
/>
</View>
</View>
</View>
</View>
Expand Down
28 changes: 18 additions & 10 deletions companion/app/(tabs)/(event-types)/index.ios.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Button, ContextMenu, Host, HStack, Image as SwiftUIImage } from "@expo/ui/swift-ui";
import { Button, Host, Image as SwiftUIImage } from "@expo/ui/swift-ui";
import * as Haptics from "expo-haptics";
import { buttonStyle, controlSize, fixedSize, frame, padding } from "@expo/ui/swift-ui/modifiers";
import { buttonStyle, controlSize, frame, padding } from "@expo/ui/swift-ui/modifiers";
import { Ionicons } from "@expo/vector-icons";
import * as Clipboard from "expo-clipboard";
import { isLiquidGlassAvailable } from "expo-glass-effect";
Expand Down Expand Up @@ -28,7 +28,7 @@ import {
useUserProfile,
} from "@/hooks";
import { useEventTypeFilter } from "@/hooks/useEventTypeFilter";
import { CalComAPIService, type EventType } from "@/services/calcom";
import type { EventType } from "@/services/calcom";
import { showErrorAlert, showSuccessAlert } from "@/utils/alerts";
import { openInAppBrowser } from "@/utils/browser";
import { getAvatarUrl } from "@/utils/getAvatarUrl";
Expand Down Expand Up @@ -111,21 +111,27 @@ export default function EventTypesIOS() {
};

const handleCopyLink = async (eventType: EventType) => {
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!");
} catch {
showErrorAlert("Error", "Failed to copy link. Please try again.");
}
};

const _handleShare = async (eventType: EventType) => {
if (!eventType.bookingUrl) {
showErrorAlert("Error", "Booking URL not available for this event type.");
return;
}
try {
const link = await CalComAPIService.buildEventTypeLink(eventType.slug);
await Share.share({
message: `Book a meeting: ${eventType.title}`,
url: link,
url: eventType.bookingUrl,
});
} catch {
showErrorAlert("Error", "Failed to share link. Please try again.");
Expand Down Expand Up @@ -226,10 +232,12 @@ export default function EventTypesIOS() {
};

const handlePreview = async (eventType: EventType) => {
if (!eventType.bookingUrl) {
showErrorAlert("Error", "Booking URL not available for this event type.");
return;
}
try {
const link = await CalComAPIService.buildEventTypeLink(eventType.slug);
// For mobile, use in-app browser
await openInAppBrowser(link, "event type preview");
await openInAppBrowser(eventType.bookingUrl, "event type preview");
} catch {
console.error("Failed to open preview");
showErrorAlert("Error", "Failed to open preview. Please try again.");
Expand Down
30 changes: 19 additions & 11 deletions companion/app/(tabs)/(event-types)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import {
useEventTypes,
} from "@/hooks";
import { useEventTypeFilter } from "@/hooks/useEventTypeFilter";
import { CalComAPIService, type EventType } from "@/services/calcom";
import type { EventType } from "@/services/calcom";
import { showErrorAlert, showSuccessAlert } from "@/utils/alerts";
import { openInAppBrowser } from "@/utils/browser";
import { getEventDuration } from "@/utils/getEventDuration";
Expand Down Expand Up @@ -133,22 +133,27 @@ export default function EventTypes() {
};

const handleCopyLink = async (eventType: EventType) => {
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!");
} catch {
showErrorAlert("Error", "Failed to copy link. Please try again.");
}
};

const _handleShare = async (eventType: EventType) => {
if (!eventType.bookingUrl) {
showErrorAlert("Error", "Booking URL not available for this event type.");
return;
}
try {
const link = await CalComAPIService.buildEventTypeLink(eventType.slug);
await Share.share({
message: `Book a meeting: ${eventType.title}`,
url: link,
url: eventType.bookingUrl,
});
} catch {
showErrorAlert("Error", "Failed to share link. Please try again.");
Expand Down Expand Up @@ -280,14 +285,15 @@ export default function EventTypes() {
};

const handlePreview = async (eventType: EventType) => {
if (!eventType.bookingUrl) {
showErrorAlert("Error", "Booking URL not available for this event type.");
return;
}
try {
const link = await CalComAPIService.buildEventTypeLink(eventType.slug);
// Open in browser
if (Platform.OS === "web") {
window.open(link, "_blank");
window.open(eventType.bookingUrl, "_blank");
} else {
// For mobile, use in-app browser
await openInAppBrowser(link, "event type preview");
await openInAppBrowser(eventType.bookingUrl, "event type preview");
}
} catch {
console.error("Failed to open preview");
Expand Down Expand Up @@ -443,6 +449,7 @@ export default function EventTypes() {
/>
<TouchableOpacity
className="min-w-[60px] flex-row items-center justify-center gap-1 rounded-lg bg-black px-2.5 py-2"
style={{ flexDirection: "row", alignItems: "center", justifyContent: "center" }}
onPress={handleCreateNew}
>
<Ionicons name="add" size={18} color="#fff" />
Expand Down Expand Up @@ -507,6 +514,7 @@ export default function EventTypes() {
/>
<TouchableOpacity
className="min-w-[60px] flex-row items-center justify-center gap-1 rounded-lg bg-black px-2.5 py-2"
style={{ flexDirection: "row", alignItems: "center", justifyContent: "center" }}
onPress={handleCreateNew}
>
<Ionicons name="add" size={18} color="#fff" />
Expand Down
2 changes: 1 addition & 1 deletion companion/app/profile-sheet.ios.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ export default function ProfileSheet() {
}}
>
{/* Profile Header */}
<View className="mt-20 border-b border-gray-200 px-6">
<View className="mt-20 px-6">
{isLoading ? (
<View className="items-center py-8">
<ActivityIndicator size="large" color="#000" />
Expand Down
2 changes: 1 addition & 1 deletion companion/app/profile-sheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export default function ProfileSheet() {
contentContainerStyle={{ paddingBottom: insets.bottom + 20 }}
>
{/* Profile Header */}
<View className="border-b border-gray-200 px-6 py-6">
<View className="px-6 py-6">
{isLoading ? (
<View className="items-center py-8">
<ActivityIndicator size="large" color="#000" />
Expand Down
Loading
Loading