Files
calendar/companion/components/LocationsListIOSPicker.ios.tsx
Dhairyashil ShindeGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
478ca05246 feat(companion): update Android booking detail page to match iOS design (#26715)
* feat(companion): update Android booking detail page to match iOS design

* feat(companion): add video icon button to Android header for join meeting

* fix(companion): use eventType.description instead of booking.description

Address Cubic AI review feedback - the booking description may contain
Additional Notes which can cause duplicate display. The event type
description is the proper source for this information.

Co-Authored-By: unknown <>

* Revert "fix(companion): use eventType.description instead of booking.description"

This reverts commit 3e324313f2d72704ab51f723a52b2784b33e7867.

* fix(companion): extract IOSPickerTrigger to platform-specific files for web compatibility

* fix(companion): extract iOS pickers to platform-specific files for web compatibility

Extract iOS-only native picker components from AvailabilityTab, BasicsTab,
LimitsTab, RecurringTab, and LocationsList to platform-specific files to
fix 'requireNativeViewManager is not available on web' error in browser extension.

Each tab now has:
- TabIOSPicker.ios.tsx - iOS implementation with native @expo/ui/swift-ui
- TabIOSPicker.tsx - Web/Android fallback that returns null

* fix(companion): fix Switch toggle thumb color for web/extension

Change thumbColor condition from Platform.OS === 'android' to
Platform.OS !== 'ios' so that web/extension also gets white thumb color
instead of the default green.

* fix(companion): fix Participants section padding for web/extension

Move padding classes from AppPressable to a child View to ensure
padding is properly applied on web. AnimatedPressable doesn't
reliably apply className padding on web platforms.

* fix(companion): fix unexpected text node error on web

Change ternary operator in Hosts section from 'booking.user && (...)' to
'booking.user ? (...) : null' to prevent React Native Web from trying
to render 'false' as a text node when booking.user is falsy.

* fix(companion): wrap Stack.Header in iOS platform check for web compatibility

The Stack.Header components are iOS-specific and cause 'Unexpected text node'
errors on web. Wrap them in Platform.OS === 'ios' check to prevent rendering
on web/Android where they're not supported.

* fix(companion): convert all && conditionals to ternary operators for web compatibility

React Native Web renders boolean 'false' from && operators as text nodes.
Changed all conditional rendering patterns from 'condition && (<Component>)'
to 'condition ? (<Component>) : null' to prevent 'Unexpected text node' errors.

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-11 16:02:13 -03:00

72 lines
2.1 KiB
TypeScript

import { Button, ContextMenu, Host } from "@expo/ui/swift-ui";
import { buttonStyle } from "@expo/ui/swift-ui/modifiers";
import { isLiquidGlassAvailable } from "expo-glass-effect";
import type React from "react";
import type { LocationItem, LocationOptionGroup } from "@/types/locations";
const getSFSymbolForType = (type: string) => {
switch (type) {
case "address":
return "mappin.and.ellipse";
case "link":
return "link";
case "phone":
return "phone";
default:
return "video";
}
};
function isLocationAlreadyAdded(locations: LocationItem[], optionValue: string): boolean {
return locations.some((loc) => {
if (loc.type === "integration" && optionValue.startsWith("integrations:")) {
return loc.integration === optionValue.replace("integrations:", "");
}
if (["address", "link", "phone"].includes(loc.type)) {
return false;
}
return loc.type === optionValue;
});
}
interface LocationsListIOSPickerProps {
isHeader?: boolean;
locationOptions: LocationOptionGroup[];
locations: LocationItem[];
onSelectOption: (value: string, label: string) => void;
trigger: React.ReactNode;
}
export function LocationsListIOSPicker({
isHeader = false,
locationOptions,
locations,
onSelectOption,
trigger,
}: LocationsListIOSPickerProps) {
return (
<Host matchContents>
<ContextMenu
modifiers={!isHeader ? [buttonStyle(isLiquidGlassAvailable() ? "glass" : "bordered")] : []}
activationMethod="singlePress"
>
<ContextMenu.Items>
{locationOptions.flatMap((group) =>
group.options
.filter((opt) => !isLocationAlreadyAdded(locations, opt.value))
.map((option) => (
<Button
key={option.value}
onPress={() => onSelectOption(option.value, option.label)}
label={option.label}
systemImage={getSFSymbolForType(option.value)}
/>
))
)}
</ContextMenu.Items>
<ContextMenu.Trigger>{trigger}</ContextMenu.Trigger>
</ContextMenu>
</Host>
);
}