ios: https://github.com/user-attachments/assets/efdfd3e3-239f-4cbf-be1a-7784d1df1851 android: https://github.com/user-attachments/assets/a8e22a5c-60f3-4fb6-8923-b8a786bceb0c ## Overview This PR introduces native iOS UI components, refactors the profile menu, and simplifies the event type creation flow for a more native iOS experience. ## Key Changes ### iOS Native UI Components - **iOS-specific Event Types Page**: Added native Stack.Header, glass UI, and context menus for iOS - **Platform-specific Profile Sheet**: Created separate implementations for iOS (formSheet) and Android/Web (modal) - **Bottom Glass UI Navbar**: Updated bottom navigation bar with glass UI styling for iOS - **Native iOS Alerts**: Replaced custom modals with native `Alert.prompt` for event types and availability pages ### Profile Menu Refactor - Restructured More page with folder layout and native iOS header support - Added profile button to More page header on iOS with glass UI - Added "Copy public page link" and "Roadmap" options to profile sheet - Refactored Header component: removed inline profile modal, now uses route-based navigation - Updated Availability page with New menu and profile button in header - Fixed "My Settings" URL to use `/general` endpoint - Removed "Profile" item from More section menu - Updated tab layout to support `(more)` folder structure ### Simplified Event Type Creation - Reduced event type creation to only require title input - Auto-generate slug from title using slugify utility - Set default duration to 15 minutes - Leave description empty (users can edit later) - Applied to both iOS and Android/Web platforms ### UI Improvements - Updated login button styling: changed background color to pure black (#000000) with white text for better contrast
79 lines
2.7 KiB
TypeScript
79 lines
2.7 KiB
TypeScript
import { Ionicons } from "@expo/vector-icons";
|
|
import { useRouter } from "expo-router";
|
|
import { useCallback, useEffect, useState } from "react";
|
|
import { ActivityIndicator, Image, Platform, TouchableOpacity, View } from "react-native";
|
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
import { CalComAPIService, type UserProfile } from "@/services/calcom";
|
|
import { getAvatarUrl } from "@/utils/getAvatarUrl";
|
|
import { CalComLogo } from "./CalComLogo";
|
|
|
|
export function Header() {
|
|
const router = useRouter();
|
|
const insets = useSafeAreaInsets();
|
|
const [userProfile, setUserProfile] = useState<UserProfile | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
const fetchUserProfile = useCallback(async () => {
|
|
try {
|
|
const profile = await CalComAPIService.getUserProfile();
|
|
setUserProfile(profile);
|
|
setLoading(false);
|
|
} catch (err) {
|
|
console.error("Failed to fetch user profile");
|
|
if (__DEV__) {
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
const stack = err instanceof Error ? err.stack : undefined;
|
|
console.debug("[Header] fetchUserProfile failed", { message, stack });
|
|
}
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
fetchUserProfile();
|
|
}, [fetchUserProfile]);
|
|
|
|
const handleProfile = () => {
|
|
// Navigate to profile sheet on all platforms (Android, Web, Extension)
|
|
router.push("/profile-sheet");
|
|
};
|
|
|
|
return (
|
|
<View
|
|
className="flex-row items-center justify-between border-b border-[#E5E5EA] bg-white px-2 md:px-4"
|
|
style={{ paddingTop: insets.top + 4, paddingBottom: 4 }}
|
|
>
|
|
{/* Left: Cal.com Logo */}
|
|
<View className="ms-1">
|
|
<CalComLogo width={101} height={22} color="#333" />
|
|
</View>
|
|
|
|
{/* Right: Icons */}
|
|
<View
|
|
className="flex-row items-center gap-4"
|
|
style={Platform.OS === "web" ? { marginRight: 8 } : {}}
|
|
>
|
|
{/* Profile Picture */}
|
|
<TouchableOpacity onPress={handleProfile} className="p-1">
|
|
{loading ? (
|
|
<ActivityIndicator size="small" color="#666" />
|
|
) : userProfile?.avatarUrl ? (
|
|
<Image
|
|
source={{ uri: getAvatarUrl(userProfile.avatarUrl) }}
|
|
className="h-8 w-8 rounded-full"
|
|
style={{ width: 32, height: 32, borderRadius: 16 }}
|
|
/>
|
|
) : (
|
|
<View
|
|
className="items-center justify-center rounded-full bg-[#E5E5EA]"
|
|
style={{ width: 32, height: 32 }}
|
|
>
|
|
<Ionicons name="person-outline" size={20} color="#666" />
|
|
</View>
|
|
)}
|
|
</TouchableOpacity>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|