diff options
Diffstat (limited to 'app/(tabs)')
| -rw-r--r-- | app/(tabs)/_layout.tsx | 8 | ||||
| -rw-r--r-- | app/(tabs)/explore.tsx | 102 | ||||
| -rw-r--r-- | app/(tabs)/index.tsx | 204 | 
3 files changed, 158 insertions, 156 deletions
diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 22a49b6..fcc94db 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -23,15 +23,15 @@ export default function TabLayout() {            ),          }}        /> -      <Tabs.Screen +      {/*<Tabs.Screen          name="explore"          options={{ -          title: 'Explore', +          title: 'Alerts',            tabBarIcon: ({ color, focused }) => ( -            <TabBarIcon name={focused ? 'code-slash' : 'code-slash-outline'} color={color} /> +            <TabBarIcon name={focused ? 'map' : 'map-outline'} color={color} />            ),          }} -      /> +      />*/}      </Tabs>    );  } diff --git a/app/(tabs)/explore.tsx b/app/(tabs)/explore.tsx deleted file mode 100644 index e480218..0000000 --- a/app/(tabs)/explore.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import Ionicons from '@expo/vector-icons/Ionicons'; -import { StyleSheet, Image, Platform } from 'react-native'; - -import { Collapsible } from '@/components/Collapsible'; -import { ExternalLink } from '@/components/ExternalLink'; -import ParallaxScrollView from '@/components/ParallaxScrollView'; -import { ThemedText } from '@/components/ThemedText'; -import { ThemedView } from '@/components/ThemedView'; - -export default function TabTwoScreen() { -  return ( -    <ParallaxScrollView -      headerBackgroundColor={{ light: '#D0D0D0', dark: '#353636' }} -      headerImage={<Ionicons size={310} name="code-slash" style={styles.headerImage} />}> -      <ThemedView style={styles.titleContainer}> -        <ThemedText type="title">Explore</ThemedText> -      </ThemedView> -      <ThemedText>This app includes example code to help you get started.</ThemedText> -      <Collapsible title="File-based routing"> -        <ThemedText> -          This app has two screens:{' '} -          <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> and{' '} -          <ThemedText type="defaultSemiBold">app/(tabs)/explore.tsx</ThemedText> -        </ThemedText> -        <ThemedText> -          The layout file in <ThemedText type="defaultSemiBold">app/(tabs)/_layout.tsx</ThemedText>{' '} -          sets up the tab navigator. -        </ThemedText> -        <ExternalLink href="https://docs.expo.dev/router/introduction"> -          <ThemedText type="link">Learn more</ThemedText> -        </ExternalLink> -      </Collapsible> -      <Collapsible title="Android, iOS, and web support"> -        <ThemedText> -          You can open this project on Android, iOS, and the web. To open the web version, press{' '} -          <ThemedText type="defaultSemiBold">w</ThemedText> in the terminal running this project. -        </ThemedText> -      </Collapsible> -      <Collapsible title="Images"> -        <ThemedText> -          For static images, you can use the <ThemedText type="defaultSemiBold">@2x</ThemedText> and{' '} -          <ThemedText type="defaultSemiBold">@3x</ThemedText> suffixes to provide files for -          different screen densities -        </ThemedText> -        <Image source={require('@/assets/images/react-logo.png')} style={{ alignSelf: 'center' }} /> -        <ExternalLink href="https://reactnative.dev/docs/images"> -          <ThemedText type="link">Learn more</ThemedText> -        </ExternalLink> -      </Collapsible> -      <Collapsible title="Custom fonts"> -        <ThemedText> -          Open <ThemedText type="defaultSemiBold">app/_layout.tsx</ThemedText> to see how to load{' '} -          <ThemedText style={{ fontFamily: 'SpaceMono' }}> -            custom fonts such as this one. -          </ThemedText> -        </ThemedText> -        <ExternalLink href="https://docs.expo.dev/versions/latest/sdk/font"> -          <ThemedText type="link">Learn more</ThemedText> -        </ExternalLink> -      </Collapsible> -      <Collapsible title="Light and dark mode components"> -        <ThemedText> -          This template has light and dark mode support. The{' '} -          <ThemedText type="defaultSemiBold">useColorScheme()</ThemedText> hook lets you inspect -          what the user's current color scheme is, and so you can adjust UI colors accordingly. -        </ThemedText> -        <ExternalLink href="https://docs.expo.dev/develop/user-interface/color-themes/"> -          <ThemedText type="link">Learn more</ThemedText> -        </ExternalLink> -      </Collapsible> -      <Collapsible title="Animations"> -        <ThemedText> -          This template includes an example of an animated component. The{' '} -          <ThemedText type="defaultSemiBold">components/HelloWave.tsx</ThemedText> component uses -          the powerful <ThemedText type="defaultSemiBold">react-native-reanimated</ThemedText> library -          to create a waving hand animation. -        </ThemedText> -        {Platform.select({ -          ios: ( -            <ThemedText> -              The <ThemedText type="defaultSemiBold">components/ParallaxScrollView.tsx</ThemedText>{' '} -              component provides a parallax effect for the header image. -            </ThemedText> -          ), -        })} -      </Collapsible> -    </ParallaxScrollView> -  ); -} - -const styles = StyleSheet.create({ -  headerImage: { -    color: '#808080', -    bottom: -90, -    left: -35, -    position: 'absolute', -  }, -  titleContainer: { -    flexDirection: 'row', -    gap: 8, -  }, -}); diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 324aeb7..46a690f 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -1,51 +1,134 @@ -import { Image, StyleSheet, Platform } from 'react-native'; +import { Alert, Platform, Pressable, StyleSheet, Text, TextInput, View } from 'react-native'; -import { HelloWave } from '@/components/HelloWave';  import ParallaxScrollView from '@/components/ParallaxScrollView';  import { ThemedText } from '@/components/ThemedText';  import { ThemedView } from '@/components/ThemedView'; +import React, { useState, useEffect } from 'react'; +import { API_URL } from '@env'; +import AsyncStorage from '@react-native-async-storage/async-storage';   +  export default function HomeScreen() { +  const [username, setUsername] = useState(''); +  const [password, setPassword] = useState(''); +  const [token, setToken] = useState(''); + +  const storeToken = async (token: string) => { +    if (Platform.OS === 'web') { +      localStorage.setItem('token', token); +    } else { +      await AsyncStorage.setItem('token', token); +    } +  }; + +  const handleLogin = async () => { +    if (!username || !password) { +      Alert.alert('Error', 'Username and password are required.'); +      return; +    } + +    try { +      const response = await fetch(`${API_URL}/graphql`, { +        method: 'POST', +        headers: { +          'Content-Type': 'application/json', +        }, +        body: JSON.stringify({ +          query: ` +            mutation Login($input: LoginCredentials!) {  +              login(input: $input) {  +                accessToken  +                tokenType  +              }  +            }`, +          variables: { +            input: { +              email: username, +              password, +            }, +          }, +        }), +      }); + +      const data = await response.json(); + +      if (data.errors) { +        const errorMessages = data.errors.map((error: any) => error.message); +        Alert.alert('Error', errorMessages.join('\n')); +      } else { +        const { accessToken } = data.data.login; +        await storeToken(accessToken); +        setToken(accessToken); +      } +    } catch (err) { +      console.error('Login Error:', err); +      Alert.alert('Error', 'An error occurred during login.'); +    } +  }; + +  const handleLogout = async () => { +    await removeToken(); +    setToken(''); +  }; + +  const removeToken = async () => { +    if (Platform.OS === 'web') { +      localStorage.removeItem('token'); +    } else { +      await AsyncStorage.removeItem('token'); +    } +  }; + +  useEffect(() => { +    const retrieveToken = async () => { +      const storedToken = Platform.OS === 'web' ? localStorage.getItem('token') : await AsyncStorage.getItem('token'); +      setToken(storedToken || ''); +    }; + +    retrieveToken(); +  }, []); +    return ( -    <ParallaxScrollView -      headerBackgroundColor={{ light: '#A1CEDC', dark: '#1D3D47' }} -      headerImage={ -        <Image -          source={require('@/assets/images/partial-react-logo.png')} -          style={styles.reactLogo} -        /> -      }> -      <ThemedView style={styles.titleContainer}> -        <ThemedText type="title">Welcome!</ThemedText> -        <HelloWave /> -      </ThemedView> -      <ThemedView style={styles.stepContainer}> -        <ThemedText type="subtitle">Step 1: Try it</ThemedText> -        <ThemedText> -          Edit <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> to see changes. -          Press{' '} -          <ThemedText type="defaultSemiBold"> -            {Platform.select({ ios: 'cmd + d', android: 'cmd + m' })} -          </ThemedText>{' '} -          to open developer tools. -        </ThemedText> -      </ThemedView> -      <ThemedView style={styles.stepContainer}> -        <ThemedText type="subtitle">Step 2: Explore</ThemedText> -        <ThemedText> -          Tap the Explore tab to learn more about what's included in this starter app. -        </ThemedText> -      </ThemedView> -      <ThemedView style={styles.stepContainer}> -        <ThemedText type="subtitle">Step 3: Get a fresh start</ThemedText> -        <ThemedText> -          When you're ready, run{' '} -          <ThemedText type="defaultSemiBold">npm run reset-project</ThemedText> to get a fresh{' '} -          <ThemedText type="defaultSemiBold">app</ThemedText> directory. This will move the current{' '} -          <ThemedText type="defaultSemiBold">app</ThemedText> to{' '} -          <ThemedText type="defaultSemiBold">app-example</ThemedText>. -        </ThemedText> -      </ThemedView> +    <ParallaxScrollView> +      {token ? ( +        <ThemedView>  +          <Pressable onPress={handleLogout} style={styles.formButton}> +            <Text style={{ color: 'white', textAlign: 'center' }}>Logout</Text> +          </Pressable> +        </ThemedView> +      ) : ( +        <> +          <ThemedView style={styles.titleContainer}> +            <ThemedText type="title">Welcome, mate!</ThemedText> +          </ThemedView> +          <ThemedView style={styles.formContainer}> +            <View> +              <ThemedText style={styles.text}>Username</ThemedText> +              <TextInput +                style={styles.formInput} +                onChangeText={setUsername} +                value={username} +                placeholder="Username" +              /> +            </View> +            <View> +              <ThemedText style={styles.text}>Password</ThemedText> +              <TextInput +                style={styles.formInput} +                onChangeText={setPassword} +                value={password} +                placeholder="Password" +                secureTextEntry +              /> +            </View> +            <View style={styles.buttonContainer}> +              <Pressable onPress={handleLogin} style={styles.formButton}> +                <Text style={{ color: 'white', textAlign: 'center' }}>Login</Text> +              </Pressable> +            </View> +          </ThemedView> +        </> +      )}      </ParallaxScrollView>    );  } @@ -54,17 +137,38 @@ const styles = StyleSheet.create({    titleContainer: {      flexDirection: 'row',      alignItems: 'center', -    gap: 8, +    marginBottom: 20,    }, -  stepContainer: { -    gap: 8, +  text: {      marginBottom: 8, +    color: '#333',    }, -  reactLogo: { -    height: 178, -    width: 290, -    bottom: 0, -    left: 0, -    position: 'absolute', +  formContainer: { +    marginTop: 20, +    paddingHorizontal: 20,    }, +  formInput: { +    width: '100%', +    paddingVertical: 12, +    paddingHorizontal: 16, +    borderRadius: 8, +    borderWidth: 1, +    borderColor: '#ccc', +    backgroundColor: '#f9f9f9', +    marginBottom: 20, +  }, +  buttonContainer: { +    marginTop: 20, +  }, +  formButton: { +    paddingVertical: 12, +    paddingHorizontal: 24, +    backgroundColor: '#007AFF', +    fontSize: 16, +    fontWeight: '600', +    textAlign: 'center', +    borderRadius: 8, +    color: 'white', +  }  }); +  |