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 { EASUpdateLaunchSection } from './EASUpdateLaunchSection';
9import { EmptySection } from './EmptySection';
10import { LegacyLaunchSection } from './LegacyLaunchSection';
11import { ProjectHeader } from './ProjectHeader';
12import { ConstantItem } from '../../components/ConstantItem';
13import ScrollView from '../../components/NavigationScrollView';
14import ShareProjectButton from '../../components/ShareProjectButton';
15import { WebContainerProjectPage_Query } from '../../graphql/types';
16import { HomeStackRoutes } from '../../navigation/Navigation.types';
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          {appHasEASUpdates(app) && (
59            <>
60              <EASUpdateLaunchSection app={app} />
61              <Spacer.Vertical size="xl" />
62            </>
63          )}
64          {appHasLegacyUpdate(app) && (
65            <>
66              <LegacyLaunchSection app={app} />
67              <Spacer.Vertical size="xl" />
68            </>
69          )}
70          {!appHasLegacyUpdate(app) && !appHasEASUpdates(app) && (
71            <>
72              <EmptySection />
73              <Spacer.Vertical size="xl" />
74            </>
75          )}
76          <View bg="default" border="default" overflow="hidden" rounded="large">
77            <ConstantItem title="Owner" value={app.username} />
78            {app.sdkVersion !== '0.0.0' && (
79              <>
80                <Divider style={{ height: 1 }} />
81                <ConstantItem title="SDK Version" value={app.sdkVersion} />
82              </>
83            )}
84            {app.latestReleaseForReleaseChannel?.runtimeVersion && (
85              <>
86                <Divider style={{ height: 1 }} />
87                <ConstantItem
88                  title="Runtime Version"
89                  value={app.latestReleaseForReleaseChannel?.runtimeVersion}
90                />
91              </>
92            )}
93          </View>
94        </View>
95      </ScrollView>
96    );
97  }
98
99  React.useEffect(() => {
100    if (data?.app?.byId) {
101      const fullName = data?.app.byId.fullName;
102      const title = data?.app.byId.name ?? fullName;
103      navigation.setOptions({
104        title,
105        headerRight: () => <ShareProjectButton fullName={fullName} />,
106      });
107    }
108  }, [navigation, data?.app?.byId]);
109
110  return <View flex="1">{contents}</View>;
111}
112
113function appHasLegacyUpdate(app: ProjectPageApp): boolean {
114  return app.published;
115}
116
117function appHasEASUpdates(app: ProjectPageApp): boolean {
118  return app.updateBranches.some((branch) => branch.updates.length > 0);
119}
120