> For the complete documentation index, see [llms.txt](https://reactjs.koida.tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://reactjs.koida.tech/final-term-project/level-1-team-project-3.md).

# Level 1 Team Project

## Weather Minotoring App

<figure><img src="/files/EfWKBJGf8jP29uKdvx1o" alt="" width="338"><figcaption></figcaption></figure>

### Weather Monitoring App: Setup and Explanation

This guide explains how to build a simple React weather application using Vite. It displays weather information for different days and changes the background based on the weather condition.

**1. Project Setup (Using Vite)**

* **Install Node.js:** Make sure you have Node.js (which includes npm) installed on your system. You can download it from <https://nodejs.org/>.
* **Create Vite Project:** Open your terminal or command prompt and run the following command to create a new React project named `weather-app`:

  ```bash
  npm create vite@latest weather-minitoring-app -- --template react
  ```
* **Navigate to Project Directory:**

  ```
  cd weather-minitoring-app
  ```
* **Install Dependencies:**

  ```
  npm install
  ```
* **Run the Development Server:**

  ```
  npm run dev
  ```

  This will start the development server, and you can view the basic Vite React app in your browser (usually at `http://localhost:5173`).

**2. Project Structure**

Organize your project files as follows within the `src` directory:

```
weather-app/
├── public/
│   └── vite.svg
├── src/
│   ├── assets/
│   │   └── react.svg
│   ├── components/
│   │   ├── Weather.jsx
│   │   └── weatherData.js
│   ├── images/          # Create this folder
│   │   ├── cloudy-background.jpg
│   │   ├── rainy-background.jpg
│   │   ├── snowy-background.jpg
│   │   └── sunny-background.jpg
│   ├── App.jsx          # Modify this file
│   ├── index.css        # Default Vite styles (can be modified or removed)
│   ├── main.jsx         # Entry point
│   └── style.css        # Create this file for custom styles
├── .eslintrc.cjs
├── .gitignore
├── index.html
├── package.json
├── package-lock.json
└── vite.config.js

```

* **`src/components/`**: This directory will hold reusable UI components.
  * `Weather.jsx`: The component responsible for displaying the weather details for a specific day.
  * `weatherData.js`: A JavaScript file to store the hardcoded weather data array.
* **`src/images/`**: Place your background images here (e.g., `sunny-background.jpg`, `cloudy-background.jpg`, etc.). **Important:** You need to provide these image files yourself.
* **`src/App.jsx`**: The main application component where the state and logic for switching days will reside.
* **`src/style.css`**: Your custom CSS rules for styling the application.

**3. Core Concepts Explained**

* **React Components:** React apps are built using components – reusable pieces of UI. We'll have `App` (the main component) and `Weather` (a child component).
* **JSX:** A syntax extension for JavaScript that looks like HTML. It's used to describe what the UI should look like.
* **`State (useState Hook):`** State allows components to "remember" information and re-render when that information changes. We'll use state in `App.jsx` to keep track of which day's weather is currently displayed.
  * `const [currentDayIndex, setCurrentDayIndex] = useState(0);` initializes a state variable `currentDayIndex` to `0` and provides a function `setCurrentDayIndex` to update it.
* **Props:** How parent components pass data down to child components. `App.jsx` will pass the weather data for the current day down to the `Weather.jsx` component as props.
* **`Event Handling (onClick):`** We'll attach an `onClick` handler to the button. When clicked, it will call a function to update the `currentDayIndex` state, causing the app to display the next day's weather.
* **Conditional Rendering/Styling:** The background image will change based on the `condition` property of the current day's weather data. We achieve this by dynamically setting a class or inline style on the main container element in `App.jsx`.
* **Modularity:** Separating concerns into different files (`weatherData.js`, `Weather.jsx`, `App.jsx`, `style.css`) makes the code easier to understand, manage, and maintain.
* **CSS Styling:** The `style.css` file contains rules to style the HTML elements generated by the React components (e.g., centering content, styling the button, setting text colors).

**4. Data Flow**

1. `weatherData.js` exports the array of weather objects.
2. `App.jsx` imports `weatherData`.
3. `App.jsx` uses `useState` to manage `currentDayIndex`.
4. `App.jsx` selects the weather data for the `currentDayIndex` from the `weatherData` array.
5. `App.jsx` determines the correct background image URL based on the selected day's weather `condition`.
6. `App.jsx` passes the selected day's weather data (`day`, `condition`, `emoji`, `lowTemp`, `highTemp`) as props to the `Weather.jsx` component.
7. `App.jsx` renders the `Weather` component and the "Next Day" button.
8. `Weather.jsx` receives the props and displays the weather information.
9. When the button in `App.jsx` is clicked, the `handleNextDayClick` function updates the `currentDayIndex` state.
10. React detects the state change and re-renders `App.jsx`, which in turn re-renders `Weather.jsx` with the new day's data and potentially updates the background image.

## Implement the App

**Step 1. Create the files:** Create the directories (`src/components`, `src/images`) and files (`src/components/weatherData.js`, `src/components/Weather.jsx`, `src/style.css`) as shown in the structure.

{% tabs %}
{% tab title="weatherData.js" %}

```jsx
// src/components/weatherData.js
/**
 * @typedef {Object} WeatherDay
 * @property {string} day - The day of the week (e.g., "Monday").
 * @property {string} condition - The weather condition (e.g., "Sunny", "Cloudy", "Rainy", "Snowy").
 * @property {string} emoji - The emoji representing the weather condition.
 * @property {number} lowTemp - The low temperature for the day.
 * @property {number} highTemp - The high temperature for the day.
 * @property {string} background - The filename of the background image associated with the condition.
 */

/**
 * Array containing weather data for different days.
 * @type {WeatherDay[]}
 */
export const weatherData = [
  {
    id: 1,
    day: 'Monday',
    condition: 'Sunny',
    emoji: '☀️',
    lowTemp: 20,
    highTemp: 35,
    background: 'sunny-background.jpg', // Matches image file in src/images
  },
  {
    id: 2,
    day: 'Tuesday',
    condition: 'Rainy',
    emoji: '🌧️',
    lowTemp: 15,
    highTemp: 25,
    background: 'rainy-background.jpg', // Matches image file in src/images
  },
  {
    
    id: 3,
    day: 'Wednesday',
    condition: 'Snowy',
    emoji: '❄️',
    lowTemp: -5,
    highTemp: 2,
    background: 'snowy-background.jpg', // Matches image file in src/images
  },
  // Add more days if needed, ensure corresponding images exist
  // Example:
  {
     id: 4,
     day: 'Thursday',
     condition: 'Cloudy',
     emoji: '☁️',
     lowTemp: 18,
     highTemp: 28,
     background: 'cloudy-background.jpg' // Matches image file in src/images
   },
];
```

{% endtab %}

{% tab title="Weather.jsx" %}

```jsx
// Some code
// src/components/Weather.jsx
import React from 'react';
import PropTypes from 'prop-types'; // Import PropTypes for prop validation

/**
 * Weather Component
 * Displays weather information for a single day.
 *
 * @param {object} props - Component props.
 * @param {string} props.day - Day of the week.
 * @param {string} props.emoji - Weather emoji.
 * @param {string} props.condition - Weather condition description.
 * @param {number} props.lowTemp - Low temperature.
 * @param {number} props.highTemp - High temperature.
 */
function Weather({ day, emoji, condition, lowTemp, highTemp }) {
  return (
    <div className="weather-info">
      <h2>{day}</h2>
      <span className="emoji" role="img" aria-label={condition}>
        {emoji}
      </span>
      <p className="condition">{condition}</p>
      <p className="temperature">
        Low: {lowTemp}°C | High: {highTemp}°C
      </p>
    </div>
  );
}

// Define PropTypes for type checking and documentation
Weather.propTypes = {
  day: PropTypes.string.isRequired,
  emoji: PropTypes.string.isRequired,
  condition: PropTypes.string.isRequired,
  lowTemp: PropTypes.number.isRequired,
  highTemp: PropTypes.number.isRequired,
};

export default Weather;
```

{% endtab %}

{% tab title="images" %}

```jsx
// Some code
// --- Image Import Logic ---
// Vite handles static asset imports. We create an object mapping conditions
// to their respective image URLs. This assumes images are in src/images.
// NOTE: Vite requires static string literals for dynamic imports during build.
// If you have many images or need more complex logic, consider placing images
// in the `public` folder and referencing them directly by path (e.g., '/images/sunny-background.jpg').
// However, putting them in `src` allows Vite to hash filenames for better caching.

// We need to import the images so Vite bundles them
import sunnyBg from '../images/sunny-background.jpg';
import rainyBg from '../images/rainy-background.jpg';
import snowyBg from '../images/snowy-background.jpg';
import cloudyBg from '../images/cloudy-background.jpg'; // Assuming you might add a cloudy day

/**
 * Maps weather conditions to their imported background image modules.
 * @type {Object.<string, string>}
 */
export const backgroundImages = {
  Sunny: sunnyBg,
  Rainy: rainyBg,
  Snowy: snowyBg,
  Cloudy: cloudyBg, // Add other conditions if needed
};
```

{% endtab %}

{% tab title="style.css" %}

```css
/* src/style.css */
/* Basic Reset & Body Styling */
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #333; /* Default text color */
  line-height: 1.6;
}

#root {
  /* Ensure the root element takes full height */
  min-height: 100vh;
  display: flex; /* Use flexbox for centering */
  justify-content: center; /* Center horizontally */
  align-items: center; /* Center vertically */
}

/* App Container Styling */
.app-container {
  width: 100%;
  min-height: 100vh; /* Ensure it covers the viewport height */
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: 20px;
  box-sizing: border-box; /* Include padding in width/height */

  /* Background image styling */
  background-size: cover; /* Cover the entire container */
  background-position: center; /* Center the image */
  background-repeat: no-repeat; /* Do not repeat the image */
  transition: background-image 0.5s ease-in-out; /* Smooth transition for background */

  /* Text shadow for better readability on various backgrounds */
  text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.5);
  color: white; /* Make text white for better contrast on images */
}

/* Weather Component Styling */
.weather-info {
  background-color: rgba(0, 0, 0, 0.5); /* Semi-transparent black background */
  padding: 30px 40px;
  border-radius: 15px; /* Rounded corners */
  margin-bottom: 30px;
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); /* Subtle shadow */
  display: inline-block; /* Fit content size */
  border: 1px solid rgba(255, 255, 255, 0.2); /* Subtle border */
}

.weather-info h2 {
  margin-top: 0;
  margin-bottom: 10px;
  font-size: 2.5rem; /* Larger day text */
  font-weight: bold;
}

.weather-info .emoji {
  font-size: 4rem; /* Larger emoji */
  margin-bottom: 10px;
  display: block; /* Ensure it takes its own line */
}

.weather-info p {
  margin: 8px 0;
  font-size: 1.2rem; /* Readable text size */
}

.weather-info .condition {
  font-style: italic;
  font-size: 1.5rem;
  margin-bottom: 15px;
}

.weather-info .temperature {
  font-weight: bold;
}

/* Button Styling */
.next-day-button {
  padding: 12px 25px;
  font-size: 1rem;
  font-weight: bold;
  color: white;
  background-color: #007bff; /* Blue background */
  border: none;
  border-radius: 25px; /* Fully rounded corners */
  cursor: pointer;
  transition: background-color 0.3s ease, transform 0.2s ease;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

.next-day-button:hover {
  background-color: #0056b3; /* Darker blue on hover */
  transform: translateY(-2px); /* Slight lift effect */
}

.next-day-button:active {
  background-color: #004085; /* Even darker blue when clicked */
  transform: translateY(0px); /* Back to original position */
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); /* Smaller shadow */
}

/* Simple Theme Matching (Example) */
/* You could add more specific styles based on weather condition classes */
.app-container.sunny {
  /* Specific styles for sunny theme if needed, e.g., button color */
  /* .next-day-button { background-color: #ffc107; color: #333; } */
}

.app-container.rainy {
  /* .next-day-button { background-color: #17a2b8; } */
}

.app-container.snowy {
  /* .next-day-button { background-color: #e2e6ea; color: #333; } */
}

.app-container.cloudy {
   /* .next-day-button { background-color: #6c757d; } */
}
```

{% endtab %}
{% endtabs %}

**Step 2. Copy the code:** Paste the corresponding code into each file (`weatherData.js`, `style.css`, `Weather.jsx`, `App.jsx`).

```jsx
// src/App.jsx
import React, { useState, useEffect } from 'react';
import Weather from './components/Weather';
import { weatherData, backgroundImages } from './components/weatherData'; // Import data and image map
import './style.css'; // Import custom styles

function App() {
  // State to keep track of the current day's index in the weatherData array
  const [currentDayIndex, setCurrentDayIndex] = useState(0);
  // State to hold the current background image URL
  const [backgroundImage, setBackgroundImage] = useState('');

  // Get the weather details for the currently selected day
  const currentWeatherData = weatherData[currentDayIndex];

  // --- Effect to update background image ---
  // This useEffect hook runs whenever currentWeatherData changes.
  useEffect(() => {
    if (currentWeatherData) {
      // Find the corresponding background image URL from the map
      const conditionKey = currentWeatherData.condition; // e.g., "Sunny", "Rainy"
      const imageUrl = backgroundImages[conditionKey]; // Get the imported image path

      if (imageUrl) {
        setBackgroundImage(`url(${imageUrl})`); // Set the background image style string
      } else {
        // Optional: Set a default background if no specific image is found
        setBackgroundImage(''); // Or set to a default image URL
        console.warn(`No background image found for condition: ${conditionKey}`);
      }
    }
  }, [currentWeatherData]); // Dependency array: run effect when currentWeatherData changes

  // --- Event Handler for Button Click ---
  const handleNextDayClick = () => {
    // Calculate the index of the next day
    // Use the modulo operator (%) to wrap around to the beginning of the array
    const nextIndex = (currentDayIndex + 1) % weatherData.length;
    setCurrentDayIndex(nextIndex); // Update the state
  };

  // --- Render Logic ---
  // Get the weather condition to use as a class for potential theme styling
  const weatherConditionClass = currentWeatherData?.condition.toLowerCase() || 'default';

  return (
    // Main container div
    // Apply dynamic background image using inline style
    // Apply dynamic class based on weather condition
    <div
      className={`app-container ${weatherConditionClass}`}
      style={{ backgroundImage: backgroundImage }}
    >
      {/* Conditionally render the Weather component if data exists */}
      {currentWeatherData ? (
        <Weather
          day={currentWeatherData.day}
          emoji={currentWeatherData.emoji}
          condition={currentWeatherData.condition}
          lowTemp={currentWeatherData.lowTemp}
          highTemp={currentWeatherData.highTemp}
        />
      ) : (
        // Display a loading message or fallback if data isn't ready (optional)
        <p>Loading weather data...</p>
      )}

      {/* Button to cycle through the days */}
      <button className="next-day-button" onClick={handleNextDayClick}>
        Next Day's Forecast
      </button>
    </div>
  );
}

export default App;

```

**Step 3. Add Images:** Place your background images (e.g., `sunny-background.jpg`, `rainy-background.jpg`, `snowy-background.jpg`) inside the `src/images` folder. Make sure the filenames match those used in `weatherData.js`.

**Step 4. Run the app:** If the development server isn't running, start it with `npm run dev` in your terminal (from the `weather-app` directory).

**Step 5. View:** Open your browser to the specified local address (e.g., `http://localhost:5173`).
