Files
cal.diy/companion/utils/deep-links.ts
T

129 lines
4.0 KiB
TypeScript

/**
* Deep Links Utility
*
* This module provides utilities for opening Cal.com web pages from the mobile app.
* Used for features that require server-side behavior that cannot be safely reproduced
* client-side (e.g., request reschedule).
*/
import * as Linking from "expo-linking";
import * as WebBrowser from "expo-web-browser";
import { Alert } from "react-native";
// Default Cal.com web URL - can be overridden for self-hosted instances
const DEFAULT_CAL_WEB_URL = "https://app.cal.com";
/**
* Get the Cal.com web URL from environment or use default
*/
function getCalWebUrl(): string {
// In a real implementation, this would read from environment config
// For now, use the default Cal.com URL
return DEFAULT_CAL_WEB_URL;
}
/**
* Open a booking detail page in the web browser.
* This is used for actions that require the full web experience.
*
* @param bookingUid - The unique identifier of the booking
*/
export async function openBookingInWeb(bookingUid: string): Promise<void> {
const webUrl = getCalWebUrl();
const url = `${webUrl}/booking/${bookingUid}`;
try {
await WebBrowser.openBrowserAsync(url, {
presentationStyle: WebBrowser.WebBrowserPresentationStyle.FULL_SCREEN,
});
} catch {
console.error("Failed to open booking in web browser");
// Fallback to system browser
try {
await Linking.openURL(url);
} catch {
Alert.alert("Error", "Failed to open booking in browser. Please try again.");
}
}
}
/**
* Open the request reschedule flow in the web browser.
* Since request reschedule is a server-driven operation with complex side effects
* (emails, webhooks, calendar updates), we open the web page where the user can
* trigger it safely.
*
* Note: The web flow uses a dialog (RescheduleDialog.tsx) that calls
* trpc.viewer.bookings.requestReschedule.useMutation. There's no direct URL route
* for request reschedule, so we open the booking detail page.
*
* @param bookingUid - The unique identifier of the booking
*/
export async function openRequestRescheduleInWeb(bookingUid: string): Promise<void> {
// Show an informational alert before opening the web page
Alert.alert(
"Request Reschedule",
"You will be redirected to the web app to request a reschedule. This ensures all notifications and calendar updates are handled correctly.",
[
{ text: "Cancel", style: "cancel" },
{
text: "Open in Browser",
onPress: () => openBookingInWeb(bookingUid),
},
]
);
}
/**
* Open the reschedule page for an attendee to pick a new time.
* This is the public reschedule page that attendees use.
*
* @param bookingUid - The unique identifier of the booking
* @param rescheduleUid - The reschedule token/uid (optional)
*/
export async function openReschedulePage(
bookingUid: string,
rescheduleUid?: string
): Promise<void> {
const webUrl = getCalWebUrl();
const url = rescheduleUid
? `${webUrl}/reschedule/${rescheduleUid}`
: `${webUrl}/booking/${bookingUid}`;
try {
await WebBrowser.openBrowserAsync(url, {
presentationStyle: WebBrowser.WebBrowserPresentationStyle.FULL_SCREEN,
});
} catch {
console.error("Failed to open reschedule page in web browser");
try {
await Linking.openURL(url);
} catch {
Alert.alert("Error", "Failed to open reschedule page. Please try again.");
}
}
}
/**
* Open the cancel booking page in the web browser.
* This is a fallback for cases where the API cancel doesn't work.
*
* @param bookingUid - The unique identifier of the booking
*/
export async function openCancelBookingInWeb(bookingUid: string): Promise<void> {
const webUrl = getCalWebUrl();
const url = `${webUrl}/booking/${bookingUid}`;
try {
await WebBrowser.openBrowserAsync(url, {
presentationStyle: WebBrowser.WebBrowserPresentationStyle.FULL_SCREEN,
});
} catch {
console.error("Failed to open cancel booking page in web browser");
try {
await Linking.openURL(url);
} catch {
Alert.alert("Error", "Failed to open booking page. Please try again.");
}
}
}