chore(deps): update dependencies and add version constraints (#26328)

* chore(deps): update dependencies and add version constraints

 - Update direct dependencies: body-parser, @nestjs/swagger, react-use, trigger.dev
 - Add resolutions for consistent dependency versions across the monorepo
 - Add packageExtensions to ensure compatible transitive dependency versions

* fix: upgrade rollup resolution from 3.29.5 to 4.22.4

 Rollup 3.x is incompatible with vite 5.x which requires rollup ^4.20.0.
 The previous resolution caused CI failures due to missing ./parseAst
 export

* fix: update axios resolution to 1.13.2

Align resolution with direct dependency in apps/api/v2.
Both versions include the fix, but 1.13.2 is newer and
avoids an unnecessary downgrade
This commit is contained in:
Pedro Castro authored and GitHub committed 2026-01-01 23:18:53 +00:00
1 parent 6bdb08317d
commit 40dd546429
19 files changed
+794 -834

No files matched your search

+2 -2
View File
@@ -54,14 +54,14 @@
"@nestjs/jwt": "10.2.0",
"@nestjs/passport": "10.0.3",
"@nestjs/platform-express": "10.4.20",
"@nestjs/swagger": "7.3.0",
"@nestjs/swagger": "7.4.2",
"@nestjs/throttler": "6.2.1",
"@sentry/nestjs": "9.46.0",
"@sentry/node": "9.46.0",
"@sentry/profiling-node": "9.46.0",
"@snyk/protect": "latest",
"axios": "1.13.2",
"body-parser": "1.20.2",
"body-parser": "1.20.3",
"bull": "4.15.1",
"class-transformer": "0.5.1",
"class-validator": "0.14.3",
@@ -94,7 +94,8 @@ export default function Availability() {
<Stack.Header
style={{ backgroundColor: "transparent", shadowColor: "transparent" }}
blurEffect={isLiquidGlassAvailable() ? undefined : "light"}
hidden={Platform.OS === "android"}>
hidden={Platform.OS === "android"}
>
<Stack.Header.Title large>Availability</Stack.Header.Title>
<Stack.Header.Right>
{/* New Menu */}
@@ -218,7 +218,8 @@ export default function EventTypesIOS() {
});
},
onError: (duplicateError) => {
const message = duplicateError instanceof Error ? duplicateError.message : String(duplicateError);
const message =
duplicateError instanceof Error ? duplicateError.message : String(duplicateError);
console.error("Failed to duplicate event type", message);
if (__DEV__) {
const stack = duplicateError instanceof Error ? duplicateError.stack : undefined;
@@ -281,13 +282,18 @@ export default function EventTypesIOS() {
id: newEventType.id.toString(),
title: newEventType.title,
description: newEventType.description || "",
duration: (newEventType.lengthInMinutes || newEventType.length || 15).toString(),
duration: (
newEventType.lengthInMinutes ||
newEventType.length ||
15
).toString(),
slug: newEventType.slug || "",
},
});
},
onError: (createError) => {
const message = createError instanceof Error ? createError.message : String(createError);
const message =
createError instanceof Error ? createError.message : String(createError);
console.error("Failed to create event type", message);
if (__DEV__) {
const stack = createError instanceof Error ? createError.stack : undefined;
@@ -373,7 +379,8 @@ export default function EventTypesIOS() {
{/* iOS Native Header with Glass UI */}
<Stack.Header
style={{ backgroundColor: "transparent", shadowColor: "transparent" }}
blurEffect={isLiquidGlassAvailable() ? undefined : "light"}>
blurEffect={isLiquidGlassAvailable() ? undefined : "light"}
>
<Stack.Header.Title large>Event Types</Stack.Header.Title>
<Stack.Header.Right>
@@ -385,12 +392,14 @@ export default function EventTypesIOS() {
<Stack.Header.Menu title="Sort by">
<Stack.Header.MenuAction
icon="textformat.abc"
onPress={() => handleSortByOption("alphabetical")}>
onPress={() => handleSortByOption("alphabetical")}
>
Alphabetical
</Stack.Header.MenuAction>
<Stack.Header.MenuAction
icon="calendar.badge.clock"
onPress={() => handleSortByOption("newest")}>
onPress={() => handleSortByOption("newest")}
>
Newest First
</Stack.Header.MenuAction>
<Stack.Header.MenuAction icon="clock" onPress={() => handleSortByOption("duration")}>
@@ -400,13 +409,19 @@ export default function EventTypesIOS() {
{/* Filter Submenu - opens as separate submenu */}
<Stack.Header.Menu title="Filter">
<Stack.Header.MenuAction icon="checkmark.circle" onPress={() => handleFilterOption("all")}>
<Stack.Header.MenuAction
icon="checkmark.circle"
onPress={() => handleFilterOption("all")}
>
All Event Types
</Stack.Header.MenuAction>
<Stack.Header.MenuAction icon="eye" onPress={() => handleFilterOption("active")}>
Active Only
</Stack.Header.MenuAction>
<Stack.Header.MenuAction icon="dollarsign.circle" onPress={() => handleFilterOption("paid")}>
<Stack.Header.MenuAction
icon="dollarsign.circle"
onPress={() => handleFilterOption("paid")}
>
Paid Events
</Stack.Header.MenuAction>
</Stack.Header.Menu>
@@ -444,7 +459,8 @@ export default function EventTypesIOS() {
contentContainerStyle={{ paddingBottom: 120 }}
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
showsVerticalScrollIndicator={false}
contentInsetAdjustmentBehavior="automatic">
contentInsetAdjustmentBehavior="automatic"
>
{filteredEventTypes.length === 0 && searchQuery.trim() !== "" ? (
<View className="flex-1 items-center justify-center bg-gray-50 p-5 pt-20">
<EmptyScreen
@@ -482,7 +498,8 @@ export default function EventTypesIOS() {
<Host matchContents>
<ContextMenu
modifiers={[buttonStyle(isLiquidGlassAvailable() ? "glass" : "bordered"), padding()]}
activationMethod="singlePress">
activationMethod="singlePress"
>
<ContextMenu.Items>
<Button systemImage="link" onPress={handleOpenCreateModal} label="New Event Type" />
</ContextMenu.Items>
+12 -5
View File
@@ -88,7 +88,8 @@ export default function More() {
{/* iOS Native Header with Glass UI */}
<Stack.Header
style={{ backgroundColor: "transparent", shadowColor: "transparent" }}
blurEffect={isLiquidGlassAvailable() ? undefined : "light"}>
blurEffect={isLiquidGlassAvailable() ? undefined : "light"}
>
<Stack.Header.Title large>More</Stack.Header.Title>
<Stack.Header.Right>
{userProfile?.avatarUrl ? (
@@ -113,7 +114,8 @@ export default function More() {
style={{ backgroundColor: "#f8f9fa" }}
contentContainerStyle={{ padding: 16, paddingBottom: 120 }}
showsVerticalScrollIndicator={false}
contentInsetAdjustmentBehavior="automatic">
contentInsetAdjustmentBehavior="automatic"
>
<View className="overflow-hidden rounded-lg border border-[#E5E5EA] bg-white">
{menuItems.map((item, index) => (
<TouchableOpacity
@@ -121,7 +123,8 @@ export default function More() {
onPress={item.onPress}
className={`flex-row items-center justify-between bg-white px-5 py-5 active:bg-[#F8F9FA] ${
index < menuItems.length - 1 ? "border-b border-[#E5E5EA]" : ""
}`}>
}`}
>
<View className="flex-1 flex-row items-center">
<Ionicons name={item.icon} size={20} color="#333" />
<Text className="ml-3 text-base font-semibold text-[#333]">{item.name}</Text>
@@ -139,7 +142,8 @@ export default function More() {
<View className="mt-6 overflow-hidden rounded-lg border border-[#E5E5EA] bg-white">
<TouchableOpacity
onPress={handleSignOut}
className="flex-row items-center justify-center bg-white px-5 py-4 active:bg-red-50">
className="flex-row items-center justify-center bg-white px-5 py-4 active:bg-red-50"
>
<Ionicons name="log-out-outline" size={20} color="#800000" />
<Text className="ml-2 text-base font-medium text-[#800000]">Sign Out</Text>
</TouchableOpacity>
@@ -149,7 +153,10 @@ export default function More() {
<Text className="mt-6 px-1 text-center text-xs text-gray-400">
The companion app is an extension of the web application.{"\n"}
For advanced features, visit{" "}
<Text className="text-gray-800" onPress={() => openInAppBrowser("https://app.cal.com", "Cal.com")}>
<Text
className="text-gray-800"
onPress={() => openInAppBrowser("https://app.cal.com", "Cal.com")}
>
app.cal.com
</Text>
</Text>
+51 -15
View File
@@ -21,13 +21,18 @@ function RootLayoutContent() {
headerLargeTitle: false,
title: Platform.OS === "ios" ? "You" : "Profile",
presentation:
Platform.OS === "ios" ? (isLiquidGlassAvailable() ? "formSheet" : "modal") : "containedModal",
Platform.OS === "ios"
? isLiquidGlassAvailable()
? "formSheet"
: "modal"
: "containedModal",
// iOS-specific sheet options (ignored on Android)
sheetGrabberVisible: Platform.OS === "ios",
sheetAllowedDetents: Platform.OS === "ios" ? [0.6, 0.9] : undefined,
sheetInitialDetentIndex: Platform.OS === "ios" ? 0 : undefined,
contentStyle: {
backgroundColor: Platform.OS === "ios" && isLiquidGlassAvailable() ? "transparent" : "#FFFFFF",
backgroundColor:
Platform.OS === "ios" && isLiquidGlassAvailable() ? "transparent" : "#FFFFFF",
},
headerStyle: {
backgroundColor: Platform.OS === "ios" ? "transparent" : "#FFFFFF",
@@ -43,13 +48,18 @@ function RootLayoutContent() {
headerLargeTitle: false,
title: "Session Details",
presentation:
Platform.OS === "ios" ? (isLiquidGlassAvailable() ? "formSheet" : "modal") : "containedModal",
Platform.OS === "ios"
? isLiquidGlassAvailable()
? "formSheet"
: "modal"
: "containedModal",
// iOS-specific sheet options (ignored on Android)
sheetGrabberVisible: Platform.OS === "ios",
sheetAllowedDetents: Platform.OS === "ios" ? [0.7, 0.9] : undefined,
sheetInitialDetentIndex: Platform.OS === "ios" ? 0 : undefined,
contentStyle: {
backgroundColor: Platform.OS === "ios" && isLiquidGlassAvailable() ? "transparent" : "#F2F2F7",
backgroundColor:
Platform.OS === "ios" && isLiquidGlassAvailable() ? "transparent" : "#F2F2F7",
},
headerStyle: {
backgroundColor: Platform.OS === "ios" ? "transparent" : "#F2F2F7",
@@ -65,12 +75,17 @@ function RootLayoutContent() {
headerLargeTitle: false,
title: "Edit Location",
presentation:
Platform.OS === "ios" ? (isLiquidGlassAvailable() ? "formSheet" : "modal") : "containedModal",
Platform.OS === "ios"
? isLiquidGlassAvailable()
? "formSheet"
: "modal"
: "containedModal",
sheetGrabberVisible: Platform.OS === "ios",
sheetAllowedDetents: Platform.OS === "ios" ? [0.5, 0.7] : undefined,
sheetInitialDetentIndex: Platform.OS === "ios" ? 0 : undefined,
contentStyle: {
backgroundColor: Platform.OS === "ios" && isLiquidGlassAvailable() ? "transparent" : "#F2F2F7",
backgroundColor:
Platform.OS === "ios" && isLiquidGlassAvailable() ? "transparent" : "#F2F2F7",
},
headerStyle: {
backgroundColor: Platform.OS === "ios" ? "transparent" : "#F2F2F7",
@@ -86,12 +101,17 @@ function RootLayoutContent() {
headerLargeTitle: false,
title: "Mark No-Show",
presentation:
Platform.OS === "ios" ? (isLiquidGlassAvailable() ? "formSheet" : "modal") : "containedModal",
Platform.OS === "ios"
? isLiquidGlassAvailable()
? "formSheet"
: "modal"
: "containedModal",
sheetGrabberVisible: Platform.OS === "ios",
sheetAllowedDetents: Platform.OS === "ios" ? [0.4, 0.6] : undefined,
sheetInitialDetentIndex: Platform.OS === "ios" ? 0 : undefined,
contentStyle: {
backgroundColor: Platform.OS === "ios" && isLiquidGlassAvailable() ? "transparent" : "#F2F2F7",
backgroundColor:
Platform.OS === "ios" && isLiquidGlassAvailable() ? "transparent" : "#F2F2F7",
},
headerStyle: {
backgroundColor: Platform.OS === "ios" ? "transparent" : "#F2F2F7",
@@ -107,12 +127,17 @@ function RootLayoutContent() {
headerLargeTitle: false,
title: "Recordings",
presentation:
Platform.OS === "ios" ? (isLiquidGlassAvailable() ? "formSheet" : "modal") : "containedModal",
Platform.OS === "ios"
? isLiquidGlassAvailable()
? "formSheet"
: "modal"
: "containedModal",
sheetGrabberVisible: Platform.OS === "ios",
sheetAllowedDetents: Platform.OS === "ios" ? [0.7, 0.9] : undefined,
sheetInitialDetentIndex: Platform.OS === "ios" ? 0 : undefined,
contentStyle: {
backgroundColor: Platform.OS === "ios" && isLiquidGlassAvailable() ? "transparent" : "#F2F2F7",
backgroundColor:
Platform.OS === "ios" && isLiquidGlassAvailable() ? "transparent" : "#F2F2F7",
},
headerStyle: {
backgroundColor: Platform.OS === "ios" ? "transparent" : "#F2F2F7",
@@ -128,12 +153,17 @@ function RootLayoutContent() {
headerLargeTitle: false,
title: "Add Guests",
presentation:
Platform.OS === "ios" ? (isLiquidGlassAvailable() ? "formSheet" : "modal") : "containedModal",
Platform.OS === "ios"
? isLiquidGlassAvailable()
? "formSheet"
: "modal"
: "containedModal",
sheetGrabberVisible: Platform.OS === "ios",
sheetAllowedDetents: Platform.OS === "ios" ? [0.6, 0.8] : undefined,
sheetInitialDetentIndex: Platform.OS === "ios" ? 0 : undefined,
contentStyle: {
backgroundColor: Platform.OS === "ios" && isLiquidGlassAvailable() ? "transparent" : "#F2F2F7",
backgroundColor:
Platform.OS === "ios" && isLiquidGlassAvailable() ? "transparent" : "#F2F2F7",
},
headerStyle: {
backgroundColor: Platform.OS === "ios" ? "transparent" : "#F2F2F7",
@@ -149,12 +179,17 @@ function RootLayoutContent() {
headerLargeTitle: false,
title: "Reschedule",
presentation:
Platform.OS === "ios" ? (isLiquidGlassAvailable() ? "formSheet" : "modal") : "containedModal",
Platform.OS === "ios"
? isLiquidGlassAvailable()
? "formSheet"
: "modal"
: "containedModal",
sheetGrabberVisible: Platform.OS === "ios",
sheetAllowedDetents: Platform.OS === "ios" ? [0.8, 0.95] : undefined,
sheetInitialDetentIndex: Platform.OS === "ios" ? 0 : undefined,
contentStyle: {
backgroundColor: Platform.OS === "ios" && isLiquidGlassAvailable() ? "transparent" : "#F2F2F7",
backgroundColor:
Platform.OS === "ios" && isLiquidGlassAvailable() ? "transparent" : "#F2F2F7",
},
headerStyle: {
backgroundColor: Platform.OS === "ios" ? "transparent" : "#F2F2F7",
@@ -185,7 +220,8 @@ function RootLayoutContent() {
return (
<View
style={[containerStyle, Platform.OS === "web" && { pointerEvents: "auto" as const }]}
className={containerClass}>
className={containerClass}
>
<StatusBar barStyle="dark-content" backgroundColor="#ffffff" />
{content}
<NetworkStatusBanner />
@@ -194,11 +194,15 @@ export const BookingListScreen: React.FC<BookingListScreenProps> = ({
case "upcoming":
case "unconfirmed":
// Sort by start time ascending
return sorted.sort((a, b) => new Date(a.startTime).getTime() - new Date(b.startTime).getTime());
return sorted.sort(
(a, b) => new Date(a.startTime).getTime() - new Date(b.startTime).getTime()
);
case "past":
case "cancelled":
// Sort by start time descending (latest first)
return sorted.sort((a, b) => new Date(b.startTime).getTime() - new Date(a.startTime).getTime());
return sorted.sort(
(a, b) => new Date(b.startTime).getTime() - new Date(a.startTime).getTime()
);
default:
return sorted;
}
@@ -327,10 +331,17 @@ export const BookingListScreen: React.FC<BookingListScreenProps> = ({
contentContainerStyle={{
padding: 20,
}}
refreshControl={<RefreshControl refreshing={isManualRefreshing} onRefresh={manualRefresh} />}
refreshControl={
<RefreshControl refreshing={isManualRefreshing} onRefresh={manualRefresh} />
}
contentInsetAdjustmentBehavior="automatic"
style={{ backgroundColor: "white" }}>
<EmptyScreen icon={emptyState.icon} headline={emptyState.title} description={emptyState.text} />
style={{ backgroundColor: "white" }}
>
<EmptyScreen
icon={emptyState.icon}
headline={emptyState.title}
description={emptyState.text}
/>
</ScrollView>
</View>
</Activity>
@@ -342,9 +353,12 @@ export const BookingListScreen: React.FC<BookingListScreenProps> = ({
contentContainerStyle={{
padding: 20,
}}
refreshControl={<RefreshControl refreshing={isManualRefreshing} onRefresh={manualRefresh} />}
refreshControl={
<RefreshControl refreshing={isManualRefreshing} onRefresh={manualRefresh} />
}
contentInsetAdjustmentBehavior="automatic"
style={{ backgroundColor: "white" }}>
style={{ backgroundColor: "white" }}
>
<EmptyScreen
icon="search-outline"
headline={`No results found for "${searchQuery}"`}
@@ -362,7 +376,9 @@ export const BookingListScreen: React.FC<BookingListScreenProps> = ({
keyExtractor={(item) => item.key}
renderItem={renderListItem}
contentContainerStyle={{ paddingBottom: 90 }}
refreshControl={<RefreshControl refreshing={isManualRefreshing} onRefresh={manualRefresh} />}
refreshControl={
<RefreshControl refreshing={isManualRefreshing} onRefresh={manualRefresh} />
}
showsVerticalScrollIndicator={false}
contentInsetAdjustmentBehavior="automatic"
style={{ backgroundColor: "white" }}
@@ -377,7 +393,9 @@ export const BookingListScreen: React.FC<BookingListScreenProps> = ({
keyExtractor={(item) => item.key}
renderItem={renderListItem}
contentContainerStyle={{ paddingBottom: 90 }}
refreshControl={<RefreshControl refreshing={isManualRefreshing} onRefresh={manualRefresh} />}
refreshControl={
<RefreshControl refreshing={isManualRefreshing} onRefresh={manualRefresh} />
}
showsVerticalScrollIndicator={false}
/>
</View>
@@ -132,7 +132,8 @@ export const AddGuestsScreen = forwardRef<AddGuestsScreenHandle, AddGuestsScreen
return (
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
className={`flex-1 ${backgroundStyle}`}>
className={`flex-1 ${backgroundStyle}`}
>
<ScrollView
className="flex-1"
contentContainerStyle={{
@@ -140,7 +141,8 @@ export const AddGuestsScreen = forwardRef<AddGuestsScreenHandle, AddGuestsScreen
paddingBottom: insets.bottom + 16,
}}
keyboardShouldPersistTaps="handled"
showsVerticalScrollIndicator={!transparentBackground}>
showsVerticalScrollIndicator={!transparentBackground}
>
{/* Email input */}
{transparentBackground && (
<Text className="mb-2 px-1 text-[13px] font-medium text-gray-500">Email *</Text>
@@ -148,7 +150,8 @@ export const AddGuestsScreen = forwardRef<AddGuestsScreenHandle, AddGuestsScreen
<View
className={`mb-3 overflow-hidden rounded-xl px-4 py-3 ${
transparentBackground ? "border border-gray-300/40 bg-white/60" : "bg-white"
}`}>
}`}
>
{!transparentBackground && (
<Text className="mb-1.5 text-[13px] font-medium text-gray-500">Email *</Text>
)}
@@ -172,7 +175,8 @@ export const AddGuestsScreen = forwardRef<AddGuestsScreenHandle, AddGuestsScreen
<View
className={`mb-4 overflow-hidden rounded-xl px-4 py-3 ${
transparentBackground ? "border border-gray-300/40 bg-white/60" : "bg-white"
}`}>
}`}
>
{!transparentBackground && (
<Text className="mb-1.5 text-[13px] font-medium text-gray-500">Name (optional)</Text>
)}
@@ -193,7 +197,8 @@ export const AddGuestsScreen = forwardRef<AddGuestsScreenHandle, AddGuestsScreen
}`}
onPress={handleAddGuest}
activeOpacity={0.7}
disabled={isSaving}>
disabled={isSaving}
>
<Ionicons name="add-circle" size={22} color="#007AFF" />
<Text className="ml-2 text-[17px] font-medium text-[#007AFF]">Add</Text>
</TouchableOpacity>
@@ -207,24 +212,31 @@ export const AddGuestsScreen = forwardRef<AddGuestsScreenHandle, AddGuestsScreen
<View
className={`overflow-hidden rounded-xl ${
transparentBackground ? "border border-gray-300/40 bg-white/60" : "bg-white"
}`}>
}`}
>
{guests.map((guest, index) => (
<View
key={guest.email}
className={`flex-row items-center px-4 py-3 ${
index < guests.length - 1 ? "border-b border-gray-100/50" : ""
}`}>
<View className={`mr-3 h-10 w-10 items-center justify-center rounded-full ${pillStyle}`}>
}`}
>
<View
className={`mr-3 h-10 w-10 items-center justify-center rounded-full ${pillStyle}`}
>
<Ionicons name="person" size={20} color="#6B7280" />
</View>
<View className="flex-1">
<Text className="text-[17px] text-[#000]">{guest.email}</Text>
{guest.name && <Text className="mt-0.5 text-[15px] text-gray-500">{guest.name}</Text>}
{guest.name && (
<Text className="mt-0.5 text-[15px] text-gray-500">{guest.name}</Text>
)}
</View>
<TouchableOpacity
onPress={() => handleRemoveGuest(index)}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
disabled={isSaving}>
disabled={isSaving}
>
<Ionicons name="close-circle-outline" size={24} color="#800020" />
</TouchableOpacity>
</View>
@@ -76,7 +76,10 @@ export interface BookingDetailScreenProps {
}) => void;
}
export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreenProps): React.JSX.Element {
export function BookingDetailScreen({
uid,
onActionsReady,
}: BookingDetailScreenProps): React.JSX.Element {
const router = useRouter();
const insets = useSafeAreaInsets();
@@ -357,13 +360,15 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
paddingTop: 16,
paddingBottom: insets.bottom + 100,
}}
showsVerticalScrollIndicator={false}>
showsVerticalScrollIndicator={false}
>
{/* Title Section - iOS Calendar Style */}
<View className="mb-8">
{/* Meeting Title */}
<Text
className="mb-4 text-[26px] font-semibold leading-tight text-black"
style={{ letterSpacing: -0.3 }}>
style={{ letterSpacing: -0.3 }}
>
{booking.title}
</Text>
@@ -376,7 +381,9 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
)}
{durationFormatted && (
<View className="rounded-full bg-[#E5E5EA] px-2.5 py-1">
<Text className="text-[13px] font-medium text-[#636366]">{durationFormatted}</Text>
<Text className="text-[13px] font-medium text-[#636366]">
{durationFormatted}
</Text>
</View>
)}
</View>
@@ -396,7 +403,8 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
<View className="mb-4 overflow-hidden rounded-xl bg-white">
<AppPressable
className="flex-row items-center justify-between px-4 py-3.5"
onPress={() => setParticipantsExpanded(!participantsExpanded)}>
onPress={() => setParticipantsExpanded(!participantsExpanded)}
>
<Text className="text-[17px] text-black">Participants</Text>
<View className="flex-row items-center">
<Text className="mr-1 text-[17px] text-[#8E8E93]">{totalParticipants}</Text>
@@ -418,7 +426,8 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
key={host.email || `host-${index}`}
className={`flex-row items-center py-2 ${
index > 0 ? "border-t border-[#E5E5EA]" : ""
}`}>
}`}
>
<Ionicons name="star" size={18} color="#FFD60A" />
<Text className="ml-2.5 flex-1 text-[15px] text-black" numberOfLines={1}>
{host.name || host.email || "Host"}
@@ -443,8 +452,11 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
<View
key={attendee.email}
className={`flex-row items-center py-2 ${
index > 0 || booking.hosts?.length || booking.user ? "border-t border-[#E5E5EA]" : ""
}`}>
index > 0 || booking.hosts?.length || booking.user
? "border-t border-[#E5E5EA]"
: ""
}`}
>
<Ionicons name={statusIcon.name} size={20} color={statusIcon.color} />
<Text className="ml-2.5 flex-1 text-[15px] text-black" numberOfLines={1}>
{attendee.name || attendee.email}
@@ -466,7 +478,8 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
index > 0 || booking.attendees?.length || booking.hosts?.length || booking.user
? "border-t border-[#E5E5EA]"
: ""
}`}>
}`}
>
<Ionicons name="person-outline" size={20} color="#8E8E93" />
<Text className="ml-2.5 flex-1 text-[15px] text-[#8E8E93]" numberOfLines={1}>
{guestEmail}
@@ -494,21 +507,23 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
"additionalNotes",
];
const displayableEntries = Object.entries(booking.bookingFieldsResponses).filter(([key, value]) => {
if (excludedKeys.includes(key)) return false;
const displayableEntries = Object.entries(booking.bookingFieldsResponses).filter(
([key, value]) => {
if (excludedKeys.includes(key)) return false;
if (value === null || value === undefined || value === "") return false;
if (value === null || value === undefined || value === "") return false;
if (Array.isArray(value) && value.length === 0) return false;
if (Array.isArray(value) && value.length === 0) return false;
if (typeof value === "object" && !Array.isArray(value) && value !== null) {
const obj = value as Record<string, unknown>;
if ("value" in obj && "optionValue" in obj) return false;
if (Object.keys(obj).length === 0) return false;
if (typeof value === "object" && !Array.isArray(value) && value !== null) {
const obj = value as Record<string, unknown>;
if ("value" in obj && "optionValue" in obj) return false;
if (Object.keys(obj).length === 0) return false;
}
return true;
}
return true;
});
);
if (displayableEntries.length === 0) return null;
@@ -538,7 +553,10 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
.trim();
return (
<View key={key} className={`py-2 ${index > 0 ? "border-t border-[#E5E5EA]" : ""}`}>
<View
key={key}
className={`py-2 ${index > 0 ? "border-t border-[#E5E5EA]" : ""}`}
>
<Text className="mb-0.5 text-[13px] text-[#8E8E93]">{displayKey}</Text>
<Text className="text-[17px] text-black">{displayValue}</Text>
</View>
@@ -583,7 +601,8 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
params: { uid: fromUid },
});
}
}}>
}}
>
<Text className="text-[17px] text-black">Rescheduled from</Text>
<View className="flex-row items-center">
<Text className="mr-1 text-[15px] text-[#007AFF]">View original</Text>
@@ -603,7 +622,8 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
params: { uid },
});
}
}}>
}}
>
<Text className="text-[17px] text-black">Rescheduled to</Text>
<View className="flex-row items-center">
<Text className="mr-1 text-[15px] text-[#007AFF]">View new</Text>
@@ -618,7 +638,8 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
booking.rescheduledFromUid || booking.rescheduledToUid || booking.fromReschedule
? "border-t border-[#E5E5EA]"
: ""
}`}>
}`}
>
<Text className="mb-0.5 text-[13px] text-[#8E8E93]">Reason</Text>
<Text className="text-[17px] text-black">{booking.reschedulingReason}</Text>
</View>
@@ -644,7 +665,9 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
)}
{booking.cancelledByEmail && (
<View className={`py-2 ${booking.cancellationReason ? "border-t border-[#E5E5EA]" : ""}`}>
<View
className={`py-2 ${booking.cancellationReason ? "border-t border-[#E5E5EA]" : ""}`}
>
<Text className="mb-0.5 text-[13px] text-[#8E8E93]">Cancelled by</Text>
<Text className="text-[17px] text-black">{booking.cancelledByEmail}</Text>
</View>
@@ -656,7 +679,8 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
booking.cancellationReason || booking.cancelledByEmail
? "border-t border-[#E5E5EA]"
: ""
}`}>
}`}
>
<Ionicons name="warning" size={18} color="#FF9500" />
<Text className="ml-2 text-[17px] text-black">Host was absent</Text>
</View>
@@ -446,7 +446,8 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
headerRight: () => (
<AppPressable
className="h-10 w-10 items-center justify-center rounded-full"
onPress={() => setShowActionsModal(true)}>
onPress={() => setShowActionsModal(true)}
>
<Ionicons name="ellipsis-horizontal" size={24} color="#000" />
</AppPressable>
),
@@ -478,7 +479,9 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
</View>
<View className="flex-1">
<View className="mb-1 flex-row flex-wrap items-center">
<Text className="text-base font-medium text-[#333]">{booking.user.name}</Text>
<Text className="text-base font-medium text-[#333]">
{booking.user.name}
</Text>
<View className="ml-2 rounded bg-[#007AFF] px-2 py-0.5">
<Text className="text-xs font-medium text-white">host</Text>
</View>
@@ -490,7 +493,8 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
booking.hosts.map((host, hostIndex) => (
<View
key={host.email ?? host.name}
className={`flex-row items-start ${hostIndex > 0 ? "mt-4" : ""}`}>
className={`flex-row items-start ${hostIndex > 0 ? "mt-4" : ""}`}
>
<View className="mr-3 h-12 w-12 items-center justify-center rounded-full bg-black">
<Text className="text-base font-semibold text-white">
{getInitials(host.name || "Host")}
@@ -498,7 +502,9 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
</View>
<View className="flex-1">
<View className="mb-1 flex-row flex-wrap items-center">
<Text className="text-base font-medium text-[#333]">{host.name || "Host"}</Text>
<Text className="text-base font-medium text-[#333]">
{host.name || "Host"}
</Text>
<View className="ml-2 rounded bg-[#007AFF] px-2 py-0.5">
<Text className="text-xs font-medium text-white">host</Text>
</View>
@@ -517,11 +523,15 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
(attendee as { noShow?: boolean; absent?: boolean }).noShow === true ||
(attendee as { noShow?: boolean; absent?: boolean }).absent === true;
return (
<View key={attendee.email} className={`flex-row items-start ${index > 0 ? "mt-4" : ""}`}>
<View
key={attendee.email}
className={`flex-row items-start ${index > 0 ? "mt-4" : ""}`}
>
<View
className={`mr-3 h-12 w-12 items-center justify-center rounded-full ${
isNoShow ? "bg-[#DC2626]" : "bg-black"
}`}>
}`}
>
<Text className="text-base font-semibold text-white">
{getInitials(attendee.name)}
</Text>
@@ -531,13 +541,16 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
<Text
className={`text-base font-medium ${
isNoShow ? "text-[#DC2626]" : "text-[#333]"
}`}>
}`}
>
{attendee.name}
</Text>
{isNoShow && (
<View className="ml-2 flex-row items-center rounded-full bg-[#FEE2E2] px-2 py-0.5">
<Ionicons name="eye-off" size={12} color="#DC2626" />
<Text className="ml-1 text-xs font-medium text-[#DC2626]">No-show</Text>
<Text className="ml-1 text-xs font-medium text-[#DC2626]">
No-show
</Text>
</View>
)}
</View>
@@ -557,7 +570,10 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
<View className="mb-2 rounded-2xl bg-white p-6">
<Text className="mb-4 text-base font-medium text-[#666]">Where</Text>
{locationProvider.url ? (
<AppPressable onPress={handleJoinMeeting} className="flex-row flex-wrap items-center">
<AppPressable
onPress={handleJoinMeeting}
className="flex-row flex-wrap items-center"
>
{locationProvider.iconUrl ? (
<SvgImage
uri={locationProvider.iconUrl}
@@ -588,7 +604,8 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
) : null}
{/* Recurring Event Section */}
{booking.recurringEventId || (booking as { recurringBookingUid?: string }).recurringBookingUid ? (
{booking.recurringEventId ||
(booking as { recurringBookingUid?: string }).recurringBookingUid ? (
<View className="mb-2 rounded-2xl bg-white p-6">
<Text className="mb-2 text-base font-medium text-[#666]">Recurring Event</Text>
<Text className="text-base text-[#666]">Every 2 weeks for 6 occurrences</Text>
@@ -607,11 +624,19 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
{locationProvider?.url ? (
<AppPressable
onPress={handleJoinMeeting}
className="mb-2 flex-row items-center justify-center rounded-lg bg-black px-6 py-4">
className="mb-2 flex-row items-center justify-center rounded-lg bg-black px-6 py-4"
>
{locationProvider.iconUrl ? (
<SvgImage uri={locationProvider.iconUrl} width={20} height={20} style={{ marginRight: 8 }} />
<SvgImage
uri={locationProvider.iconUrl}
width={20}
height={20}
style={{ marginRight: 8 }}
/>
) : null}
<Text className="text-base font-semibold text-white">Join {locationProvider.label}</Text>
<Text className="text-base font-semibold text-white">
Join {locationProvider.label}
</Text>
</AppPressable>
) : null}
</ScrollView>
@@ -639,7 +664,9 @@ export function BookingDetailScreen({ uid, onActionsReady }: BookingDetailScreen
<View className="absolute inset-0 items-center justify-center bg-black/50">
<View className="rounded-2xl bg-white px-8 py-6">
<ActivityIndicator size="large" color="#000" />
<Text className="mt-3 text-base font-medium text-gray-700">Cancelling booking...</Text>
<Text className="mt-3 text-base font-medium text-gray-700">
Cancelling booking...
</Text>
</View>
</View>
)}
@@ -69,7 +69,11 @@ const detectLocationType = (location: string): LocationTypeId => {
if (!location) return "link";
// Check if it's a URL
if (location.startsWith("http://") || location.startsWith("https://") || location.startsWith("www.")) {
if (
location.startsWith("http://") ||
location.startsWith("https://") ||
location.startsWith("www.")
) {
return "link";
}
@@ -84,7 +88,10 @@ const detectLocationType = (location: string): LocationTypeId => {
};
export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocationScreenProps>(
function EditLocationScreen({ booking, onSuccess, onSavingChange, transparentBackground = false }, ref) {
function EditLocationScreen(
{ booking, onSuccess, onSavingChange, transparentBackground = false },
ref
) {
const insets = useSafeAreaInsets();
const backgroundStyle = transparentBackground ? "bg-transparent" : "bg-[#F2F2F7]";
const [selectedType, setSelectedType] = useState<LocationTypeId>("link");
@@ -155,7 +162,9 @@ export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocat
setIsSaving(true);
try {
await CalComAPIService.updateLocationV2(booking.uid, locationPayload);
Alert.alert("Success", "Location updated successfully", [{ text: "OK", onPress: onSuccess }]);
Alert.alert("Success", "Location updated successfully", [
{ text: "OK", onPress: onSuccess },
]);
setIsSaving(false);
} catch (error) {
safeLogError("[EditLocationScreen] Failed to update location:", error);
@@ -190,7 +199,8 @@ export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocat
paddingBottom: insets.bottom + 16,
}}
keyboardShouldPersistTaps="handled"
showsVerticalScrollIndicator={!transparentBackground}>
showsVerticalScrollIndicator={!transparentBackground}
>
{transparentBackground ? (
<>
{/* Location Type Selector with Native Context Menu - Glass UI */}
@@ -199,15 +209,23 @@ export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocat
<Ionicons name={selectedTypeConfig.iconName} size={20} color="#007AFF" />
</View>
<View className="flex-1">
<Text className="text-[17px] font-medium text-[#000]">{selectedTypeConfig.label}</Text>
<Text className="mt-0.5 text-[13px] text-gray-500">{selectedTypeConfig.description}</Text>
<Text className="text-[17px] font-medium text-[#000]">
{selectedTypeConfig.label}
</Text>
<Text className="mt-0.5 text-[13px] text-gray-500">
{selectedTypeConfig.description}
</Text>
</View>
{/* Native iOS Context Menu Button */}
<Host matchContents>
<ContextMenu
modifiers={[buttonStyle(isLiquidGlassAvailable() ? "glass" : "bordered"), padding()]}
activationMethod="singlePress">
modifiers={[
buttonStyle(isLiquidGlassAvailable() ? "glass" : "bordered"),
padding(),
]}
activationMethod="singlePress"
>
<ContextMenu.Items>
<Button
systemImage={LOCATION_TYPES.link.sfSymbol}
@@ -251,7 +269,9 @@ export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocat
onChangeText={setInputValue}
keyboardType={selectedTypeConfig.keyboardType}
multiline={selectedTypeConfig.inputType === "multiline"}
textAlignVertical={selectedTypeConfig.inputType === "multiline" ? "top" : "center"}
textAlignVertical={
selectedTypeConfig.inputType === "multiline" ? "top" : "center"
}
autoCapitalize={selectedType === "link" ? "none" : "sentences"}
autoCorrect={selectedType !== "link" && selectedType !== "phone"}
editable={!isSaving}
@@ -284,15 +304,23 @@ export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocat
<Ionicons name={selectedTypeConfig.iconName} size={20} color="#007AFF" />
</View>
<View className="flex-1">
<Text className="text-[17px] font-medium text-[#000]">{selectedTypeConfig.label}</Text>
<Text className="mt-0.5 text-[13px] text-gray-500">{selectedTypeConfig.description}</Text>
<Text className="text-[17px] font-medium text-[#000]">
{selectedTypeConfig.label}
</Text>
<Text className="mt-0.5 text-[13px] text-gray-500">
{selectedTypeConfig.description}
</Text>
</View>
{/* Native iOS Context Menu Button */}
<Host matchContents>
<ContextMenu
modifiers={[buttonStyle(isLiquidGlassAvailable() ? "glass" : "bordered"), padding()]}
activationMethod="singlePress">
modifiers={[
buttonStyle(isLiquidGlassAvailable() ? "glass" : "bordered"),
padding(),
]}
activationMethod="singlePress"
>
<ContextMenu.Items>
<Button
systemImage={LOCATION_TYPES.link.sfSymbol}
@@ -339,7 +367,9 @@ export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocat
onChangeText={setInputValue}
keyboardType={selectedTypeConfig.keyboardType}
multiline={selectedTypeConfig.inputType === "multiline"}
textAlignVertical={selectedTypeConfig.inputType === "multiline" ? "top" : "center"}
textAlignVertical={
selectedTypeConfig.inputType === "multiline" ? "top" : "center"
}
autoCapitalize={selectedType === "link" ? "none" : "sentences"}
autoCorrect={selectedType !== "link" && selectedType !== "phone"}
editable={!isSaving}
@@ -86,7 +86,11 @@ export interface EditLocationScreenHandle {
const detectLocationType = (location: string): LocationTypeId => {
if (!location) return "link";
if (location.startsWith("http://") || location.startsWith("https://") || location.startsWith("www.")) {
if (
location.startsWith("http://") ||
location.startsWith("https://") ||
location.startsWith("www.")
) {
return "link";
}
@@ -99,7 +103,10 @@ const detectLocationType = (location: string): LocationTypeId => {
};
export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocationScreenProps>(
function EditLocationScreen({ booking, onSuccess, onSavingChange, transparentBackground = false }, ref) {
function EditLocationScreen(
{ booking, onSuccess, onSavingChange, transparentBackground = false },
ref
) {
const insets = useSafeAreaInsets();
const backgroundStyle = transparentBackground ? "bg-transparent" : "bg-[#F2F2F7]";
const pillStyle = transparentBackground ? "bg-[#E8E8ED]/50" : "bg-[#E8E8ED]";
@@ -160,7 +167,9 @@ export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocat
setIsSaving(true);
try {
await CalComAPIService.updateLocationV2(booking.uid, locationPayload);
Alert.alert("Success", "Location updated successfully", [{ text: "OK", onPress: onSuccess }]);
Alert.alert("Success", "Location updated successfully", [
{ text: "OK", onPress: onSuccess },
]);
setIsSaving(false);
} catch (error) {
safeLogError("[EditLocationScreen] Failed to update location:", error);
@@ -189,7 +198,8 @@ export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocat
<>
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
className={`flex-1 ${backgroundStyle}`}>
className={`flex-1 ${backgroundStyle}`}
>
<ScrollView
className="flex-1"
contentContainerStyle={{
@@ -197,11 +207,14 @@ export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocat
paddingBottom: insets.bottom + 16,
}}
keyboardShouldPersistTaps="handled"
showsVerticalScrollIndicator={!transparentBackground}>
showsVerticalScrollIndicator={!transparentBackground}
>
{/* Current Location Info - hidden in transparent mode */}
{!transparentBackground && booking.location && (
<View className="mb-4 flex-row items-start rounded-xl bg-white p-4">
<View className={`mr-3 h-10 w-10 items-center justify-center rounded-full ${pillStyle}`}>
<View
className={`mr-3 h-10 w-10 items-center justify-center rounded-full ${pillStyle}`}
>
<Ionicons name="location" size={20} color="#6B7280" />
</View>
<View className="flex-1">
@@ -227,16 +240,22 @@ export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocat
}
onPress={() => setShowTypePicker(true)}
disabled={isSaving}
activeOpacity={0.7}>
activeOpacity={0.7}
>
<View
className={`mr-3 h-10 w-10 items-center justify-center rounded-lg ${
transparentBackground ? "bg-[#007AFF]/20" : "bg-[#007AFF]/15"
}`}>
}`}
>
<Ionicons name={selectedTypeConfig.iconName} size={22} color="#007AFF" />
</View>
<View className="flex-1">
<Text className="text-[17px] font-medium text-[#000]">{selectedTypeConfig.label}</Text>
<Text className="mt-0.5 text-[13px] text-gray-500">{selectedTypeConfig.description}</Text>
<Text className="text-[17px] font-medium text-[#000]">
{selectedTypeConfig.label}
</Text>
<Text className="mt-0.5 text-[13px] text-gray-500">
{selectedTypeConfig.description}
</Text>
</View>
<Ionicons name="chevron-down" size={20} color="#9CA3AF" />
</TouchableOpacity>
@@ -252,7 +271,8 @@ export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocat
transparentBackground
? "mb-4 overflow-hidden rounded-xl border border-gray-300/40 bg-white/60"
: "mb-4 overflow-hidden rounded-xl bg-white"
}>
}
>
<TextInput
className={`px-4 py-3 text-[17px] text-[#000] ${
selectedTypeConfig.inputType === "multiline" ? "min-h-[100px]" : "h-[50px]"
@@ -277,14 +297,17 @@ export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocat
visible={showTypePicker}
transparent
animationType="fade"
onRequestClose={() => setShowTypePicker(false)}>
onRequestClose={() => setShowTypePicker(false)}
>
<TouchableOpacity
className="flex-1 items-center justify-center bg-black/50"
activeOpacity={1}
onPress={() => setShowTypePicker(false)}>
onPress={() => setShowTypePicker(false)}
>
<TouchableOpacity
activeOpacity={1}
className="max-h-[70%] w-[320px] overflow-hidden rounded-2xl bg-white">
className="max-h-[70%] w-[320px] overflow-hidden rounded-2xl bg-white"
>
<View className="border-b border-gray-200 px-4 py-3">
<Text className="text-center text-[17px] font-semibold text-[#000]">
Select Location Type
@@ -304,18 +327,25 @@ export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocat
setInputValue("");
}
setShowTypePicker(false);
}}>
}}
>
<View
className={`mr-3 h-10 w-10 items-center justify-center rounded-lg ${
isSelected ? "bg-[#007AFF]/20" : "bg-[#F2F2F7]"
}`}>
<Ionicons name={item.iconName} size={22} color={isSelected ? "#007AFF" : "#6B7280"} />
}`}
>
<Ionicons
name={item.iconName}
size={22}
color={isSelected ? "#007AFF" : "#6B7280"}
/>
</View>
<View className="flex-1">
<Text
className={`text-[17px] ${
isSelected ? "font-semibold text-[#007AFF]" : "text-[#000]"
}`}>
}`}
>
{item.label}
</Text>
<Text className="mt-0.5 text-[13px] text-gray-500">{item.description}</Text>
@@ -327,7 +357,8 @@ export const EditLocationScreen = forwardRef<EditLocationScreenHandle, EditLocat
/>
<TouchableOpacity
className="border-t border-gray-200 py-3"
onPress={() => setShowTypePicker(false)}>
onPress={() => setShowTypePicker(false)}
>
<Text className="text-center text-[17px] font-semibold text-[#007AFF]">Cancel</Text>
</TouchableOpacity>
</TouchableOpacity>
@@ -145,7 +145,11 @@ export function MarkNoShowScreen({
const isLast = index === safeAttendees.length - 1;
// For transparent mode (iOS glass UI), use consistent styling regardless of no-show state
const itemBgStyle = transparentBackground ? "bg-white/60" : isNoShow ? "bg-[#FEF2F2]" : "bg-white";
const itemBgStyle = transparentBackground
? "bg-white/60"
: isNoShow
? "bg-[#FEF2F2]"
: "bg-white";
return (
<TouchableOpacity
@@ -158,15 +162,18 @@ export function MarkNoShowScreen({
} ${itemBgStyle}`}
onPress={() => handleMarkNoShow(item)}
disabled={isProcessing}
activeOpacity={0.7}>
activeOpacity={0.7}
>
<View
className={`mr-3 h-12 w-12 items-center justify-center rounded-full ${
transparentBackground ? "bg-[#000]" : isNoShow ? "bg-[#FECACA]" : pillStyle
}`}>
}`}
>
<Text
className={`text-[16px] font-semibold ${
transparentBackground ? "text-white" : isNoShow ? "text-[#DC2626]" : "text-gray-600"
}`}>
}`}
>
{getInitials(item.name)}
</Text>
</View>
@@ -186,15 +193,20 @@ export function MarkNoShowScreen({
<View className="flex-row items-center">
<View
className={`flex-row items-center rounded-full px-3.5 py-2 ${
isNoShow ? "border border-[#16A34A] bg-white" : "border border-[#FEE2E2] bg-[#FEE2E2]"
}`}>
isNoShow
? "border border-[#16A34A] bg-white"
: "border border-[#FEE2E2] bg-[#FEE2E2]"
}`}
>
<Ionicons
name={isNoShow ? "eye" : "eye-off"}
size={15}
color={isNoShow ? "#16A34A" : "#DC2626"}
style={{ marginRight: 5 }}
/>
<Text className={`text-[14px] font-semibold ${isNoShow ? "text-[#16A34A]" : "text-[#DC2626]"}`}>
<Text
className={`text-[14px] font-semibold ${isNoShow ? "text-[#16A34A]" : "text-[#DC2626]"}`}
>
{isNoShow ? "Unmark" : "Mark"}
</Text>
</View>
@@ -57,12 +57,14 @@ export function MeetingSessionDetailsScreen({
<View
className={`mb-4 overflow-hidden rounded-xl ${
transparentBackground ? "border border-gray-300/40 bg-white/60" : "bg-white"
}`}>
}`}
>
{/* Session header */}
<View
className={`flex-row items-center justify-between p-4 ${
transparentBackground ? "" : "border-b border-gray-100"
}`}>
}`}
>
<View className="flex-row items-center">
<View className={`mr-3 h-10 w-10 items-center justify-center rounded-full ${pillStyle}`}>
<Ionicons name="videocam" size={20} color="#6B7280" />
@@ -73,7 +75,9 @@ export function MeetingSessionDetailsScreen({
</View>
{item.duration && (
<View className={`rounded-full px-3 py-1 ${pillStyle}`}>
<Text className="text-[13px] font-medium text-gray-600">{formatDuration(item.duration)}</Text>
<Text className="text-[13px] font-medium text-gray-600">
{formatDuration(item.duration)}
</Text>
</View>
)}
</View>
@@ -82,18 +86,24 @@ export function MeetingSessionDetailsScreen({
<View className="p-4">
<View className="mb-2 flex-row items-center">
<Ionicons name="time-outline" size={18} color="#8E8E93" />
<Text className="ml-2 text-[15px] text-gray-600">Started: {formatDate(item.startTime)}</Text>
<Text className="ml-2 text-[15px] text-gray-600">
Started: {formatDate(item.startTime)}
</Text>
</View>
{item.endTime && (
<View className="mb-2 flex-row items-center">
<Ionicons name="time-outline" size={18} color="#8E8E93" />
<Text className="ml-2 text-[15px] text-gray-600">Ended: {formatTime(item.endTime)}</Text>
<Text className="ml-2 text-[15px] text-gray-600">
Ended: {formatTime(item.endTime)}
</Text>
</View>
)}
{item.maxParticipants && (
<View className="flex-row items-center">
<Ionicons name="people-outline" size={18} color="#8E8E93" />
<Text className="ml-2 text-[15px] text-gray-600">Max participants: {item.maxParticipants}</Text>
<Text className="ml-2 text-[15px] text-gray-600">
Max participants: {item.maxParticipants}
</Text>
</View>
)}
</View>
@@ -109,8 +119,11 @@ export function MeetingSessionDetailsScreen({
key={participant.id || pIndex}
className={`mb-2 flex-row items-center p-3 ${
transparentBackground ? "" : "rounded-xl bg-[#F2F2F7]"
}`}>
<View className={`mr-3 h-9 w-9 items-center justify-center rounded-full ${pillStyle}`}>
}`}
>
<View
className={`mr-3 h-9 w-9 items-center justify-center rounded-full ${pillStyle}`}
>
<Ionicons name="person" size={18} color="#6B7280" />
</View>
<View className="flex-1">
@@ -59,7 +59,8 @@ export function ViewRecordingsScreen({
transparentBackground ? "border border-gray-300/40 bg-white/60" : "bg-white"
}`}
onPress={() => handleOpenRecording(item)}
activeOpacity={0.7}>
activeOpacity={0.7}
>
<View className="flex-row items-center p-4">
<View className={`mr-3 h-10 w-10 items-center justify-center rounded-full ${pillStyle}`}>
<Ionicons name="videocam" size={20} color="#6B7280" />
@@ -84,7 +85,9 @@ export function ViewRecordingsScreen({
<View className={`mb-4 h-16 w-16 items-center justify-center rounded-full ${pillStyle}`}>
<Ionicons name="videocam-off" size={32} color="#8E8E93" />
</View>
<Text className="text-center text-[17px] font-semibold text-[#000]">No recordings available</Text>
<Text className="text-center text-[17px] font-semibold text-[#000]">
No recordings available
</Text>
<Text className="mt-2 text-center text-[15px] leading-5 text-gray-500">
Recordings may take some time to process after the meeting ends.
</Text>
+27 -1
View File
@@ -130,7 +130,33 @@
"dayjs@^1.8.29": "patch:dayjs@npm%3A1.11.4#./.yarn/patches/dayjs-npm-1.11.4-97921cd375.patch",
"import-in-the-middle": "1.13.1",
"react@19.2.0": "19.2.2",
"react@19.2.1": "19.2.2"
"react@19.2.1": "19.2.2",
"tar-fs": "2.1.4",
"rollup": "4.22.4",
"jpeg-js": "0.4.4",
"validator": "13.15.22",
"form-data": "4.0.4",
"axios": "1.13.2",
"jws": "4.0.1",
"jsonwebtoken": "9.0.0"
},
"packageExtensions": {
"@boxyhq/saml-jackson@*": {
"dependencies": {
"typeorm": "0.3.27",
"node-forge": "1.3.2"
}
},
"lingo.dev@*": {
"dependencies": {
"@modelcontextprotocol/sdk": "1.24.0"
}
},
"ink@3.2.0": {
"dependencies": {
"ws": "7.5.10"
}
}
},
"engines": {
"npm": ">=7.0.0",
+1 -1
View File
@@ -45,6 +45,6 @@
"devDependencies": {
"@testing-library/react-hooks": "8.0.1",
"@types/web-push": "3.6.3",
"trigger.dev": "4.1.0"
"trigger.dev": "4.3.1"
}
}
+1 -1
View File
@@ -84,7 +84,7 @@
"clsx": "2.1.1",
"dompurify": "3.3.1",
"marked": "15.0.6",
"react-use": "17.5.0",
"react-use": "17.6.0",
"tailwind-merge": "1.13.2",
"tailwindcss": "4.1.17"
},
+1 -1
View File
@@ -14,7 +14,7 @@
"@calcom/platform-constants": "workspace:*",
"@calcom/platform-enums": "workspace:*",
"@nestjs/common": "10.4.20",
"@nestjs/swagger": "7.3.0",
"@nestjs/swagger": "7.4.2",
"class-transformer": "0.5.1",
"class-validator": "0.14.3",
"libphonenumber-js": "1.10.49",
+391 -688
View File
File diff suppressed because it is too large. Load diff