Skip to content

Postwires

Primary Menu
  • Home
  • CSS
  • Documentation
  • HTML
  • Java
  • Javascript
  • Questions
  • React js
  • React Native
Watch Video
  • Home
  • Uncategorized
  • weather app build with latest technology
  • Uncategorized

weather app build with latest technology

john October 31, 2025
//app.js


import React from  "react";
import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
import HomeScreen from  "./screens/HomeScreen";
import DetailScreen from  "./screens/DetailScreen";

const Stack = createStackNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>

        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen
          name="Details"
          component={DetailScreen}
          options={({ route }) => ({
            title: route.params?.city
              ? `Weather • ${route.params.city}`
              : "Details",
          })}
        />

      </Stack.Navigator>
    </NavigationContainer>
  );
}

//DetailScreen.js


import React, { useState, useEffect } from "react";
import { View, Text, StyleSheet, ActivityIndicator, ImageBackground } from "react-native";
import Icon from "react-native-vector-icons/Feather";

const API_KEY = "fbd8a1595fc2352d6963a9a70e296358";

export default function DetailScreen({ route }) {
  const { city } = route.params;
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [errorMsg, setErrorMsg] = useState("");

  useEffect(() => {
    setLoading(true);
    setErrorMsg("");
    fetch(
      `https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(
        city
      )}&appid=${API_KEY}&units=metric`
    )
      .then((res) => res.json())
      .then((json) => {
        if (json.cod !== 200) {
          setErrorMsg(json.message || "City not found");
          setData(null);
        } else {
          setData(json);
        }
      })
      .catch(() => setErrorMsg("Network error"))
      .finally(() => setLoading(false));
  }, []);

  if (loading) return <ActivityIndicator style={{ flex: 1 }} size="large" />;

  if (errorMsg || !data) {
    return (
      <ImageBackground source={{uri: "https://images.pexels.com/photos/209831/pexels-photo-209831.jpeg"}} style={styles.center}>
        <View style={styles.errorCard}>
          <Text style={styles.errorText}>Error: {errorMsg || "City not found"}</Text>
        </View>
      </ImageBackground>
    );
  }

  
  const cond = (data.weather?.[0]?.main || "").toLowerCase(); 
  const isDay = (data.weather?.[0]?.icon || "").includes("d");

  const mainIconName =
    cond.includes("clear")
      ? isDay ? "sun" : "moon"
      : cond.includes("cloud")
      ? "cloud"
      : cond.includes("rain")
      ? "cloud-rain"
      : cond.includes("snow")
      ? "cloud-snow"
      : cond.includes("drizzle")
      ? "cloud-drizzle"
      : cond.includes("thunder")
      ? "cloud-lightning"
      : "cloud";

  const localTime = (() => {
    const dt = data.dt || 0;           
    const tz = data.timezone || 0;     
    const d = new Date((dt + tz) * 1000);
    const hh = String(d.getUTCHours()).padStart(2, "0");
    const mm = String(d.getUTCMinutes()).padStart(2, "0");
    return `${hh}:${mm}`;
  })();

  return (
    <ImageBackground source={{uri: "https://images.pexels.com/photos/209831/pexels-photo-209831.jpeg"}} style={styles.container}>
      <View style={styles.card}>
        
        <Text style={styles.city}>{data.name}</Text>
        <Text style={styles.subtle}>Local time: {localTime}</Text>

        
        <View style={{ alignItems: "center", marginVertical: 10 }}>
          <Icon name={mainIconName} size={56} color="dark gray" />
        </View>
        <Text style={styles.temp}>{Math.round(data.main.temp)}°C</Text>

       
        <Text style={styles.cond}>
          {data.weather[0].main} ({data.weather[0].description})
        </Text>

        
        <View style={styles.row}>
          <View style={styles.infoBox}>
            <Icon name="wind" size={18} />
            <Text style={styles.infoText}>{data.wind.speed} m/s</Text>
          </View>

          <View style={styles.infoBox}>
            <Icon name="cloud" size={18} />
            <Text style={styles.infoText}>{data.clouds.all}%</Text>
          </View>
        </View>
      </View>
    </ImageBackground>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: "center", alignItems: "center" },
  center: { flex: 1, justifyContent: "center", alignItems: "center" },
  card: {
    width: "85%",
    padding: 20,
    backgroundColor: "rgba(255,255,255,0.88)",
    borderRadius: 14,
    alignItems: "center",
  },
  city: { fontSize: 24, fontWeight: "800" },
  subtle: { marginTop: 4, fontSize: 12, color: "gray" },
  temp: { fontSize: 56, fontWeight: "800", marginVertical: 6 },
  cond:  { fontSize: 16, textTransform: "capitalize", marginBottom: 12 },
  row: {
    flexDirection: "row",
    justifyContent: "space-between",
    width: "70%",
    marginTop: 6,
    gap: 12,
  },
  infoBox:  {
    flex: 1,
    flexDirection: "row",
    alignItems: "center",
    gap: 6,
    paddingVertical: 10,
    paddingHorizontal: 12,
    backgroundColor: "light gray",
    borderRadius: 10,
    justifyContent: "center",
  },
  infoText: { fontSize: 14, fontWeight: "600" },
  errorCard: {
    padding: 16,
    backgroundColor: "white",
    borderRadius: 12,
    marginHorizontal: 20,
  },
  errorText: { fontSize: 16, color: "red", fontWeight: "700" },
});

//HomeScreen.js
import React from "react";
import {
  View,
  Text,
  TextInput,
  StyleSheet,
  ImageBackground,
  TouchableOpacity,
  TouchableWithoutFeedback,
  Keyboard

} from "react-native";
import { Formik } from "formik";
import * as Yup from "yup";

const citySchema = Yup.object().shape({
  city: Yup.string()
    .required("Enter city name")
    .test("no-spaces", "Enter valid city name", (value) => value && value.trim().length > 0),
});

export default function HomeScreen({ navigation }) {
  return (
    <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
    <ImageBackground
      source={{
        uri: "https://images.pexels.com/photos/209831/pexels-photo-209831.jpeg?auto=compress&cs=tinysrgb&w=1200",
      }}
      
      style={styles.container}
    >
      
      <View style={styles.card}>
        <Text style={styles.title}>Search Weather</Text>

        <Formik
          initialValues={{ city: "" }}
          validationSchema={citySchema}
          onSubmit={(values) => {
            const city = values.city.trim();
            navigation.navigate("Details", { city });
          }}
        >
          {({ handleChange, handleBlur, handleSubmit, values, errors, touched }) => {
            const disabled = !values.city.trim();

            return (
              <>
                <TextInput
                  style={[styles.input, touched.city && errors.city ? styles.inputError : null]}
                  placeholder="Enter city name"
                  value={values.city}
                  onChangeText={handleChange("city")}
                  onBlur={handleBlur("city")}
                  placeholderTextColor="gray"
                  returnKeyType="search"
                  onSubmitEditing={handleSubmit}
                />

                {touched.city && errors.city ? (
                  <Text style={styles.errorText}>{errors.city}</Text>
                ) : null}

                <TouchableOpacity
                  style={[styles.btn, disabled ? styles.btnDisabled : null]}
                  onPress={handleSubmit}
                  activeOpacity={0.7}
                  disabled={disabled}
                >
                  <Text style={styles.btnText}>Search</Text>
                </TouchableOpacity>
              </>
            );
          }}
        </Formik>
      </View>
      
    </ImageBackground>
    </TouchableWithoutFeedback>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: "center" },
  card: {
    marginHorizontal: 20,
    padding: 20,
    backgroundColor: "rgba(255,255,255,0.88)",
    borderRadius: 12,
  },
   title: { fontSize: 24, textAlign: "center", marginBottom: 16, fontWeight: "700", color: "black" },
   input: {
    borderWidth: 1,
    borderColor: "white",
    backgroundColor: "white",
    padding: 12,
    borderRadius: 8,
    marginBottom: 8,
  },
  inputError: {
    borderColor: "red",
  },
  errorText: {
    color: "red",
    marginBottom: 12,
  },
  btn: {
    backgroundColor: "dodgerblue",
    paddingVertical: 12,
    borderRadius: 8,
    alignItems: "center",
  },
  btnDisabled: {
    opacity: 0.5,
  },

  btnText: {
    color: "white",
    fontWeight: "700",
    fontSize: 16,
  },
});






//package.json
{
  "name": "weatherApp",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "lint": "eslint .",
    "start": "react-native start",
    "test": "jest"
  },
  "dependencies": {
    "@react-native/new-app-screen": "0.82.0",
    "@react-navigation/native": "^7.1.18",
    "@react-navigation/stack": "^7.4.10",
    "formik": "^2.4.6",
    "react": "19.1.1",
    "react-native": "0.82.0",
    "react-native-gesture-handler": "^2.28.0",
    "react-native-safe-area-context": "^5.6.1",
    "react-native-screens": "^4.16.0",
    "react-native-vector-icons": "^10.3.0",
    "yup": "^1.7.1"
  },
  "devDependencies": {
    "@babel/core": "^7.25.2",
    "@babel/preset-env": "^7.25.3",
    "@babel/runtime": "^7.25.0",
    "@react-native-community/cli": "20.0.0",
    "@react-native-community/cli-platform-android": "20.0.0",
    "@react-native-community/cli-platform-ios": "20.0.0",
    "@react-native/babel-preset": "0.82.0",
    "@react-native/eslint-config": "0.82.0",
    "@react-native/metro-config": "0.82.0",
    "@react-native/typescript-config": "0.82.0",
    "@types/jest": "^29.5.13",
    "@types/react": "^19.1.1",
    "@types/react-test-renderer": "^19.1.0",
    "eslint": "^8.19.0",
    "jest": "^29.6.3",
    "prettier": "2.8.8",
    "react-test-renderer": "19.1.1",
    "typescript": "^5.8.3"
  },
  "engines": {
    "node": ">=20"
  }
}

//app/build.gradle

apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"

//

import React, { useState, useEffect } from "react";
import { View, Text, StyleSheet, ActivityIndicator, ImageBackground } from "react-native";
import Icon from "react-native-vector-icons/Feather";

const API_KEY = "fbd8a1595fc2352d6963a9a70e296358";

export default function DetailScreen({ route }) {
  const { city } = route.params;
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [errorMsg, setErrorMsg] = useState("");

  useEffect(() => {
    setLoading(true);
    setErrorMsg("");
    fetch(
      `https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(
        city
      )}&appid=${API_KEY}&units=metric`
    )
      .then((res) => res.json())
      .then((json) => {
        if (json.cod !== 200) {
          setErrorMsg(json.message || "City not found");
          setData(null);
        } else {
          setData(json);
        }
      })
      .catch(() => setErrorMsg("Network error"))
      .finally(() => setLoading(false));
  }, []);

  if (loading) return <ActivityIndicator style={{ flex: 1 }} size="large" />;

  if (errorMsg || !data) {
    return (
      <ImageBackground source={{uri: "https://images.pexels.com/photos/209831/pexels-photo-209831.jpeg"}} style={styles.center}>
        <View style={styles.errorCard}>
          <Text style={styles.errorText}>Error: {errorMsg || "City not found"}</Text>
        </View>
      </ImageBackground>
    );
  }

  
  const cond = (data.weather?.[0]?.main || "").toLowerCase(); 
  const isDay = (data.weather?.[0]?.icon || "").includes("d");

  const mainIconName =
    cond.includes("clear")
      ? isDay ? "sun" : "moon"
      : cond.includes("cloud")
      ? "cloud"
      : cond.includes("rain")
      ? "cloud-rain"
      : cond.includes("snow")
      ? "cloud-snow"
      : cond.includes("drizzle")
      ? "cloud-drizzle"
      : cond.includes("thunder")
      ? "cloud-lightning"
      : "cloud";

  const localTime = (() => {
    const dt = data.dt || 0;           
    const tz = data.timezone || 0;     
    const d = new Date((dt + tz) * 1000);
    const hh = String(d.getUTCHours()).padStart(2, "0");
    const mm = String(d.getUTCMinutes()).padStart(2, "0");
    return `${hh}:${mm}`;
  })();

  return (
    <ImageBackground source={{uri: "https://images.pexels.com/photos/209831/pexels-photo-209831.jpeg"}} style={styles.container}>
      <View style={styles.card}>
        
        <Text style={styles.city}>{data.name}</Text>
        <Text style={styles.subtle}>Local time: {localTime}</Text>

        
        <View style={{ alignItems: "center", marginVertical: 10 }}>
          <Icon name={mainIconName} size={56} color="dark gray" />
        </View>
        <Text style={styles.temp}>{Math.round(data.main.temp)}°C</Text>

       
        <Text style={styles.cond}>
          {data.weather[0].main} ({data.weather[0].description})
        </Text>

        
        <View style={styles.row}>
          <View style={styles.infoBox}>
            <Icon name="wind" size={18} />
            <Text style={styles.infoText}>{data.wind.speed} m/s</Text>
          </View>

          <View style={styles.infoBox}>
            <Icon name="cloud" size={18} />
            <Text style={styles.infoText}>{data.clouds.all}%</Text>
          </View>
        </View>
      </View>
    </ImageBackground>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: "center", alignItems: "center" },
  center: { flex: 1, justifyContent: "center", alignItems: "center" },
  card: {
    width: "85%",
    padding: 20,
    backgroundColor: "rgba(255,255,255,0.88)",
    borderRadius: 14,
    alignItems: "center",
  },
  city: { fontSize: 24, fontWeight: "800" },
  subtle: { marginTop: 4, fontSize: 12, color: "gray" },
  temp: { fontSize: 56, fontWeight: "800", marginVertical: 6 },
  cond:  { fontSize: 16, textTransform: "capitalize", marginBottom: 12 },
  row: {
    flexDirection: "row",
    justifyContent: "space-between",
    width: "70%",
    marginTop: 6,
    gap: 12,
  },
  infoBox:  {
    flex: 1,
    flexDirection: "row",
    alignItems: "center",
    gap: 6,
    paddingVertical: 10,
    paddingHorizontal: 12,
    backgroundColor: "light gray",
    borderRadius: 10,
    justifyContent: "center",
  },
  infoText: { fontSize: 14, fontWeight: "600" },
  errorCard: {
    padding: 16,
    backgroundColor: "white",
    borderRadius: 12,
    marginHorizontal: 20,
  },
  errorText: { fontSize: 16, color: "red", fontWeight: "700" },
});

About the Author

john

Administrator

Visit Website View All Posts

Continue Reading

Previous: storeapp using react native
Next: todoapp build with latest stack

Related Stories

  • Uncategorized
  • React Native

How To Fix Gradle Error In React Native

john November 2, 2025
  • Uncategorized

jdagj

john October 31, 2025
  • Uncategorized

global map system

john October 31, 2025

Recent Posts

  • How To Fix Gradle Error In React Native
  • jdagj
  • global map system
  • todoapp build with latest stack
  • weather app build with latest technology

Categories

  • CSS
  • Documentation
  • HTML
  • Java
  • Javascript
  • Questions
  • React js
  • React Native
  • Uncategorized

You may have missed

  • Uncategorized
  • React Native

How To Fix Gradle Error In React Native

john November 2, 2025
  • Uncategorized

jdagj

john October 31, 2025
  • Uncategorized

global map system

john October 31, 2025
  • Uncategorized

todoapp build with latest stack

john October 31, 2025
  • About Author
  • About Us
  • Contact Us
  • Disclaimer
  • Privacy Policy
Copyright © All rights reserved. | MoreNews by AF themes.