1import { spacing } from '@expo/styleguide-native'; 2import { StackScreenProps } from '@react-navigation/stack'; 3import dedent from 'dedent'; 4import { Divider, Spacer, Text, useExpoTheme, View } from 'expo-dev-client-components'; 5import * as React from 'react'; 6import { ActivityIndicator } from 'react-native'; 7 8import { ConstantItem } from '../../components/ConstantItem'; 9import ScrollView from '../../components/NavigationScrollView'; 10import ShareProjectButton from '../../components/ShareProjectButton'; 11import { WebContainerProjectPage_Query } from '../../graphql/types'; 12import { HomeStackRoutes } from '../../navigation/Navigation.types'; 13import { EASUpdateLaunchSection } from './EASUpdateLaunchSection'; 14import { EmptySection } from './EmptySection'; 15import { LegacyLaunchSection } from './LegacyLaunchSection'; 16import { ProjectHeader } from './ProjectHeader'; 17 18const ERROR_TEXT = dedent` 19 An unexpected error has occurred. 20 Sorry about this. We will resolve the issue as soon as possible. 21`; 22 23type Props = { 24 loading: boolean; 25 error?: Error; 26 data?: WebContainerProjectPage_Query; 27} & StackScreenProps<HomeStackRoutes, 'ProjectDetails'>; 28 29type ProjectPageApp = WebContainerProjectPage_Query['app']['byId']; 30 31export function ProjectView({ loading, error, data, navigation }: Props) { 32 const theme = useExpoTheme(); 33 34 let contents; 35 if (error && !data?.app?.byId) { 36 console.log(error); 37 contents = ( 38 <Text 39 align="center" 40 style={{ marginBottom: spacing[4], marginHorizontal: spacing[4] }} 41 type="InterRegular"> 42 {ERROR_TEXT} 43 </Text> 44 ); 45 } else if (loading || !data?.app?.byId) { 46 contents = ( 47 <View flex="1" align="centered"> 48 <ActivityIndicator size="large" color={theme.highlight.accent} /> 49 </View> 50 ); 51 } else { 52 const app = data.app.byId; 53 54 contents = ( 55 <ScrollView style={{ flex: 1 }}> 56 <ProjectHeader app={app} /> 57 <View padding="medium"> 58 {appHasLegacyUpdate(app) && <LegacyLaunchSection app={app} />} 59 {appHasEASUpdates(app) && <EASUpdateLaunchSection app={app} />} 60 {!appHasLegacyUpdate(app) && !appHasEASUpdates(app) && <EmptySection />} 61 <Spacer.Vertical size="xl" /> 62 <View bg="default" border="default" overflow="hidden" rounded="large"> 63 <ConstantItem title="Owner" value={app.username} /> 64 <Divider style={{ height: 1 }} /> 65 <ConstantItem title="SDK Version" value={app.sdkVersion} /> 66 </View> 67 </View> 68 </ScrollView> 69 ); 70 } 71 72 React.useEffect(() => { 73 if (data?.app?.byId) { 74 const fullName = data?.app.byId.fullName; 75 const title = data?.app.byId.name ?? fullName; 76 navigation.setOptions({ 77 title, 78 headerRight: () => <ShareProjectButton fullName={fullName} />, 79 }); 80 } 81 }, [navigation, data?.app?.byId]); 82 83 return <View flex="1">{contents}</View>; 84} 85 86function appHasLegacyUpdate(app: ProjectPageApp): boolean { 87 return app.published; 88} 89 90function appHasEASUpdates(app: ProjectPageApp): boolean { 91 return app.updateBranches.some((branch) => branch.updates.length > 0); 92} 93