Files
calendar/companion/components/Header.tsx
T
Dhairyashil ShindeandGitHub 49ae10149f feat(companion): iOS native UI components and simplified event type creation (#26240)
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
2025-12-28 18:48:48 -03:00

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>
);
}