# Project export: Weather app

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2024
- Tagline: This is a weather app to check the weather details of a few default cities
- Devpost: https://devpost.com/software/weather-app-6wq04k
- GitHub: https://github.com/tarini11/treehacks
- Team: 1 GitHub contributor(s) — tarini11 (7 commits)

## Devpost submission (written by the team)

### Inspiration

I am very new to the world of development and as someone building their very first app this was very exciting to me and I decided to work on a react native weather app as I read about it and realised that it was one of the most beginner friendly options. I had heard a lot about APIs and wanted to use a popular one in my app and therefore decided to use the openweatherAPI and make a weather app.

### What it does

It is a weather app that allows you to see the weather for a few preset cities. You can further click into any city to see more details about its weather as well as a 5 day weather forecast for that city.

### How we built it

It was built using the openweather API and react native. I used a few react native libraries as well

### Challenges we ran into

As someone working on their first app, it was a steep learning curve for me and I struggled with a lot of tricky bugs, but good documentation made life easier for me

### Accomplishments we're proud of

Proud of being able to create a super cool project for my first try and excited for whats next!

## README (from the GitHub repository)

Run npm install and then npx expo start


## Detected evidence (automated analysis)

Indexed codebase: 10 recognized source files, 18 KB.
- JavaScript (language) — detected in the code
- React (technology) — detected in the code

## Codebase structure (from repository index)

### Files (12 of 12)

```
App.js
app.json
babel.config.js
CitiesPage.js
FiveDayPage.js
getWeatherData.js
HomePage.js
Main.js
package.json
README.md
unixConversion.js
WeatherPage.js
```

### Dependencies

- package.json: @babel/core@^7.20.0, @react-native-community/masked-view@^0.1.11, @react-navigation/drawer@^6.6.6, @react-navigation/material-bottom-tabs@^6.2.19, @react-navigation/native@^6.1.9, @react-navigation/native-stack@^6.9.17, @react-navigation/stack@^6.3.20, expo@~49.0.15, expo-status-bar@~1.6.0, react@18.2.0, react-native@0.72.6, react-native-gesture-handler@~2.12.0, react-native-paper@^5.11.3, react-native-reanimated@~3.3.0, react-native-safe-area-context@4.6.3, react-native-screens@~3.22.0

### Recent commits (newest first)

- Delete assets/a
- Add files via upload
- Create a
- Delete aseets/a
- Create README.md
- Create a
- Add files via upload

## Key source files (fetched from GitHub, selected and truncated for size)

### package.json

```
{
  "name": "treehacks-project",
  "version": "1.0.0",
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web"
  },
  "dependencies": {
    "@react-native-community/masked-view": "^0.1.11",
    "@react-navigation/drawer": "^6.6.6",
    "@react-navigation/material-bottom-tabs": "^6.2.19",
    "@react-navigation/native": "^6.1.9",
    "@react-navigation/native-stack": "^6.9.17",
    "@react-navigation/stack": "^6.3.20",
    "expo": "~49.0.15",
    "expo-status-bar": "~1.6.0",
    "react": "18.2.0",
    "react-native": "0.72.6",
    "react-native-gesture-handler": "~2.12.0",
    "react-native-paper": "^5.11.3",
    "react-native-reanimated": "~3.3.0",
    "react-native-safe-area-context": "4.6.3",
    "react-native-screens": "~3.22.0"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0"
  },
  "private": true
}

```

### Main.js

```javascript
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';


export default function Main() {
  return (
    <View style={styles.container}>
      <Text>Open up App.js to start working on your app!</Text>
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

```

### App.js

```javascript
import { StyleSheet} from 'react-native';
import { Provider as PaperProvider } from 'react-native-paper';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

import HomePage from './HomePage';
import CitiesPage from './CitiesPage';
import WeatherPage from './WeatherPage';
import FiveDayPage from './FiveDayPage';

const Stack = createNativeStackNavigator();

function HomeScreen({navigation}) {
  return (
    <HomePage navigation={navigation}/>
  );
}

function Cities({navigation}) {
  return (
    <CitiesPage navigation={navigation}/>
  );
}

function Weather({route, navigation}) {
  return (
    <WeatherPage route={route} navigation={navigation} />
  );
}

function FiveDay({route}) {
  return (
    <FiveDayPage route={route} />
  );
}
//const Stack = createNativeStackNavigator();

function App() {
  return (
    <PaperProvider>
      <NavigationContainer>
      <Stack.Navigator initialRouteName="Home" >
      <Stack.Screen name="Home" component={HomeScreen} />
      <Stack.Screen name="Cities" component={Cities} />
      <Stack.Screen name="Weather" component={Weather} />
      <Stack.Screen name="Five Day" component={FiveDay} />
      </Stack.Navigator>
      </NavigationContainer>
    </PaperProvider>
  );
}

export default App;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

```

### babel.config.js

```javascript
module.exports = function(api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
  };
};

```

### unixConversion.js

```javascript
//  Credit to https://www.geeksforgeeks.org/how-to-convert-unix-timestamp-to-time-in-javascript/

const unixConversion = (unix, offset) => {
    let unixTime = unix + offset;
    let dateObj = new Date(unixTime * 1000);
    let utcString = dateObj.toUTCString();
 
    let time = utcString.slice(-11, -4);
    return time;
}  
  export default unixConversion;
```

### getWeatherData.js

```javascript
const apiKey = '5a5a8a676f03d9e34025c4f6b516a125';
const units = 'metric'

const getWeatherData = async (lat, long) => {
    try {
        const response = await fetch(`https://api.openweathermap.org/data/2.5/onecall?lat=${lat}&lon=${long}&units=${units}&appid=${apiKey}`);
        const data = await response.json();
        return data;
      }
      catch(error) {
        throw error;
      }
      
};

export default getWeatherData;

```

### HomePage.js

```javascript
import { StyleSheet, View, ImageBackground} from "react-native";
import { Button } from 'react-native-paper';

export default function HomePage({navigation}) {

  return (
    <View style={styles.container}>
      <ImageBackground source={require("./backdrop.jpeg")} resizeMode="cover" style={styles.image}>
      <View style={styles.body}>
      <Button icon="weather-cloudy" mode="contained" onPress={() => { navigation.navigate('Cities')
        }}>
        Check Weather
      </Button>
      </View>
      </ImageBackground>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#dfebeb',
    alignItems: 'center',
    justifyContent: 'center'
  },
  body: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  image: {
    flex: 1,
    width: '100%', 
    height: '100%',
  }
});

```

### CitiesPage.js

```javascript

import { StyleSheet, View, ImageBackground} from "react-native";
import { Button} from 'react-native-paper';

export default function CitiesPage({navigation}) {

  return (
    <View style={styles.container}>
    <ImageBackground source={require("./backdrop.jpeg")} resizeMode="cover" style={styles.image}>
    <View style={styles.stanford}>
    <View style={styles.button}>
    <Button 
        mode="contained"
        onPress={() => { navigation.navigate('Weather',{
            city: "Stanford",
            lat: "37.428230",
            long: "-122.168861"
          })
        }}>
      Stanford
      </Button>
      </View>
    </View>
    <View style={styles.delhi}>
    <View style={styles.button}>
    <Button 
        mode="contained"
        onPress={() => { navigation.navigate('Weather',{
            city: "New Delhi",
            lat: "28.644800",
            long: "77.216721"
          })
        }}>
      New Delhi
      </Button>
    </View>
    </View>
    <View style={styles.seattle}>
    <View style={styles.button}>
    <Button 
        mode="contained"
        onPress={() => { navigation.navigate('Weather',{
            city: "New York",
            lat: "40.7128",
            long: "-73.935242" 
          })
        }}>
      New York
      </Button>
    </View>
    </View>
    <View style={styles.toronto}>
    <View style={styles.button}>
    <Button 
        mode="contained"
        onPress={() => { navigation.navigate('Weather',{
            city: "Toronto",
            lat: "43.653908",
            long: "-79.384293" 
          })
        }}>
      Toronto
      </Button>
    </View>
    </View>
    <View style={styles.dallas}>
    <View style={styles.button}>
    <Button 
        mode="contained"
        onPress={() => { navigation.navigate('Weather',{
            city: "Dallas",
            lat: "32.779167",
            long: "-96.808891"
          })
        }}>
      Dallas
      </Button>
    </View>
    </View>
    </ImageBackground>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#dfebeb',
    alignItems: 'center',
    justifyContent: 'center',
  },
  stanford: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  delhi: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  seattle: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  toronto: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  dallas: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  image: {
    flex: 1,
    width: '100%', 
    height: '100%',
  }
});

```

### WeatherPage.js

```javascript
import { StyleSheet, View, ImageBackground, Image} from "react-native";
import { useState, useEffect } from "react";
import { Text, Icon, Button } from 'react-native-paper';

import unixConversion from './unixConversion';
import getWeatherData from './getWeatherData';

export default function weatherPage({route, navigation}) {
  const { city, lat, long } = route.params;
  const [weatherData, setWeatherData] = useState(null);

  useEffect(() => {
    async function getData() {
      try { 
        const myData = await getWeatherData(lat, long);
        setWeatherData(myData);
      } catch (error) {
        console.error('Error fetching data:', error);
      }
    };

    getData();
  }, []);

  let contentDisplayed = null;

  if (weatherData === null) {
    contentDisplayed = null
  }
  else {
    let imageUrl = "https://openweathermap.org/img/wn/" + weatherData.current.weather[0].icon + "@2x.png"
    console.log(imageUrl)
    contentDisplayed = <>
    <View style ={styles.city}>
    <Text variant="displayLarge" style={styles.bigText}>
          {city}
      </Text>
      <Text variant="displaySmall" style={styles.text}>
          {weatherData.current.temp}°
      </Text>
      <Text variant="displaySmall" style={styles.text1}>
          {weatherData.current.weather[0].description}
      </Text>
      <Text variant="displaySmall" style={styles.text1}>
          Feels Like: {weatherData.current.feels_like}°
        </Text>
    </View>
    <View style={styles.icon_weather}>
    <Image source={{ uri: imageUrl }} style={styles.image1} />
    </View>
      <View style={styles.sun_moon}>
        <View style={styles.sunrise}>
        <Text variant="displaySmall" style={styles.text}>
            Sunrise 
            <Icon
                source="weather-sunset-up"
                size={30}
                color="#DBAC0D"
            /> 
            </Text>
            <Text variant="displaySmall" style={styles.text}>
            {unixConversion(weatherData.current.sunrise, weatherData.timezone_offset)} AM
          </Text>
        </View>
        <View style={styles.sunset}>
        <Text variant="displaySmall" style={styles.text}>
            Sunset 
            <Icon
                source="weather-sunset-down"
                size={30}
                color="#DB2C0D"
            /> 
            </Text>
            <Text variant="displaySmall" style={styles.text}>
            {unixConversion(weatherData.current.sunset, weatherData.timezone_offset)} PM
          </Text>
        </View>
      </View>
      <View style={styles.fiveDay}>
      <Button 
        mode="contained"
        onPress={() => { navigation.navigate('Five Day',{
            city: city,
            lat: lat,
            long: long
          })
        }}>
            See 5 day weather
        </Button>
      </View></>
  }

  return (
      <View style={styles.container}>
        <ImageBackground source={require("./backdrop.jpeg")} resizeMode="cover" style={styles.image}>
        {contentDisplayed}
        </ImageBackground>
      </View>
    );
  }
  
  const styles = StyleSheet.create({
    container: {
      flex: 1,
      backgroundColor: '#dfebeb',
      alignItems: 'center',
      justifyContent: 'center',
    },
    city: {
      flex: 4,
      justifyContent: 'center',
      alignItems: 'center',
      borderWidth: 1,
      marginTop: 10,
      width: "100%",
      borderRadius: "100%",
      backgroundColor: '#151841'
    },
    min_max: {
      flexDirection: "row",
      alignItems: 'center',
      justifyContent: 'center',
    },
    bigText: {
      fontSize: 50,
      color: "#6A72E5"
    },
    text: {
      fontSize: 30,
      color: "#6A72E5"
    },
    text1: {
      fontSize: 20,
      color: "#5459A0"
    },
    icon_weather: {
      flex: 2,
      alignItems: 'center',
      justifyContent: 'center'
    },
    sun_moon: {
      flex: 2,
      flexDirection: 'row',
      alignItems: 'center',
      width: "100%"
    },
    sunrise: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
    },
    sunset: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
    },
    fiveDay: {
      flex: 3,
      justifyContent: 'center',
    },
    fiveDayButton: {
      padding: 10,
      backgroundColor: "#a8d1d1",
    },
    fButton: {
      alignItems: 'center',
      justifyContent: 'center',
      padding: 5,
      backgroundColor: '#7274A4'
    },
    icons: {
      padding: 10,
      borderWidth:1
    },
    image: {
      flex: 1,
      width: '100%', 
      height: '100%',
    },
    image1: {
      width: 100,
      height: 100, 
    }
});

```

### FiveDayPage.js

```javascript
import { StyleSheet, SafeAreaView, Pressable, View, Image, FlatList, ImageBackground} from "react-native";
import { useState, useEffect } from "react";
import { Text, Surface} from 'react-native-paper';

import getWeatherData from './getWeatherData';

export default function fiveDay({route}) {
  const { city, lat, long } = route.params;
  const [weatherData, setWeatherData] = useState(null);

  useEffect(() => {
    async function getData() {
      try { 
        const myData = await getWeatherData(lat, long);
        setWeatherData(myData);
      } catch (error) {
        console.error('Error fetching data:', error);
      }
    };

    getData();
  }, []);

  let contentDisplayed = null;

  if (weatherData === null) {
    contentDisplayed = null
  }
  else {
    let imageUrl1 = "https://openweathermap.org/img/wn/" + weatherData.daily[0].weather[0].icon[0] + weatherData.daily[0].weather[0].icon[1] + "n@2x.png"
    let imageUrl2 = "https://openweathermap.org/img/wn/" + weatherData.daily[1].weather[0].icon[0] + weatherData.daily[1].weather[0].icon[1] + "n@2x.png"
    let imageUrl3 = "https://openweathermap.org/img/wn/" + weatherData.daily[2].weather[0].icon[0] + weatherData.daily[2].weather[0].icon[1] + "n@2x.png"
    let imageUrl4 = "https://openweathermap.org/img/wn/" + weatherData.daily[3].weather[0].icon[0] + weatherData.daily[3].weather[0].icon[1] + "n@2x.png"
    let imageUrl5 = "https://openweathermap.org/img/wn/" + weatherData.daily[4].weather[0].icon[0] + weatherData.daily[4].weather[0].icon[1] + "n@2x.png"
    contentDisplayed = <>
    <View style={styles.day}>
      <View style={styles.dayNum}>
      <Text variant="titleLarge" style={styles.text}>
        Day 1
      </Text>
      </View>
      <View style={styles.day1}>
        <View style={styles.day2}>
        <View>
        <Text variant="titleLarge" style={styles.text1}>
        {weatherData.daily[0].weather[0].description}
        </Text>
        </View> 
        <View>
        <Image source={{ uri: imageUrl1 }} style={styles.image1} />
        </View>
        </View>
        <View style={styles.day2}>
        <View style={styles.min}>
        <Text variant="titleLarge" style={styles.text}>
          L: {weatherData.daily[0].temp.min}°
        </Text>
        </View>
        <View style={styles.max}>
        <Text variant="titleLarge" style={styles.text}>
        H: {weatherData.daily[0].temp.max}°
        </Text>
      </View>
      </View>
      </View>
    </View>
    <View style={styles.day}>
      <View style={styles.dayNum}>
      <Text variant="titleLarge" style={styles.text}>
        Day 2
      </Text>
      </View>
      <View style={styles.day1}>
        <View style={styles.day2}>
        <View>
        <Text variant="titleLarge" style={styles.text1}>
        {weatherData.daily[1].weather[0].description}
        </Text>
        </View> 
        <View>
        <Image source={{ uri: imageUrl2 }} style={styles.image1} />
        </View>
        </View>
        <View style={styles.day2}>
        <View style={styles.min}>
        <Text variant="titleLarge" style={styles.text}>
          L: {weatherData.daily[1].temp.min}°
        </Text>
        </View>
        <View style={styles.max}>
        <Text variant="titleLarge" style={styles.text}>
        H: {weatherData.daily[1].temp.max}°
        </Text>
      </View>
      </View>
      </View>
    </View>
    <View style={styles.day}>
      <View style={styles.dayNum}>
      <Text variant="titleLarge" style={styles.text}>
        Day 3
      </Text>
      </View>
      <View style={styles.day1}>
        <View style={styles.day2}>
        <View>
        <Text variant="titleLarge" style={styles.text1}>
        {weatherData.daily[2].weather[0].description}
        </Text>
        </View> 
        <View>
        <Image source={{ uri: imageUrl3 }} style={styles.image1} />
        </View>
        </View>
        <View style={styles.day2}>
        <View style={styles.min}>
        <Text variant="titleLarge" style={styles.text}>
          L: {weatherData.daily[2].temp.min}°
        </Text>
        </View>
        <View style={styles.max}>
        <Text variant="titleLarge" style={styles.text}>
        H: {weatherData.daily[2].temp.max}°
        </Text>
      </View>
      </View>
      </View>
    </View>
    <View style={styles.day}>
      <View style={styles.dayNum}>
      <Text variant="titleLarge" style={styles.text}>
        Day 4
      </Text>
      </View>
      <View style={styles.day1}>
        <View style={styles.day2}>
        <View>
        <Text variant="titleLarge" style={styles.text1}>
        {weatherData.daily[3].weather[0].description}
        </Text>
        </View> 
        <View>
        <Image source={{ uri: imageUrl4 }} style={styles.image1} />
        </View>
        </View>
        <View style={styles.day2}>
        <View style={styles.min}>
        <Text variant="titleLarge" style={styles.text}>
          L: {weatherData.daily[3].temp.min}°
        </Text>
        </View>
        <View style={styles.max}>
        <Text variant="titleLarge" style={styles.text}>
        H: {weatherData.daily[3].temp.max}°
        </Text>
      </View>
      </View>
      </View>
    </View>
    <View style={styles.day}>
      <View style={styles.dayNum}>
      <Text variant="titleLarge" style={styles.text}>
        Day 5
      </Text>
      </View>
      <View style={styles.day1}>
        <View style={styles.day2}>
        <View>
        <Text variant="titleLarge" style={styles.text1}>
        {weatherData.daily[4].weather[0].description}
        </Text>
        </View> 
        <View>
        <Image source={{ uri: imageUrl5 }} style={styles.image1} />
        </View>
        </View>
        <View style={styles.day2}>
        <View style={styles.min}>
        <Text variant="titleLarge" style={styles.text}>
          L: {weatherData.daily[4].temp.min}°
        </Text>
        </View>
        <View style={styles.max}>
        <Text variant="titleLarge" style={styles.text
[truncated — 1431 more characters]
```